目录:
- ReentrantLock
- Semaphore
- CountDownLatch
- CyclicBarrier
- ArrayBlockingQueue、LinkedBlockingQueue、DelayQueue
- CopyOnWriteArrayList
上一节吧AQS相关的知识点整理了下,这一节我来整理下AQS的一些实现类及JUC的工具包。
ReentrantLock
1、是什么:
- ReentrantLock与synchronize都是可重入锁,它可以说是synchronize的一种扩展;
- synchronize是内置锁,加锁与解锁都是交由JVM来实现的,而ReentrantLock则是JUC提供的一种由客户端来控制的可重入锁,控制粒度由用户自行决定,更加灵活。
2、实现原理:
- 通过为每个锁关联一个请求计数器和获得该锁的线程来实现,当计数器的值为0时表示该锁是未被占用的。
- 当线程请求一个未被占用的锁时,计数器的值加1,此时线程就为获取到该锁的状态,再次请求获取此锁时计数器将递增;
- 当此线程退出这个同步方法或代码块时,计数器将递减,直到计数器的值变为0时就表示锁已释放,其它线程才能获取该锁。
- 基于AQS排它锁实现。
Semaphore
1、是什么:
- Semaphore和ReentrantLock一样,也是对synchronize的扩展;
- 不同的是ReentrantLock是锁粒度和灵活去的扩展,而Semaphore是对并发数量的扩展,控制线程的并发数量。
2、实现原理:
- 通过在Semaphore初始化的时候传入一个凭证,每当有一个线程获取到锁后就将凭证数量减1,释放锁后凭证数量加1;
- 直到凭证数据小于等于0时就不再允许线程获取锁。
- 基于AQS共享锁实现。
CountDownLatch
1、是什么:
- 我们知道join()方法的作用是让一个线程执行完后再执行另一个线程,但你如果进一步了解它的话你就会知道join()方法控制的粒度比较大,它是以整个线程为单位的;也就是说join()只能在某线程执行完后才能执行另一个线程,如果我们有如下场景那join()就不能完成工作了:
- 线程A和线程B分别都要执行两个动作,记为A1、A2、B1、B2,我需要在线程A执行完A1后就要执行线程B的B1、B2。
- 如果遇到类似的场景就需要使用CountDownLatch来实现了,它是join()方法的扩展,可以更加细粒度的控制线程之间的执行问题;通过countDown()和await()来实现。
2、实现原理:
- 通过构造函数初始化一个内置的计数器,当计数器为0时会唤醒所有调用await()方法而被阻塞的线程。
- 一般情况下我们通过完成某个操作后来调用countDown()减少计数器的值,通过await()方法阻塞线程,让其执行完毕后再退出方法。
- 基于AQS共享锁实现。
CyclicBarrier
1、是什么:
- 循环栅栏,可以让所有线程都等待执行完后再继续做后续处理,与CountDownLatch非常类似,不同的是CountDownLatch是一次性的,而CyclicBarrier是可以循环使用的。
- 可以说CyclicBarrier是CountDownLatch的扩展,是对CountDownLatch执行能力的扩展,可重复执行。
2、实现原理:
- 底层基于ReentrantLock和Condition实现,定义了parties字段来表示栅栏数量,当parties满足特定条件后则唤醒线程,这是让所有线程都等待执行完后再继续做后续处理的实现原理。
- 而重复使用的原理则是通过一个叫Generation的内部类中的broken来标记,每当调用await()方法是栅栏数就会减1,直到数量为0时就会唤醒在此之上的所有线程,并重置broken为false,这样就又可以继续使用栅栏了。
ArrayBlockingQueue、LinkedBlockingQueue
1、是什么:
- ArrayBlockingQueue通过数组实现的线程安全的阻塞队列;LinkedBlockingQueue通过链表实现的线程安全的阻塞队列。
- 用于在线程池中,运行线程数大于核心线程数时,将新加入的线程放到此阻塞队列中。
2、实现原理:
- 底层同样是基于ReentrantLock和Condition来实现,通过Condition notEmpty、Condition notFull来阻塞唤醒线程的获取、添加操作。
DelayQueue
1、是什么:
- DelayQueue是一个支持延时获取元素的无界阻塞队列,队列使用PriorityQueue来实现。
- 队列中的元素必须实现Delayed接口,在创建元素时可以指定多久才能从队列中获取当前元素,只有在延迟期满时才能从队列中提取元素。
2、实现原理:
- emmmmm,同样的还是基于ReentrantLock和Condition来实现,等时间到了唤醒线程获取值。
CopyOnWriteArrayList
1、是什么:
- CopyOnWriteArrayList是一个写入时复制的集合,与其说它是一种新的数据结构还不如说它是一种设计思想。
2、实现原理:
- 当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后往新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。
- 这时候会抛出来一个新的问题,也就是数据不一致的问题。如果写线程还没来得及写回内存,其他的线程就会读到了脏数据。
- 这就是CopyOnWriteArrayList的思想和原理,就是拷贝一份写;所以使用条件也很局限,那就是在读多写少的情况下比较好。