自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(107)
  • 收藏
  • 关注

原创 redis分布式锁

Redis的数据结构并不全是简单的Key-Value,还有list,hash等复杂的结构,这些结构有可能会进行很细粒度的操作,比如在很长的列表后面添加一个元素,在hash当中添加或者删除一个对象。单线程的威力实际上非常强大,每核心效率也非常高,多线程自然是可以比单线程有更高的性能上限,但是在今天的计算环境中,即使是单机多线程的上限也往往不能满足需要了,需要进一步摸索的是多服务器集群化的方案,这些方案中多线程的技术照样是用不上的。当得到锁的线程执行完任务,需要释放锁,以便其他线程可以进入。

2024-12-21 21:14:55 861

原创 redis如何保证缓存与数据库一致性

假设线程1执行修改数据的工作,在执行完第一步后,用完了CPU时间片,CPU开始运行线程2执行读取数据的工作,线程2先查询缓存,发现为空,就去查询数据库(注意:这时数据库中的数据还是旧数据),然后更新到缓存并返回给用户。假设先淘汰缓存,再写数据库:第一步淘汰缓存成功,第二步写数据库失败【如下图:cache中无数据,db中是旧数据】。假设先写数据库,再淘汰缓存:第一步写数据库操作成功,第二步淘汰缓存失败,则会出现DB中是新数据,Cache中是旧数据,数据不一致【如下图:db中是新数据,cache中是旧数据】。

2024-12-21 21:02:39 839 3

原创 Redis缓存穿透、击穿、雪崩

简单来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操作返回成功时,再进行load db的操作并回设缓存;一个一定不存在缓存且在数据库查询不到的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。假设位数组的长度为m,哈希函数的个数为k。

2024-12-21 15:06:41 1024

原创 redis过期删除及淘汰机制

4)volatile-lru策略和volatile-random策略适合我们将一个Redis实例既应用于缓存和又应用于持久化存储的时候,然而我们也可以通过使用两个Redis实例来达到相同的效果,值得一提的是将key设置过期时间实际上会消耗更多的内存,因此我们建议使用allkeys-lru策略从而更有效率的使用内存。(2)惰性删除:键过期了就过期了,不管。然后,Redis检查内存使用情况,如果已使用的内存大于maxmemory,则开始根据用户配置的不同淘汰策略来淘汰内存(key),从而换取一定的内存。

2024-12-20 22:16:24 1215

原创 redis如何持久化

什么是持久化?简单来讲就是将数据放到断电后数据不会丢失的设备中,也就是我们通常理解的硬盘上。首先我们来看一下数据库在进行写操作时到底做了哪些事,主要有下面五个过程:1>客户端向服务端发送写操作(数据在客户端的内存中)。2>数据库服务端接收到写请求的数据(数据在服务端的内存中)。3>服务端调用write这个系统调用,将数据往磁盘上写(数据在系统内存的缓冲区中)。4>操作系统将缓冲区中的数据转移到磁盘控制器上(数据在磁盘缓存中)。5>磁盘控制器将数据写到磁盘的物理介质中(数据真正落到磁盘上)。

2024-12-20 21:59:10 1007

原创 Redis的数据结构和使用场景

Redis(全称:Remote Dictionary Server 远程字典服务)是一个开源的使用ANSI编写、支持网络、可基于内存亦可持久化的日志型、Key-Value,并提供多种语言的API。redis是一个key-value。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list()、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些。

2024-12-20 21:51:03 688

原创 文件系统简介

文件系统是操作系统中负责管理持久数据的子系统,说简单点,就是负责把用户的文件存到磁盘硬件中,因为即使计算机断电了,磁盘里的数据并不会丢失,所以可以持久化的保存文件。文件系统的基本数据单位是文件,它的目的是对磁盘上的文件进行组织管理,那组织的方式不同,就会形成不同的文件系统。Linux最经典的一句话是:「一切皆文件」,不仅普通的文件和目录,就连块设备、管道、socket 等,也都是统一交给文件系统管理的。Linux。

2024-12-01 21:11:33 714

原创 TCP/IP协议

一句话,主要防止已经失效的连接请求报文突然又传送到了服务器,从而产生错误。如果使用的是两次握手建立连接,假设有这样一种场景,客户端发送了第一个请求连接并且没有丢失,只是因为在网络结点中滞留的时间太长了,由于TCP的客户端迟迟没有收到确认报文,以为服务器没有收到,此时重新向服务器发送这条报文,此后客户端和服务器经过两次握手完成连接,传输数据,然后关闭连接。

2024-12-01 20:37:19 804

