- 博客(23)
- 收藏
- 关注
原创 JUC并发容器之ConcurrentHashMap源码分析
我们知道HashMap是线程不安全的,在并发情况下使用HashMap的put操作会导致死循环,导致CPU利用率接近100%。导致死循环的原因是HashMap在put操作时,如果put的元素个数已经达到阈值,会对数组进行扩容,把原来的元素移动到新的HashMap上去,也会对链表中的元素进行rehash。就是在复制元素的过程中,如果有并发操作,则会把HashMap的Entry链表形成环形数据结构,一旦形成环形结构,在Entry的next节点永远也不为空,因此在get操作的时候就出现了死循环的情况。既然HashM
2020-05-18 22:09:08
322
原创 JUC并发工具之Exchanger源码解析
实现原理Exchanger(交换者)是用于线程协作的工具类。Exchanger用于进行两个线程之间的数据交换。它提供一个同步点,在这个同步点,两个线程可以交换彼此的数据。这两个线程通过exchange()方法交换数据,当一个线程先执行exchange()方法后,它会一直等待第二个线程也执行exchange()方法,当这两个线程到达同步点时,这两个线程就可以交换数据了。Exchanger的算法核心是通过一个可以交换数据的slot和一个可以带有数据item的参与者,在源码中的定义如下:for (;;) {
2020-05-17 20:12:45
460
原创 JUC并发工具之Semaphore源码分析
Semaphore(信号量)是用来控制同时访问特定资源的线程数量。它通过协调各个线程,以保证合理的使用公共资源。以一个停车场的运作为例。为了简单起见,假设停车场只有三个车位,一开始三个车位都是空的。这时如果同时来了五辆车,看门人允许其中三辆不受阻碍的进入,然后放下车拦,剩下的车则必须在入口等待,此后来的车也都不得不在入口处等待。这时,有一辆车离开停车场,看门人得知后,打开车拦,放入一辆,如果又离开两辆,则又可以放入两辆,如此往复。这个停车系统中,每辆车就好比一个线程,看门人就好比一个信号量,看门人限制了可以
2020-05-14 17:48:50
199
原创 JUC并发工具之CyclicBarrier源码分析
CyclicBarrier顾名思义就是可循环使用的屏障。它主要实现的功能是让一组线程到达一个屏障(也可以叫同步点)时阻塞,直到最后一个线程到达屏障时,屏障才会放行,所有被屏障拦截的线程才可以继续运行。CyclicBarrier结构CyclicBarrier结构如下:通过上图我们可以看到,CyclicBarrier是通过ReentrantLock和Condition来实现的。它有两个构造方法,其源码如下:public CyclicBarrier(int parties) { this(par
2020-05-13 14:06:54
223
原创 JUC并发工具之CountDownLatch源码分析
CountDownLatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。它是通过一个计数器来实现的,当我们在new 一个CountDownLatch对象的时候需要带入该计数器值,该值就表示了线程的数量。每当一个线程完成自己的任务后,计数器的值就会减1。当计数器的值变为0时,就表示所有的线程均已经完成了任务,然后就可以恢复等待的线程继续执行了。我们先用一个简单的实例来了解下CountDownLatch的使用,实例如下:public class CountDown
2020-05-11 21:36:26
263
原创 JUC之Condition源码分析
Condition接口定义了类似Object的监视器方法,它与Lock配合能够实现等待/通知模式,我们知道Object类中的wait()与notify()方法与synchronized关键字配合也能实现等待/通知模式,但是这两者在使用方式和功能上是有差别的,下面是Condition和Object监视方法的对比:Condition接口提供的方法列表如下:Condition的实例必须通过Loc...
2020-05-06 12:39:48
181
原创 JUC之读写锁:ReentrantReadWriteLock源码分析
ReentrantReadWriteLock介绍读写锁的特性是在同一时刻,可以允许多个读线程访问,但是在写线程访问时,所有读线程和其它写线程都会被阻塞。读写锁内部维护了一对锁,它们分别是一个读锁和一个写锁。通过读锁和写锁的分离,使得并发性相比于一般的排他锁有了很大的提升。读写锁简化了读写交互场景的编程方式,在读写锁出现之前,如果要实现读写锁的功能,就要使用Java的等待通知机制,即当写操作时,所...
2020-05-05 17:11:42
285
原创 JUC之重入锁:ReentrantLock源码分析
1 ReentrantLock简介 ReentrantLock可重入锁,它表示该锁能够支持一个线程对资源的重复加锁。除此之外还支持获取锁时的公平和非公平性的选择,也就是锁ReentrantLock可以构建成一个公平锁,也可以构建成一个非公平锁。在java中与ReentrantLock一样可重入的锁就是synchronized关键字,synchronized关键字的隐式支持重进入,比如在一个递归...
2020-05-04 11:15:28
252
原创 AQS之线程的阻塞和唤醒分析
在前面的文章中介绍了独占式同步状态的获取和释放以及共享式同步状态的获取和释放,在前面的文章中并没有介绍线程的阻塞和唤醒,在这篇文章中LZ将介绍在AQS中线程的阻塞和唤醒。在线程获取同步状态失败后,会加入到CHL队列中去,并且该节点会自旋式的不断的获取同步状态,在获取同步状态的过程中,需要判断当前线程是否需要被阻塞。其主要方法在acquireQueued(final Node node, int ...
2020-05-01 11:02:29
1800
原创 JMM之重排序
重排序定义在前面我们提到过,重排序是编译器和处理器为了优化程序性能而对指令序列重新排序的一种手段。但是我们也知道代码不可能毫无原则的进行重排序,如果是毫无原则的进行重排序,那么我们的代码将无法获得预期的结果。因此重排序必须满足如下原则:在单线程中不改变运行结果操作不具备数据依赖性那这两条原则如何理解么,我们先来看看下面的定义数据依赖性数据依赖性的意思是,若果两个操作访问同一个变...
2020-04-28 15:45:56
246
原创 JMM之happens-before
在JMM中有一个很重要的概念对于我们了解JMM有很大的帮助,那就是happens-before规则。happens-before规则非常重要,它是判断数据是否存在竞争、线程是否安全的主要依据。JSR-133S使用happens-before概念阐述了两个操作之间的内存可见性。在JMM中,如果一个操作的结果需要对另一个操作可见,那么这两个操作则存在happens-before关系。那什么是happ...
2019-11-04 15:22:40
1095
原创 深入分析volatile实现原理
在前面一文中我们深入的分享了synchronized的实现原理,也知道了synchronized是一把重量级的锁。在Java中还有一个关键词,那就是volatile。volatile是轻量级的synchronized,它在多线程中保证了变量的“可见性”。可见性的意思是当一个线程修改了一个变量的值后,另外的线程能够读取到这个变量修改后的值。volatile在Java语言规范中的定义如下:Java...
2019-10-23 09:50:10
968
原创 Synchronized关键字原理分析
EE30A7">实现原理Synchronized可以保证一个在多线程运行中,同一时刻只有一个方法或者代码块被执行,它还可以保证共享变量的可见性和原子性在Java中每个对象都可以作为锁,这是Synchronized实现同步的基础。具体的表现为一下3种形式:普通同步方法,锁是当前实例对象;静态同步方法,锁是当前类的Class对象;同步方法快,锁是Synchronized括号中配置...
2019-10-21 22:39:14
192
1
原创 AQS之共享式同步状态的获取和释放
前面LZ介绍了独占式获取同步状态和释放,这一章LZ将介绍共享式同步状态的获取和释放。相比于独占式同一时刻只能有一个线程获取到同步状态,共享式在同一时刻可以有多个线程获取到同步状态。例如读写文件,读文件的时候可以多个线程同时访问,但是写文件的时候,同一时刻只能有一个线程进行写操作,其它线程将被阻塞。1 acquireSharedAQS提供了acquireShared(int arg)模板方法...
2019-10-21 22:14:37
213
原创 AQS之独占式同步状态的获取和释放
上一篇文章LZ分析了AQS中的同步队列,这一章LZ将分析AQS中独占式获取同步状态和释放。AQS提供提供的独占式获取同步状态和释放的模板方法有:acquire(int arg);acquireInterruptibly(int arg)tryAcquireNanos(int arg, long nanosTimeout)release(int arg)tryRelease(int ar...
2019-09-22 09:17:44
297
原创 AbstractQueuedSynchronizer同步队列源码分析
上一章LZ在分析AQS的工作原理时,使用了一张图来解释了AQS独占模式的工作原理,在图中LZ画了一个CHL同步队列,这CHL同步队列就是AQS内部维护的一个FIFO双向队列。AQS依赖这个双向队列来完成同步状态的管理。如果当前线程获取同步状态失败,AQS将会将当前线程以及等待状态信息构建成一个节点(Node)并将其加入到同步队列中,同时会阻塞当前线程。当同步状态释放时,会把首节点中的线程唤醒,使其...
2019-09-07 22:11:15
196
1
原创 Java并发之AbstractQueuedSynchronizer工作原理
AQS之工作原理前面一章LZ简单的介绍了下AbstractQueuedSynchronizer(AQS)以及AQS中提供的一些模板方法和作用,这一章LZ将用一个简单的实例来介绍下AQS中独占锁的工作原理。独占锁顾名思义就是在同一时刻只能有一个线程能获取到锁,而其它需要获取这把锁的线程将进入到同步队列中等待获取到了锁的线程释放这把锁,只有获取锁的线程释放了锁,同步队列中的线程才能获取锁。LZ可以描...
2019-09-05 09:49:36
166
原创 AQS之简介
队列同步器AbstractQueuedSynchronizer(以下简称AQS)是用来构建锁或者其他同步组件的基础框架,它使用了一个int成员变量state来表示同步状态,通过内置一个FIFO队列来完成资源获取线程的排队工作。并发包的作者(Doug Lea)期望它能够实现大部分同步需求的基础。它是JUC并发包中的核心基础组件。同步器AbstractQueuedSynchronizer是一个抽象类...
2019-09-04 17:06:31
125
原创 DCL缺陷和优化
DCL的问题单利模式是我们经常用到的一种模式,但是要正确的书写和理解一个单利模式却没有那么简单,首先我们看看下面的代码示例:public class SignalTest { private static SignalTest instance = null; private SignalTest(){} public static SignalTest getIn...
2019-09-03 11:11:09
733
原创 volatile实现原理分析
在前面一文中我们深入的分享了synchronized的实现原理,也知道了synchronized是一把重量级的锁。在Java中还有一个关键词,那就是volatile。volatile是轻量级的synchronized,它在多线程中保证了变量的“可见性”。可见性的意思是当一个线程修改了一个变量的值后,另外的线程能够读取到这个变量修改后的值。volatile在Java语言规范中的定义如下:Java...
2019-08-29 10:49:30
284
原创 Java线程的启动和终止
在Java中我们启动线程都是调用Thread类中的start()方法来启动,当线程处理完run()方法里面的逻辑后自动终止。但是在调用start()方法之前,我们需要先构建一个Thread对象,一般我们都是直接使用Thread类的构造函数来创建一个线程对象,Thread构造函数定义如下:public Thread() { init(null, null, "Thread-" + next...
2019-08-27 14:40:23
743
原创 Java多线程简介
多线程在Java中无处不在,在上一篇(Java线程概念理解)中我们看到就算是一个最简单的Java类中也涉及到了多个线程,大家可能会疑惑,为什么一个这么简单的Java类中,却启动了那么多“无关”的线程,Java是不是将简单的问题搞复杂了呢?答案当然是否定了,这是因为正确的使用多线程能够将耗时的处理大大的缩减时间,能够让用户的体验更加友好。使用多线程的主要原因有以下几点:更多的处理器核心现代...
2019-08-27 14:38:31
195
原创 01 Java线程概念理解
1 进程进程是现代操作系统资源调度和分配的基本单位。在现代操作系统中一个程序就是一个进程。每个进程都拥有一块独立的运行空间。例如在window系统中一个运行的exe程序就是一个进程。2 线程线程是现代操作系统调度的最小单元,一个进程可以创建多个线程。一个线程拥有自己独立的堆栈、程序计数器和局部变量,线程共享进程的内存。线程在Java程序中无时不在,就算只运行一个简单的java程序也...
2019-08-18 17:33:23
129
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人