文章目录
- 为什么要使用线程池
- 为什么不建议使用 Executors静态工厂构建线程池
- synchronized的实现原理
- Synchronized和Lock的区别
- 什么是AQS
- 什么是阻塞队列
为什么要使用线程池
关于线程池的作用和线程池的执行流程参考:java线程池
为什么不建议使用 Executors静态工厂构建线程池
根据阿里巴巴Java开发手册,明确指出不允许使用Executors静态工厂构建线程池。
线程池不允许使用Executors
去创建,而是通过ThreadPoolExecutor
的方式,这样的写的目的是为了更加明确线程池的运行规则,规避资源耗尽的风险。
synchronized的实现原理
参考:synchronized及锁优化
Synchronized和Lock的区别
底层工作机制不同
synchronized
关键字是属于JVM层面实现的,它的底层是通过monitor对象来完成的,其中
wait/notify
等方法也依赖monitor对象,只有在同步代码块和同步方法中才能调用wait/notify
等方法。Lock
与synchronized
不同,它是一个具体的类,它是java api层面的锁
使用方式不同
Synchronized
关键字运行后是不需要用户去手动释放锁的,在synchronized
代码执行成功后系统会自动让线程释放对锁的占据。ReentrantLock
锁运行后需要用户手动去释放锁,如若用户没有主动去释放锁,就有可能导致出现死锁现象。ReentrantLock
需要使用lock()
和unlock()
方法配合try finally语句块来完成。
class X {
private final ReentrantLock lock = new ReentrantLock();
// ...
public void m() {
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
lock.unlock()
}
}
}
是否可中断
synchronized
不能中断,除非抛出异常或正常运行完成ReetrantLock
可中断,无影响
是否公可实现公平锁
synchronized
是一个非公平锁ReetrantLock
可以实现公平也可以实现非公平
是否支持条件唤醒
synchronized
不支持多条件- 如果使用
ReentrantLock
来实现分组唤醒需要唤醒的线程们,就可以精确唤醒,不会象synchronized
样,要么随机唤醒一个,要么唤醒全部线程。
什么是AQS
AbstractQueuedSynchronizer
简称AQS,是一个用于构建锁和同步容器的框架。事实上concurrent
包内许多类都是基于AQS构建,例如ReentrantLock,Semaphore,CountDownLatch,ReentrantReadWriteLock,FutureTask
等。AQS解决了在实现同步容器时设计的大量细节问题。
AQS使用一个FIFO的队列表示排队等待锁的线程,队列头节点称作“哨兵节点”或者“哑节点”,它不与任何线程关联。其他的节点与等待线程关联,每个节点维护一个等待状态waitStatus
。
AQS核心思想是,如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制AQS是用CLH(Craig-Landin-Hagersten)队列锁实现的,即将暂时获取不到锁的线程加入到队列中。
什么是阻塞队列
阻塞队列是一个在队列基础上又支持了两个附加操作的队列
BlockingQueue
继承了 Queue
接口,是队列的一种。Queue
和 BlockingQueue
都是在 Java 5 中加入的。
BlockingQueue
是线程安全的,在很多场景下都可以利用线程安全的队列来优雅地解决业务自身的线程安全问题。比如说,使用生产者/消费者模式的时候,生产者只需要往队列里添加元素,而消费者只需要从队列里取出它们就可以了。
阻塞插入:队列满时,队列会阻塞插入元素的线程,直到队列不满
阻塞移除:队列空时,获取元素的线程会等待队列变为非空
应用场景
阻塞队列常用于生产者和消费者的场景,生产者是向队列里添加元素的线程,消费者是从队列里取元素的线程。简而言之,阻塞队列是生产者用来存放元素、消费者获取元素的容器。
常用的阻塞队列如下:
生产者和消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一个存储空间,生产者往存储空间中添加产品,消费者从存储空间中取走产品,当存储空间为空时,消费者阻塞,当存储空间满时,生产者阻塞。
java.util.concurrent.BlockingQueue
的特性是:当队列是空的时,从队列中获取或删除元素的操作将会被阻塞,或者当队列是满时,往队列里添加元素的操作会被阻塞。