1. Lock
从JDK 5.0开始,Java提供了更强大的线程同步机制——通过显式定义同步锁对象来实现同步。同步锁使用 Lock 对象充当。
java.util.concurrent.locks.Lock
接口是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对 Lock 对象加锁,线程开始访问共享资源之前应先获得 Lock 对象。ReentrantLock 类实现了 Lock ,它拥有与 synchronized 相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是 ReentrantLock,可以显式加锁、释放锁。
- java.util.concurrent.locks(Java并发锁包)
- Lock接口的实现基本都是通过聚合了一个队列同步器AQS的子类来完成线程访问控制的。
package java.util.concurrent.locks;
import java.util.concurrent.TimeUnit;
public interface Lock {
//调用该方法的当前线程将会获取锁
void lock();
//可中断的获取锁,即在锁的获取中可以中断当前线程
void lockInterruptibly() throws InterruptedException;
//尝试非阻塞的获取锁,调用该方法后立即返回,获取成功返回true,否则返回false
boolean tryLock();
//超时的获取锁
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
//释放锁
void unlock();
//获取等待通知组件,该组件和当前锁绑定
Condition newCondition();
}
2. AQS
- 抽象队列同步器 AbstractQueuedSynchronizer 简称同步器,是用来构建锁或者其他同步组件的基础框架。同步器的主要使用方式是继承,子类通过继承同步器并实现他的抽象方法来管理同步状态。
抽象:抽象类,只实现一些主要逻辑,有些方法由子类实现。
队列:使用先进先出(FIFO)队列存储数据。
同步:实现了同步的功能。
- 使用 AQS 能简单且高效地构造出应用广泛的同步器,比如 ReentrantLock、Semaphore、ReentrantReadWriteLock、SynchronousQueue、FutureTask 等都是基于 AQS 实现的。
- 同步器依赖内部的同步队列 / 等待队列(一个FIFO双向队列)来完成同步状态的管理。当前线程获取同步状态失败时,同步器会将当前线程以及等待状态等信息构造成为一个结点(Node)并将其加入同步队列,同时会阻塞当前线程,当同步状态释放时,会把首结点中的线程唤醒,使其再次尝试获取同步状态。
- 将获取同步状态失败的线程加入到同步队列中时,为了保证线程安全,同步器提供了一个基于CAS的设置尾结点的方法:
compareAndSetTail(Node expect, Node update)
- 同步队列中的首结点是获取同步状态成功的结点,首结点的线程在释放同步状态时,会唤醒后继结点,后继结点将会在获取同步状态成功时将自己设置为首结点。
- 同步器的子类推荐被定义为自定义同步组件的静态内部类。
- 同步器的设计是基于模板方法模式的,使用者需要继承同步器并重写指定的方法,随后将同步器组合在自定义同步组件的实现中,并调用同步器提供的模板方法,而这些模板方法将会调用使用者重写的方法。
- 重写同步器指定的方法时,需要使用同步器提供的3个方法来访问或修改同步状态。
protected final int getState()
protected final void setState(int newState)
protected final boolean compareAndSetState(int expect, int update)
- 同步器可重写的方法:
protected boolean tryAcquire(int arg)
//独占式获取同步状态protected boolean tryRelease(int arg)
//独占式释放同步状态protected int tryAcquireShared(int arg)
//共享式获取同步状态protected boolean tryReleaseShared(int arg)
//共享式释放同步状态protected boolean isHeldExclusively()
//表示当前同步器是否被当前线程独占
- 同步器提供的模板方法:
public final void acquire(int arg)
//调用重写的tryAcquire(int arg)
public final void acquireInterruptibly(int arg)
public final boolean tryAcquireNanos(int arg, long nanosTimeout)
public final void acquireShared(int arg)
public final void acquireSharedInterruptibly(int arg)
public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout)
public final boolean release(int arg)
public final boolean releaseShared(int arg)
public final Collection<Thread> getQueuedThreads()
//获取等待在同步队列上的线程集合
package java.util.concurrent.locks;
public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable {
protected AbstractQueuedSynchronizer() {
}
//同步队列/等待队列中存储元素的类型为结点类
static final class Node {
//同步队列中的结点Node用来保存:
//(1)获取同步状态失败的线程引用
//(2)等待状态
//(3)前驱结点
//(4)后继结点
}
//Head of the wait queue, lazily initialized.
private transient volatile Node head; //指向同步队列中的头结点
//Tail of the wait queue, lazily initialized.
private transient volatile Node tail; //指向同步队列中的尾结点
//同步器使用一个int型的成员变量来表示同步状态
private volatile int state;
//获取当前同步状态
protected final int getState() {
return state;
}
//设置当前同步状态
protected final void setState(int newState) {
state = newState;
}
//该方法以原子操作的方式(CAS)更新state变量
protected final boolean compareAndSetState(int expect, int update) {
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
private final boolean compareAndSetHead(Node update) {
return unsafe.compareAndSwapObject(this, headOffset, null, update);
}
private final boolean compareAndSetTail(Node expect, Node update) {
return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
}
//独占式获取同步状态、结点构造、加入同步队列、在同步队列中自旋等待
public final void acquire(int arg) {
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
//唤醒同步队列中首结点的后继结点,unparkSuccessor(Node node)通过LockSupport来唤醒处于等待状态的线程
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
public final Collection<Thread> getQueuedThreads() {
ArrayList<Thread> list = new ArrayList<Thread>();
for (Node p = tail; p != null; p = p.prev) {
Thread t = p.thread;
if (t != null)
list.add(t);
}
return list;
}
}
3. ReentrantLock
- ReentrantLock的实现依赖于Java同步器框架AbstractQueuedSynchronizer(AQS)。AQS使用一个int型的volatile变量state来维护同步状态。
- ReentrantLock是可重入锁,重入是指任意线程在获取到锁之后能够再次获取该锁而不被阻塞。
- 线程再次获取锁:锁需要去识别获取锁的线程是否为当前占有锁的线程,如果是则再次成功获取锁。
- 锁的最终释放:获取锁时计数自增,释放锁时计数自减,计数表示当前锁被重复获取的次数,计数等于0时表示锁成功释放。
- ReentrantLock使用公平锁时,加锁方法
lock()
调用轨迹如下:- ReentrantLock:lock()
- FairSync:lock()
- AbstractQueuedSynchronizer:acquire(int arg)
- ReentrantLock:tryAcquire(int acquires) //此处真正开始加锁
- ReentrantLock使用公平锁时,加锁方法
unlock()
调用轨迹如下:- ReentrantLock:unlock()
- AbstractQueuedSynchronizer:release(int arg)
- Sync:tryRelease(int releases) //此处真正开始释放锁
- ReentrantLock使用非公平锁时,加锁方法
lock()
调用轨迹如下:- ReentrantLock:lock()
- NonfairSync:lock()
- AbstractQueuedSynchronizer:compareAndSetState(int expect, int update) //此处真正开始加锁
- 公平锁和非公平锁释放锁时,最后都要写一个volatile变量state。
- 公平锁获取锁时,首先会读volatile变量state。
- 非公平锁获取锁时,首先会用CAS更新volatile变量state。
package java.util.concurrent.locks;
public class ReentrantLock implements Lock, java.io.Serializable {
private final Sync sync;
//自定义同步器,静态内部类Sync继承了队列同步器AQS
abstract static class Sync extends AbstractQueuedSynchronizer {
abstract void lock();
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
//同步状态表示锁被一个线程重复获取的次数
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
} else if (current == getExclusiveOwnerThread()) {
//判断当前线程是否为已经获取锁的线程
int nextc = c + acquires; //如果是已经获取锁的线程再次请求获取锁,则将同步状态值增加
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc); //更新同步状态值
return true; //表示再次获取锁成功
}
return false;
}
protected final boolean tryRelease(int releases) {
int c = getState() - releases; //每释放一次锁,同步状态值减少
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
//当同步状态值为0时
free = true;
setExclusiveOwnerThread(null); //将占有锁的线程置为null
}
setState(c); //释放锁的最后,写volatile变量state
return free; //返回true表示最终释放锁成功
}
}
static final class FairSync extends Sync {
final void lock() {
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState(); //获取公平锁的开始,首先读volatile变量state
if (c == 0) {
/**
* hasQueuedPredecessors()用于判断同步队列中当前结点是否有前驱节点,
* 如果该方法返回true,表示有线程比当前线程更早的请求获取锁,
* 因此需要等待前驱线程获取并释放锁之后才能继续获取锁。
*/
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}