原创 OSI七层参考模型

肯定要知道对方的IP地址,这是最基本的,就像你要访问百度,肯定得知道百度的域名,域名就是百度的IP地址。在讲网络层之前,其实基于广播的这种通信就可以实现全世界通信了,你吼一声,如果全世界是一个局域网,全世界的计算机肯定可以听得见,从理论上似乎行得通,如果全世界的计算机都在吼,你想一想,这是不是一个灾难。实际上这个七层是不存在的。数据链路层中会把网络层的数据包封装到数数据链路层的数据位置,然后再添加上自己的包头,再发给物理层,物理层发给网关,网关再发给对方教室的网关,对方教室的网关收到后在那个教室做广播。

2024-11-30 23:21:31 588

原创 零拷贝与内存映射

先简单介绍一下磁盘与内存之间数据传输的方式:硬盘(磁盘)和内存之间数据传送的两种方式:PIO模式和DMA模式PIO(Programming Input Output,编程输入输出)模式下通过CPU来控制硬盘和内存之间的数据传输,是一种通过CPU执行I/O端口指令来进行数据的读写的数据交换模式。显然这种方式是不合理的,因为它需要占用大量的CPU时间来读取文件,造成文件访问时系统几乎停止响应。DMA(Direct Memory Access,直接内存访问)取代了PIO,它可以不经过CPU而直接进行磁盘和内存(内

2024-11-30 22:10:29 686

原创 计算机基础

在对CPU、缓存、内存、硬盘等概念进行详细介绍之前,先通过一个流程图来直观了解一下这几个组件之间的关系。主存就是狭义上的内存,广义上的内存包括主存和缓存。按照与CPU的接近程度,存储器分为与,简称内存与外存。内存储器又常称为主存储器(简称主存),属于主机的组成部分;外存储器又常称为辅助存储器(简称),属于外部设备。CPU不能像访问内存那样,直接访问外存,外存要与CPU或I/O设备进行数据传输,必须通过内存进行。在80386以上的高档微机中,还配置了高速缓冲存储器(cache),这时内存包括主存与两部分。

2024-11-24 23:16:41 879

原创 mybatis连接数据库底层原理

这行代码中的child.evalNode("dataSource")方法,该方法的作用就是解析< dataSource >标签及其子标签的属性值,获取数据库连接属性,如下图所示。这三种连接数据库属性的配置方式,任选一种即可,也可以三种方式混合使用。Mybatis在加载这些属性时,首先读取第一种方式配置的,其次读取第二种方式配置的,最后读取第三种方式配置的,如果三种方式中存在同名属性,先读取的属性会被后读取的属性覆盖,即第三种配置方式的优先级高于第二种方式,第二种方式的优先级高于第一种方式。

2024-11-24 22:57:36 985

原创 SpringMVC原理详解

SpringMVC是一种基于Java实现的MVC设计模式的轻量级Web框架,它是Spring框架的一部分,主要用于简化Web开发。‌ SpringMVC采用MVC架构模式,将应用程序分为模型(Model)、视图(View)和控制器(Controller)三个层次,从而实现业务逻辑、数据和界面的分离。模型层负责处理数据,视图层负责展示数据,而控制器层则负责根据输入调用相应的模型和视图。‌SpringMVC的优点包括结构松散、易于扩展和与Spring框架无缝集成。

2024-11-17 23:27:48 1019

原创 SpringMVC简单使用

MVC模型:是一种架构的新模式,本身不引入新的功能,只是帮助我们将开发的结构组织的更加合理。使展示与模型分离,流程逻辑控制、业务逻辑调用与展示逻辑分离。M(model模型):数据模型,包含要展示的数据和业务。V(View视图):用户界面,在界面上展示模型数据。C(Controller控制器):起调度作用,接收用户请求,调用业务处理请求,共享数据模型并跳转界面。使用方式有两种,现在基本上都是使用第二种方式:1、基于XML配置与注解的方式使用Spring MVC。

2024-11-17 22:45:04 995

原创 G1垃圾收集器

XX:G1HeapWastePercent(默认5%): gc过程中空出来的region是否充足阈值,在混合回收的时候,对Region回收都是基于复制算法进行的,都是把要回收的Region里的存活对象放入其他Region,然后这个Region中的垃圾对象全部清理掉,这样的话在回收过程就会不断空出来新的Region,一旦空闲出来的Region数量达到了堆内存的5%,此时就会立即停止混合回收,意味着本次混合回收就结束了。(Shenandoah优化成多线程收集了)

2024-11-17 21:53:59 976

原创 CMS垃圾收集器详解

因此对于老年代来说,引用了老年代中对象的新生代对象,也会被老年代视作“GC ROOTS”。CMS前五个阶段都是标记存活对象的,除了“初始标记”和“重新标记”阶段会stop the word ,其它三个阶段都是与用户线程一起运行的,就会出现这样的情况:gc线程正在标记存活对象,用户线程同时从年轻代向老年代提升新的对象,清理工作还没有开始,old gen已经没有空间容纳更多对象了,这时候就会导致concurrent mode failure, 然后就会使用串行收集器回收老年代的垃圾,导致停顿的时间非常长。

2024-11-17 21:35:05 1145

原创 JVM的垃圾回收机制

即使在可达性分析算法中不可达的对象,也并非是“非死不可”,这时候它们暂时处于“缓刑”阶段,要真正宣告一个对象死亡,至少要经历两次标记过程。第一次标记:如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,那它将会被第一次标记;第二次标记:第一次标记后接着会进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。在finalize()方法中没有重新与引用链建立关联关系的,将被进行第二次标记。

2024-11-17 21:27:57 1253

原创 对象的创建过程

一个Java对象的创建过程就是类实例化的过程,往往会包括类初始化的过程,在第一次创建一个类的对象时,就需要对类进行初始化,以后再创建这个类的对象时,只需进行类的实例化,就不需要进行类的初始化了。

2024-11-17 18:45:23 857

原创 类的加载和初始化

加载某个类指的是将该类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个该类的java.lang.Class对象(Class是java.lang包中的一个类),用来封装该类在方法区内的数据结构。类加载的最终产品是位于堆区中的Class对象。Class对象封装了类在方法区内的数据结构,并且向Java程序提供了访问方法区内数据结构的接口。加载阶段完成后,虚拟机外部的二进制字节流就按照虚拟机所需的格式存储在方法区之中,而且在Java堆中也创建一个java.lang.C

2024-11-17 18:22:33 1316

原创 JVM的各个组成部分及作用

JVM主要包括下面四部分,其中运行时数据区是JVM的主要部分。class loader 类加载器:加载类文件到内存。Class loader只管加载,只要符合文件结构就加载,至于能否运行,它不负责,那是有Execution Engine 负责的。execution engine :执行引擎也叫解释器,负责解释命令,交由操作系统执行。native interface:本地接口。本地接口的作用是融合不同的语言为java所用。

2024-11-17 18:06:40 704

原创 IO复用模型

IO多路复用、select模型、poll模型、epoll模型等知识点,常常是Java高级工程师及以上岗位在面试中遇到的必问面试题。为了讲多路复用,当然还是要跟风,采用鞭尸的思路,先讲讲传统的网络 IO 的弊端,用拉踩的方式捧起多路复用 IO 的优势。为了方便理解,以下所有代码都是伪代码,知道其表达的意思即可。

2024-11-15 22:58:19 985

原创 同步(阻塞和非阻塞)和异步IO概念

IO操作概念:在Unix系统中,一切都是文件。文件就是流的概念,在进行信息的交流过程中,对这些流进行数据的收发操作就是IO操作。我们都知道unix(like)世界里,一切皆文件,而文件是什么呢?文件就是一串二进制流而已,不管socket,还是FIFO、管道、终端,对我们来说,一切都是文件,一切都是流。在信息交换的过程中,我们都是对这些流进行数据的收发操作,简称为I/O操作(input and output),从流中读出数据,系统调用read,向流中写入数据,系统调用write。

2024-11-15 22:32:06 661

原创 CompletableFuture的简单用法

Java8中的CompletableFuture是对Future的扩展实现, 主要是为了弥补Future没有相应的回调机制的缺陷。CompletableFuture实现了Future和CompletionStage两个接口。

2024-11-14 23:35:46 721

原创 ThreadLocal原理与简单使用

什么是ThreadLocal?ThreadLocal类顾名思义可以理解为线程本地变量,也就是说,如果定义了一个ThreadLocal,每个线程往这个ThreadLocal中读写数据是线程隔离的,互相之间不会影响。它提供了一种将可变数据通过每个线程有自己的独立副本从而实现线程封闭的机制。它大致的实现思路是怎样的?Thread类有一个类型为ThreadLocal.ThreadLocalMap的实例变量threadLocals,也就是说每个线程有一个自己的ThreadLocalMap。

2024-11-11 00:02:27 1290

原创 线程池ThreadPoolExecutor

每当使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题:如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。在Java中通过线程池使线程可以复用,就是线程执行完一个任务,并不被销毁,而是可以继续执行其他的任务。线程池的种类及使用场景。

2024-11-10 22:38:32 869

原创 线程池ForkJoinPool

工作队列中保存的是等待执行的任务ForkJoinTask,是保存在数组中的,每个工作线程会优先完成自己队列中的任务,当自己队列中的任务为空时,才会通过工作窃取work-stealing算法从其他任务队列中获取任务。3.每个工作线程在处理自己的工作队列同时,会尝试窃取一个任务(或是来自于刚刚提交到 pool 的任务,或是来自于其他工作线程的工作队列),窃取的任务位于其他线程的工作队列的队首,也就是说工作线程在窃取其他工作线程的任务时,使用的是 FIFO 方式。例子:求1-100的和。

2024-11-10 21:39:23 204

原创 CountDownLatch和CyclicBarrier的区别

CountDownLatch是一个同步的辅助类,允许一个或多个线程,等待其他一组线程完成操作,再继续执行。CyclicBarrier是一个同步的辅助类,允许一组线程之间相互等待,达到一个共同点,再继续执行。CountDownLatch的计数器无法被重置;CyclicBarrier的计数器可以被重置后使用,因此它被称为是循环的barrier。他们都是:Synchronization aid,把它翻译成同步辅助器,既然是辅助工具,怎么使用?哪些场景使用?

2024-11-10 18:30:44 638

原创 乐观锁和悲观锁的实现方式

当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值与当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功。:总是认为不会产生并发问题,每次读取数据的时候总认为不会有其他线程对数据进行修改,因此不会上锁,但是在更新数据时,会判断其他线程在这之前有没有对数据进行修改,如果其他线程对数据进行了修改,因为并发冲突而导致更新失败,该线程就会反复重试更新数据,直到成功为止。为例,看一下在不使用锁的情况下是如何保证线程安全的。

2024-11-10 18:05:59 818

原创 AbstractQueuedSynchronizer(AQS)的原理与源码分析

头节点最开始是不封装线程的,头节点中thread字段的值被默认初始化成null,只有第一个获取锁的线程释放锁之后,唤醒头节点的下一个节点中的线程去获取锁,这时头节点的下一个节点成为新的头节点,此时头节点中才有线程,而且此时头节点中的线程被设置成了null,因为当前线程已经获取到了锁,没必要再保存在同步队列中了。1.当前线程尝试获取锁,对于公平锁,首先判断同步队列中是否有线程在等待,如果有,则将当前线程添加到同步队列中,如果没有,则通过CAS操作尝试修改同步状态state的值。如果获取失败,则阻塞当前线程。

2024-11-06 23:05:51 610

原创 java同步的实现方式,以及synchronized与Lock的异同

C、tryLock(long timeout, TimeUnit timeUnit)方法:如果获取了锁定立即返回true,如果别的线程正持有锁,会等待参数给定的时间,在等待的过程中,如果获取了锁定,就返回true,如果等待超时,返回false。java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如数据的增删改查),相互之间产生冲突,将会导致数据不准确,因此加入同步锁以避免在该线程没有完成操作之前,被其他线程的调用,从而保证了该变量的唯一性和准确性。

