锁
定义
package java.util.concurrent.locks;
import java.util.concurrent.TimeUnit;
public interface Lock {
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
Condition newCondition();
}
优点
持续等待-lock()
可中断-lockInterruptibly()
非阻塞-tryLock() 没有公平可言!
可超时-tryLock(long time, TimeUnit unit)
非阻塞块使用
任意链式锁:a+、b+、c+、a-、c-、b-
缺点
有使用要求
Lock l = ...;
l.lock();
try {
// access the resource protected by this lock
} finally {
l.unlock();
}}
特点
定义了锁的基本使用需求方法:独占(如定时任务)或者保持时序(如计时器)
普通接口+普通实现类:意味着任何人都可以实现
纯code实现,没有特殊的JVM底层支持
提供了抽象支持AbstractQueuedSynchronizer
如何实现
使用一个标志位表示锁是否被获取
使用一个数据结构保存等待的线程
AbstractQueuedSynchronizer
使用int表示状态,支持重入
使用CLH变种队列实现等待队列:双向链表,pre可靠,状态保存在前继节点中,有虚拟头节点
支持独占和共享模式
使用LockSupport进行线程阻塞
状态变量
使用int表示状态,更具拓展性
CLH队列
使用反向单链表实现
公平锁
不断自旋,获取前继节点状态
独占模式和共享模式
独占模式只支持一个线程获取锁:ReentrantLock
共享模式支持多个线程同时获取锁:Semaphore
LockSupport
park 阻塞线程
unpark 取消阻塞线程
AQS实现-ReentrantLock
可重入,独占模式
通过Sync继承AbstractQueuedSynchronizer,实现独占获取和释放
Sync具体实现分为公平和非公平两种,区别在于获取时是否能插队
ReentrantLock实现Lock接口,具体实现调用Sync
公平锁
lock细节
没人排队,尝试获取锁
自己在排队,重入
别人在排队,自己进入队列,设置pre状态,park
unlock细节
必须是获得锁的线程,不然报错
释放状态,如果完全释放,解除独占线程
如果完全释放,唤醒第一个等待线程
AQS实现-Semaphore
不可重入,共享模式
初始化一个状态值,获取时判断状态值是否超过最大值,超过获取失败,不超过获取成功
AQS实现-CountDownLatch
初始化一个状态值,每次countDown的时候释放1
await等待获取锁,当countDown完成后,await获取锁成功