Condition接口 synchronized关键字配合Object类提供的wait(), wait(long timeout),notify(), notifyAll()等方法,可以实现等待/通知模式。Condition接口也提供了类似的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public interface Condition {void await () throws InterruptedException ;void awaitUninterruptibly () ;long awaitNanos (long nanosTimeout) throws InterruptedException ;boolean await (long time, TimeUnit unit) throws InterruptedException ;boolean awaitUntil (Date deadline) throws InterruptedException ;void signal () ;void signalAll () ;}
Lock接口 synchronized进行加锁时,都是隐式加锁,不容易因为释放锁导致出错,Lock接口需要显式加锁,更加灵活。Lock接口具备synchronized关键字所不具备的灵活性:
超时加锁,在指定时间内如果尚未获取到锁,返回false,如果在超时等待的时间内被中断,则抛出异常,获取到锁则返回true。
可以响应中断,在线程获取锁的过程中,可以响应中断,避免死锁发生。
非阻塞的获取锁,使用synchronized加锁,如果没有获得锁,则会进入阻塞状态,Lock加锁则是进入等待状态。
AbstractQueuedSychronizer AQS的设计是基于模版方法mo模式的,使用者需要继承AQS,重写指定的方法,然后组合到同步组件当中使用。同步组件对外提供的调用方法,可以委托给AQS子类具体执行。
AQS的使用 同步器提供了三个方法,可以线程安全的访问同步的状态。
1 2 3 4 5 6 7 8 9 10 11 12 13 private volatile int state;protected final int getState () { return state; } protected final void setState (int newState) { state = newState; } protected final boolean compareAndSetState (int expect, int update) { return unsafe.compareAndSwapInt(this , stateOffset, expect, update); }
具体同步组件只需视情况实现以下方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 protected boolean tryAcquire (long arg) { throw new UnsupportedOperationException(); } protected boolean tryRelease (long arg) { throw new UnsupportedOperationException(); } protected long tryAcquireShared (long arg) { throw new UnsupportedOperationException(); } protected boolean tryReleaseShared (long arg) { throw new UnsupportedOperationException(); } protected boolean isHeldExclusively () { throw new UnsupportedOperationException(); }
同步组件对外提供了一些模版方法,供外部查询和操作同步状态,这些方法可以支持超时和中断的独占式获取和共享式获取同步状态。值得注意的是,这些方法都已经被final修饰,不可重写。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public final void acquire (int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); } public final boolean release (int arg) { if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0 ) unparkSuccessor(h); return true ; } return false ; }
AQS的实现 同步队列 同步器依赖内部的同步队列来完成同步状态的管理,当前线程获取同步状态失败时,会将当前线程以及等待状态信息构成一个Node加入到队尾,同时会阻塞当前线程,当同步状态被释放时,会从队列首部唤醒节点中的线程,使其尝试获取同步状态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 NOde的部分字段 static final class Node { volatile int waitStatus; volatile Node prev; volatile Node next; volatile Thread thread; Node nextWaiter; }
AQS使用同步队列维护获取同步状态失败而阻塞的的线程,head指向头节点,每次获取状态失败的线程构成节点以后加入队列尾部。首节点是获取到同步状态的线程,当其释放同步状态时,会将首节点设置为其后继节点。
1 2 3 4 5 6 7 8 9 10 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); }