2024-11-06 21:59:29 927

原创 synchronized加锁原理以及锁升级过程

由于synchronized中用到了CAS技术,此处先对CAS做个简单介绍。是乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败。CAS(V,A,B)操作中至少包含三个操作数——需要读写的内存位置(V)、进行比较的预期原值(A)和拟写入的新值(B)。如果内存位置V的值与预期原值A相匹配,那么处理器会自动将该位置值更新为新值B。否则处理器不做任何操作。无论哪种情况,它都会在CAS指令之前返回该位置的值。在。

2024-11-03 22:33:25 1352

原创 并发和并行,守护线程和用户线程,以及线程的六种状态

创建线程之后调用线程的start()方法,或该线程调用的Thread.sleep()方法结束,或在该线程中其他线程调用的join()结束,或其他线程调用notify或notifyAll方法唤醒该线程,或该线程获取到了同步方法的锁对象,或该线程的CPU时间片用完了,或在该线程中调用Thread.yield()方法。因此,当所有的非守护线程(用户线程,就是应用程序里的自定义线程)结束时,程序也就终止了,同时会杀死进程中的所有守护线程。这个线程对象也许是活的,但是,它已经不是一个单独执行的线程。

2024-11-03 22:04:49 1096

原创 多线程之间的通讯

由于线程A和线程B持有同一个MyObject类的对象object,尽管这两个线程需要调用不同的方法,但是它们是同步执行的,假如线程A先执行methodA方法,那么线程B需要等待线程A执行完了methodA()方法之后,它才能执行methodB()方法。当条件满足时,线程B调用 notify()通知线程A,所谓通知线程A,就是唤醒线程A,让它尝试获取锁,若获取成功,则进入可运行状态,否则进入阻塞状态。因为,线程B已经发了通知了,以后不再发通知了。=5),线程A调用wait() 放弃CPU,并进入等待状态。

