【java并发】juc高级锁机制探讨
?
如果允许,则获取锁,如果不允许就阻塞线程,直到同步状态允许获取。
修改同步状态,并且唤醒等待线程。
提供volatile变量 state;? 用于同步线程之间的共享状态。通过CAS和volatile保证其原子性和可见性。对应源码里的定义:
/** * 同步状态 */ private volatile int state; /** *cas */ protected final boolean compareAndSetState(int expect, int update) { // See below for intrinsics setup to support this return unsafe.compareAndSwapInt(this, stateOffset, expect, update); }?
有别于wait和notiry。这里利用jdk1.5开始提供的LockSupport.park()和LockSupport.unpark()的本地方法实现,实现线程的阻塞和唤醒。
根据论文里描述,AQS里将阻塞线程封装到一个内部类Node里。并维护一个CHL Node FIFO队列。CHL队列是一个非阻塞的FIFO队列,也就是说往里面插入或移除一个节点的时候,在并发条件下不会阻塞,而是通过自旋锁和CAS保证节点插入和移除的原子性。实现无锁且快速的插入。关于非阻塞算法可以参考? Java 理论与实践: 非阻塞算法简介。CHL队列对应代码如下:
/** * CHL头节点 */ private transient volatile Node head; /** * CHL尾节点 */ private transient volatile Node tail;
?Node节点是对Thread的一个封装,结构大概如下:
static final class Node { /** 代表线程已经被取消*/ static final int CANCELLED = 1; /** 代表后续节点需要唤醒 */ static final int SIGNAL = -1; /** 代表线程在等待某一条件/ static final int CONDITION = -2; /** 标记是共享模式*/ static final Node SHARED = new Node(); /** 标记是独占模式*/ static final Node EXCLUSIVE = null; /** * 状态位 ,分别可以使CANCELLED、SINGNAL、CONDITION、0 */ volatile int waitStatus; /** * 前置节点 */ volatile Node prev; /** * 后续节点 */ volatile Node next; /** * 节点代表的线程 */ volatile Thread thread; /** *连接到等待condition的下一个节点 */ Node nextWaiter; }?
独占获取:tryAcquire本身不会阻塞线程,如果返回true成功就继续,如果返回false那么就阻塞线程并加入阻塞队列。
?
public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))//获取失败,则加入等待队列 selfInterrupt();}?
?
public final void acquireInterruptibly(int arg) throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); if (!tryAcquire(arg)) doAcquireInterruptibly(arg); } ?
public final boolean tryAcquireNanos(int arg, long nanosTimeout) throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); return tryAcquire(arg) || doAcquireNanos(arg, nanosTimeout);}?
?
独占模式释放:释放成功会唤醒后续节点
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 void acquireShared(int arg) { if (tryAcquireShared(arg) < 0) doAcquireShared(arg);}
?
public final void acquireSharedInterruptibly(int arg) throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); if (tryAcquireShared(arg) < 0) doAcquireSharedInterruptibly(arg); }
??
public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout) throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); return tryAcquireShared(arg) >= 0 || doAcquireSharedNanos(arg, nanosTimeout); }
?
public final boolean releaseShared(int arg) { if (tryReleaseShared(arg)) { doReleaseShared(); return true; } return false; } ?
protected boolean tryAcquire(int arg) { throw new UnsupportedOperationException(); } protected boolean tryRelease(int arg) { throw new UnsupportedOperationException(); } protected int tryAcquireShared(int arg) { throw new UnsupportedOperationException(); } protected boolean tryReleaseShared(int arg) { throw new UnsupportedOperationException(); }
?
final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) {//如果状态位为0,那么尝试获取 if (compareAndSetState(0, acquires)) {//基于CAS获取和修改状态 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 tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (isFirst(current) && 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; } return false; }
?可以看看 非公平锁的不会根据FIFO,而公平锁会判断是否是第一个线程,根据FIFO来执行。
?
?
?
?
参考文献:
The java.util.concurrent Synchronizer Framework
? Java 理论与实践: 非阻塞算法简介
《深入浅出 Java Concurrency》目录