第一部分 集合 http://jimichan.iteye.com/blog/951948
第二部分 线程池 http://jimichan.iteye.com/blog/951950
第三部分 锁 http://jimichan.iteye.com/blog/951954
第四部分 同步辅助类 http://jimichan.iteye.com/blog/951955
Concurrent In Java,第四部分 同步辅助类
2011-3-9 延昭 & 陈汝烨 版权所有,特别禁止发布到百度文库
这篇是来自公司内部分享会议是写的总结,有些内容没有表达出来,大家可以来踩,但是需留下原因,以便后续补充。
4. 同步辅助类
你提交了一些任务,但你想等它们都完成了再做另外一些事情;你提交了一些任务,但是不想让它们立刻执行,等你喊123开始的时候,它们才开始执行;等等这些场景,线程之间需要相互配合,或者等待某一个条件成熟执行。这些场景想你就需要用到同步辅助类。
4.1 CountDownLatch
CountDownLatch 内部有个计数器,通过构造函数来指定。这个类就好比是倒计时的电子牌,当倒计时为0的时候就可以一起做一些事情。
摘自JavaDoc的方法介绍
void | await() 使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断。 |
boolean | await(long timeout, TimeUnit unit) 使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或超出了指定的等待时间。 |
void | 递减锁存器的计数,如果计数到达零,则释放所有等待的线程。 |
long | getCount() 返回当前计数。 |
摘自JavaDoc的例子
class Driver { // ...
void main() throws InterruptedException {
CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(N);
for (int i = 0; i < N; ++i) // create and start threads
new Thread(new Worker(startSignal, doneSignal)).start();
doSomethingElse(); // don't let run yet
startSignal.countDown(); // let all threads proceed
doSomethingElse();
doneSignal.await(); // wait for all to finish
}
}
class Worker implements Runnable {
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;
Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
this.startSignal = startSignal;
this.doneSignal = doneSignal;
}
public void run() {
try {
startSignal.await();
doWork();
doneSignal.countDown();
} catch (InterruptedException ex) {} // return;
}
void doWork() { ... }
}
当CountDownLatch(1)的时候,它就好比是个信号枪了。
4.2 CyclicBarrier
这个同步辅助类,它让多个线程可以在多个屏障点进行等待,所以叫cyclic,而且有个附加选择你可以在线程到达屏障点后执行一个任务(在释放其他线程之前)
new CyclicBarrier(N,
new Runnable() {
public void run() {
mergeRows(...);
}
});
为了帮助你理解,假设一个场景。
有一个任务,A、B、C分别从三个仓库(甲乙丙)搬运不同3个不同的零件到客户X的公司,然后再一起组装机器,完成后一起坐车去公司总部。
这个任务需要ABC三个线程同时进行,但是由于从仓库到客户X那边距离不等、交通状态未知的情况下,所花费的时间也不等。同时由于三个人负责的零件不同,所以安装机器的时候花费时间也不一样。这个场景中有两个需要线程间等待的地方。CyclicBarrier就可以闪亮登场了。
public class Main3 {
public static void main(String[] args) {
CyclicBarrier barrier = new CyclicBarrier(3,new Runnable() {
@Override
public void run() {
System.out.println("到达公共屏障点");
}
});
ExecutorService es = Executors.newCachedThreadPool();
es.submit(new Worker("A", 5000, 8000, barrier));
es.submit(new Worker("B", 2000, 16000, barrier));
es.submit(new Worker("C", 9000, 2000, barrier));
es.shutdown();
}
static class Worker implements Runnable {
String name;
int t1;// 搬运零件所需要的时间
int t2;// 参与组装工作需要的时间
CyclicBarrier barrier;
public Worker(String name, int t1, int t2, CyclicBarrier barrier) {
super();
this.name = name;
this.t1 = t1;
this.t2 = t2;
this.barrier = barrier;
}
@Override
public void run() {
try {
print(name + " 开始搬运零件");
Thread.sleep(t1);// 模拟搬运时间
print(name + " 到达目的地");
int a = barrier.await(); // 等待其他人
if(a==0){
//说明是最后一个到的可以执行特殊操作
}
print(name + " 开始组装机器");
Thread.sleep(t2);// 模拟组装时间.
print(name + " 完成组装机器");
barrier.await(); // 等待其他人组装完毕
print(name + " 一起回总公司");
} catch (Exception e) {
e.printStackTrace();
}
}
}
static SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
static void print(String x) {
System.out.println( sdf.format(new Date()) + ": "+x);
}
}
4.3 Semaphore
一个经典的信号量计数器。一般被用来控制对共享资源同时访问线程数量的控制。
特殊情况下信号量设置为1,那么就类似互斥锁的功能。
此类的构造方法可选地接受一个公平 参数。当设置为 false 时,此类不对线程获取锁的顺序做任何保证。和之前提到的争用获取顺序一样,在非公平模式下,系统将获得更好的吞吐量,jvm也会保证在非公平模式下让所有线程得到访问机会。
参考书目
JavaDoc http://www.oschina.net/uploads/doc/javase-6-doc-api-zh_CN/overview-summary.html
java.util.concurrent 您不知道的 5 件事
http://www.ibm.com/developerworks/cn/java/j-5things4.html?ca=drs-
http://www.ibm.com/developerworks/cn/java/j-5things15/index.html