2024-11-03 21:32:18 853

原创 notify和notifyAll的区别,以及sleep、wait和join的区别

对象的wait(0)方法的作用是让线程一直等待,直到其他线程针对该线程调用同一个对象的notify或notifyAll方法。这是因为线程t1和线程t2的run方法中同步代码块中的锁对象都是t1对象,在线程t2的run中调用了t1.join()方法,由上面分析可知,在join方法内部,线程t2会再次获取t1对象作为锁对象进入到join方法内部的同步方法中,并在执行join方法内部的wait方法时释放掉t1对象锁,这时线程t2就不再拥有任何锁,线程t1就可以获取到锁对象t1从而执行自己的run方法。

2024-11-03 21:21:14 1017

原创 interrupt、interrupted、isInterrupted方法详解

thread线程调用了interrupt方法,并没有使thread线程立即中断,只是将thread线程的中断标志设置为true(线程的中断状态被设置),通过thread.isInterrupted方法判断线程的中断状态是否被设置,若被设置了,则返回true,否则返回false。当线程调用interrupt方法时,会进入到同步代码块中,由于blocker==null,所以不执行if语句中的代码,而是调用interrupt0()方法,将线程的中断标志位设置为true。方法不能中断线程,只是设置线程的中断状态。

2024-11-03 20:30:08 697

