线程同步工具类[1]
Low level synchronize
Java 提供的Low level 同步方式主要有 synchronize 关键字 和 Lock 的实现类.
Lock的实现类主要有 ReentrantLock 和 ReentrantReadWriteLock.ReadLock 和 ReentrantReadWriteLock.WriteLock;
使用Object的wait(), notify() 和notifyAll() 方法, 也可以实现同步.
High level synchronize
Java 提供的high level 同步方式主要有
Semaphore, CountDownLatch, CyclicBarrier, Phaser, Exchanger.
Semaphore
Semaphore一般用来对共享资源的限制访问, 通过构造函数参数设置共享资源的总量, 通过acquire() 获得访问权限, 通过release() 释放已经获得的权限.
通过设置fair参数, 可以设置是否可以公平获得.
当acquire() 不能立即得到时, 当前线程会挂起, 直到获得或者被interrupted . acquire()的变种有:
void acquire(int permits);
void acquireUninterruptibly();
void acquireUninterruptibly(int permits);
boolean tryAcquire();
boolean tryAcquire(int permits);
boolean tryAcquire(int permits, long timeout, TimeUnit unit);
boolean tryAcquire(long timeout, TimeUnit unit);
release() 方法也有变种 release(int), 一次release 多个permit.
当permit 只有1的时候, 通常被称之为Binary Semaphore, 与很多Lock机制类似.
还提供了一些其他实用方法去check semaphore的当前状态, 比如: availablePermits(), getQueuedThreads(), getQueueLength(), isFair().
CountDownLatch
CountDownLatch 是一个非常简洁的线程同步实用工具, 初始设置等待的事件数为N (构造函数设置), 在等待的线程通过await()方法被block住, 直到有足够的其它线程调用Latch的countDown() 方法, 一直到count down 到0.
并不需要有N个线程调用countDown() 方法, 也许更多, 也许更少, 一个线程调用countDown方法之后, 不会被block, 会继续运行(与CyclicBarrier不同), 它有可能多次调用countDown() 方法.
同时, 也不一定只有一个线程在await(), 可能有多个线程同时在等待.
await() 的另外一个变种是只wait固定的时间await(long timeout, TimeUnit unit);
count数不能reset, 只能在构造函数时传入, 一旦count down 到0, 后续的await() 线程return immediately, 不会被block.
CyclicBarrier
N个线程等待一个同步点. 每个线程在同步点的代码处调用await()方法, 同时被block住, 直到有N个线程都调用了await()方法, 则所有在此同步点被block的线程被release. 被release之后, 这个Barrier可以被重复利用, 只要调用reset()方法, 就可以再次被利用, 所以冠以 Cyclic.
CyclicBarrier可选设置一个Runnable Command, 当N个线程都达到同步点之后, 并且在这些线程被release 之前, 这个Runnable command 被执行, 可以做一些求和, 总结之类的事情.
await() 有个变种, 可以设置最长等待时间 public int await(long timeout, TimeUnit unit);
await() 的返回值是线程到达barrier的index, (parties -1) 是第一个, 0 代表最后一个. 如果设置了Runnable Command, 那么最后一个到达的去执行这个Runnable Command. 如果你想设置第一个到达的去执行, 可以不要设置到 CyclicBarrier的构造函数中, 而是判断 await() 方法的返回值(arrival index).
若任何等待线程在等待期间被interrupt, 则所有线程抛出 InterruptedException;
若Barrier 被reset, 则抛出 BrokenBarrierException.
若设置的 timeout 时间超时, 则抛出 TimeoutException.
如果有线程timeout 或者被 interrupt, 或者Barrier Action 发生异常, 都会导致Barrier 变成 Broken 状态.