多线程访问共享变量存在数据同时修改导致不一致问题,就需要锁来对共享数据的访问进行管理。
多个线程A B C 去竞争同一个锁L,存在线程获取锁的同步状态管理,排队获取锁,竞争获取锁,等待获取锁,释放锁唤醒其他等待中的线程问题。
Java中的synchronized关键字是一种锁的实现,隐式的管理多线程与锁的问题,由JVM实现。
JUC包下提供了显示锁来管理多线程和锁问题,Lock接口,队列同步器(AQS)AbstractQueuedSynchronizer分别定义了锁的操作接口和锁的实现基础模板。
AQS同步器的模板方法基本分为3类,独占式的获取与释放同步状态,共享式的获取与释放同步状态,查询等待队列中的等待线程情况。
独占锁获取了同步状态之后,其他独占和共享访问都会阻塞。 共享锁获取了同步状态之后,共享访问不会被阻塞,独占访问会被阻塞。
独占锁的获取过程
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
// FairSync尝试获取同步状态
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
// 当前状态为0 去尝试
if (c == 0) {
// 没有前驱节点并且获取成功 将当前线程设为持有锁的线程
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
// 当前状态不为0 判断持有锁的线程是不是当前线程 是的话重新设置状态值 说明ReentrantLock.FairSync是可重入锁
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
// 尝试获取同步状态
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);