原创 进程与线程的区别,以及创建线程的几种方式

(此处说的是线程,而不是普通对象)的wait方法,此时线程A会释放掉持有的线程B对象的锁,并等待线程B执行run方法。当线程B运行结束时,会自动调用自身的notifyAll方法,唤醒所有等待线程B对象锁的线程尝试获取锁,即线程A会被唤醒,尝试获取线程B对象的锁,如果获取成功,则接着wait方法之后的代码继续执行,如果获取失败,则进入线程B对象的锁池阻塞等待,并尝试下一次获取B对象的锁。(1)定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。

2024-11-03 20:20:18 850

原创 Java内存模型以及原子性、可见性与有序性

线程安全高频面试题:高并发如何保证线程安全,谈谈你对高并发的理解。其实java的多线程并发问题最终都会反映在java的内存模型上,高并发情况下需要保证线程安全,所谓线程安全无非是要控制多个线程对某个公共资源的有序访问或修改。在回答高并发的问题时,主要从java内存模型与线程同步两方面回答即可。线程安全就是说多线程访问同一代码,不会产生不确定的结果。如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。

2024-11-03 19:50:50 648

原创 迭代器 Iterator的原理以及与ListIterator的区别

3.ListIterator实现了Iterator接口,并新增了其他功能,比如:add()方法向集合中增加元素,set()方法修改集合中的元素,previousIndex()方法获取前一个元素的索引,nextIndex()方法获取后一个元素的索引等。由于每一个容器都有取出或删除元素的功能,这些功能定义都一样,只不过实现的具体方式不同(因为每一个容器的数据结构不一样),所以,在java中对共性的功能进行抽取并封装在Iterator接口中,从而出现了迭代器。一个方法,用于获取迭代器。

2024-11-03 10:48:00 480

原创 Queue中add/offer、element/peek、remove/poll区别

1. add和offer方法都是向队列中增加元素,区别在于:在队列满的情况下,add方法将选择抛异常来表示队列已经满了,而offer方法通过返回false表示队列已经满了;3. element和peek方法都是返回队列的头元素,但是不删除头元素,区别在于:在队列为空的情况下,element方法将抛异常,而peek方法将返回null。2. remove和poll方法都是删除并返回队列的头元素,区别在于:在队列为空的情况下,remove方法将抛异常,而poll方法将返回null;

2024-11-03 10:35:52 314

原创 数组和List之间的区别及转换

附上arraylist扩充机制:newCapacity=oldCapacity+(oldCapacity>>1)(注:>>1:右移1位,相当于除以2),但由于源码里传过来的minCapcatiy的值是size+1,能够实现grow方法调用就肯定是(size+1)>elementData.length的情况,所以size就是初始最大容量或上一次扩容后达到的最大容量,才会进行扩容。而且,每次添加新的元素的时候都会检查内部数组的空间是否足够,效率比数组低(这是比较麻烦的地方)。

2024-11-03 10:33:10 442

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除