ReentrantLock 是 java.util.concurrent.locks 中的一个可重入锁类。在高竞争条件下有更好的性能,且可以中断。ReentrantLock 是基于 AQS 实现的。AQS 是基于 FIFO 队列的实现,整个 AQS 是典型的模板模式的应用,设计的十分精巧,对于 FIFO 队列的各种操作在 AQS 中就已经实现了,AQS 的子类一般只需要重写 tryAcquire(int arg) 和 tryRelease(int arg) 两个方法即可。
初窥 condition
了解 condition 之前需要先了解一下 Java 的 等待/通知 机制:https://www.cnblogs.com/powercto/p/10848825.html
AbstractQueuedSynchronizer 简介
提供了一个基于 FIFO 队列,可以用于构建阻塞锁或者同步容器的基础框架,AQS 是基于 FIFO 队列的实现,因此必然存在一个个节点,Node 就是一个节点。对于 FIFO 队列的各种操作在 AQS 中都已经实现了,AQS 的子类一般只需要重写 tryAcquire(int arg) 和 tryRelease(int arg) 两个方法即可。成为依靠单个原子 int 值来表示状态的有用基础。子类必须定义更改此状态的受保护方法,并定义哪种状态对于此对象意味着被获取或被释放。假定这些条件之后,此类中的其他方法就可以实现所有排队和阻塞机制。
启动线程时 start 和 run 的区别
每个线程都有要执行的任务,线程的任务逻辑可以在 Thread 类的 run 方法中直接实现或通过该方法调用,因此
run() 相当于线程任务的入口,它由 Java 虚拟机在运行相应线程时直接调用,而不是由应用代码进行调用
而 start 的作用是启动相应线程。启动一个线程实际是请求 Java 虚拟机运行相应的线程,而这个线程何时能够运行是由线程调度器决定的。
start() 调用结束并不表示相应线程已经开始运行,这个线程可能稍后运行,也可能永远不会运行
ThreadLocal 实现原理
首先,在每个线程 Thread 内部有一个 Threadlocal.ThreadLocalMap 类型的成员变量 ThreadLocals,ThreadLocalMap 是 ThreadLocal 的内部类,这个 ThreadLocals 就是用来存储实际的变量副本,键值为当前的 ThreadLocal 对象,value 为变量副本。
Java 内存模型的 happen-before 原则
happen-before 口诀:如果两个操作之间具有 happen-before 关系,那么前一个操作结果就会对后一个操作可见。是 Java 内存模型中定义的两个操作之间的偏序关系。
常见的 happen-before 规则:
程序顺序规则:一个线程中的每个操作,happen-before 于该线程中的任意后续操作。
- 注解:如果只有一个线程的操作,那么前一个操作的结果肯定会对后续的操作可见
所规则:对一个锁的解锁 happen-before 于随后对这个锁的加锁
- 注解:这个最常见的就是 synchronized 方法和 synchronized 块
volatile 变量规则:对一个 volatile 域的写,happen-before 于任意后续对这个 volatile 域的读。该规则在 concurrentHashMap 中读操作不需要加锁有很好的体现
传递性:如果 A happen-before B,且 B happen-before C,那么 Ahappen-before C
线程启动规则:Thread 对象的 start() 方法 happen-before 此线程的每一个动作
线程终止规则:线程的所有操作都 happen-before 对此线程的终止检测,可通过 Thread.join() 方法结束、Thread.isAlive() 的返回值等手段检测线程是否已经停止运行
线程中断规则:对线程 interrupt() 方法的调用 happen-before 发生于中断线程检测到中断事件的发生