在多线程设计中,我猜常常会遇到线程间相互等待以及某个线程等待1个或多个线程的场景,比如多线程精密计算和大量数据处理,这里写下我自己的体会和理解。
我想应该有很多办法,如果是简单的1:1关系,那么可以wait()和notify()解决,就像一把锁和一把钥匙;如果是1:N关系,这个1就需要关心N的所有状态了,最笨的办法是1可以去查看N当前的状态,轮询询问工作是否做完。而好点的办法是N做完后主动告诉1,然后N就会有2种选择,要么听从1的命令,要么继续干自己其他的活。
用传统的方法我想应该是都能实现的,而JDK1.5提供了CyclicBarrier与CountDownLatch来解决了这两个问题,而她们的区别是:
CyclicBarrier使所有线程相互等待,而CountDownLatch使一个或多个线程等待其他线程。区别类似上面蓝色字体,CountDownLatch不会等待其他线程了,只要做完自己的工作就干自己的活去了,也就是run()方法里其他的任务。
Example:
- public static void testCountDownLatch() throws InterruptedException{
- CountDownLatch cdl=new CountDownLatch(2);
- ExecutorService exe=Executors.newFixedThreadPool(2);
- class Bow implements Runnable{
- CountDownLatch cdl;
- public Bow(CountDownLatch cdl){
- this.cdl=cdl;
- }
- public void run(){
- System.out.println("The bow is coming");
- System.out.println("kick a bow ");
- this.cdl.countDown();
- System.out.println("do other thing");
- }
- }
- exe.execute(new Bow(cdl));
- exe.execute(new Bow(cdl));
- exe.shutdown();
- System.out.println("Wait...");
- cdl.await();
- System.out.println("End..");
- }
- public static void main(String[] args) {
- try {
- Test.testCountDownLatch();
- } catch (InterruptedException e) {
- }
- }
public static void testCountDownLatch() throws InterruptedException{
CountDownLatch cdl=new CountDownLatch(2);
ExecutorService exe=Executors.newFixedThreadPool(2);
class Bow implements Runnable{
CountDownLatch cdl;
public Bow(CountDownLatch cdl){
this.cdl=cdl;
}
public void run(){
System.out.println("The bow is coming");
System.out.println("kick a bow ");
this.cdl.countDown();
System.out.println("do other thing");
}
}
exe.execute(new Bow(cdl));
exe.execute(new Bow(cdl));
exe.shutdown();
System.out.println("Wait...");
cdl.await();
System.out.println("End..");
}
public static void main(String[] args) {
try {
Test.testCountDownLatch();
} catch (InterruptedException e) {
}
}
输出的结果为:
The bow is coming
kick a bow
do other thing
Wait...
The bow is coming
kick a bow
do other thing
End..
如上所说do other thing不受影响。
写了一个CyclicBarrier的例子:
- public static void testCyclicBarrier() throws InterruptedException, BrokenBarrierException{
- CyclicBarrier barr=new CyclicBarrier(2+1);
- ExecutorService exe=Executors.newFixedThreadPool(2);
- class Bow implements Runnable{
- CyclicBarrier barr;
- public Bow(CyclicBarrier barr){
- this.barr=barr;
- }
- public void run(){
- System.out.println("The bow is coming");
- System.out.println("kick a down");
- try {
- barr.await();
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (BrokenBarrierException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- System.out.println("do other thing");
- }
- }
- exe.execute(new Bow(barr));
- exe.execute(new Bow(barr));
- exe.shutdown();
- System.out.println("Wait...");
- barr.await();
- System.out.println("End..");
- }
- public static void main(String[] args) {
- try {
- Test.testCyclicBarrier();
- } catch (InterruptedException e) {
- }
- catch (BrokenBarrierException e) {
- }
- }
public static void testCyclicBarrier() throws InterruptedException, BrokenBarrierException{
CyclicBarrier barr=new CyclicBarrier(2+1);
ExecutorService exe=Executors.newFixedThreadPool(2);
class Bow implements Runnable{
CyclicBarrier barr;
public Bow(CyclicBarrier barr){
this.barr=barr;
}
public void run(){
System.out.println("The bow is coming");
System.out.println("kick a down");
try {
barr.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("do other thing");
}
}
exe.execute(new Bow(barr));
exe.execute(new Bow(barr));
exe.shutdown();
System.out.println("Wait...");
barr.await();
System.out.println("End..");
}
public static void main(String[] args) {
try {
Test.testCyclicBarrier();
} catch (InterruptedException e) {
}
catch (BrokenBarrierException e) {
}
}
输出结果为:
Wait...
The bow is coming
kick a down
The bow is coming
kick a down
do other thing
End..
do other thing
这应该是CyclicBarrier吧?
兄弟你的例子来说明问题似乎让人不好琢磨。我也写了两个例子,大家一起学习下
- public class CyclicBarrierTest {
- public static void main(String[] args) {
- ExecutorService service = Executors.newCachedThreadPool();
- final CyclicBarrier cb = new CyclicBarrier(3);//构造方法里的数字标识有几个线程到达集合地点开始进行下一步工作
- for(int i=0;i<3;i++){
- Runnable runnable = new Runnable(){
- public void run(){
- try {
- Thread.sleep((long)(Math.random()*10000));
- System.out.println("线程" + Thread.currentThread().getName() +
- "即将到达集合地点1,当前已有" + cb.getNumberWaiting() + "个已经到达,正在等候");
- cb.await();
- Thread.sleep((long)(Math.random()*10000));
- System.out.println("线程" + Thread.currentThread().getName() +
- "即将到达集合地点2,当前已有" + cb.getNumberWaiting() + "个已经到达,正在等候");
- cb.await();
- Thread.sleep((long)(Math.random()*10000));
- System.out.println("线程" + Thread.currentThread().getName() +
- "即将到达集合地点3,当前已有" + cb.getNumberWaiting() + "个已经到达,正在等候");
- cb.await();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- };
- service.execute(runnable);
- }
- service.shutdown();
- }
- }
public class CyclicBarrierTest {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
final CyclicBarrier cb = new CyclicBarrier(3);//构造方法里的数字标识有几个线程到达集合地点开始进行下一步工作
for(int i=0;i<3;i++){
Runnable runnable = new Runnable(){
public void run(){
try {
Thread.sleep((long)(Math.random()*10000));
System.out.println("线程" + Thread.currentThread().getName() +
"即将到达集合地点1,当前已有" + cb.getNumberWaiting() + "个已经到达,正在等候");
cb.await();
Thread.sleep((long)(Math.random()*10000));
System.out.println("线程" + Thread.currentThread().getName() +
"即将到达集合地点2,当前已有" + cb.getNumberWaiting() + "个已经到达,正在等候");
cb.await();
Thread.sleep((long)(Math.random()*10000));
System.out.println("线程" + Thread.currentThread().getName() +
"即将到达集合地点3,当前已有" + cb.getNumberWaiting() + "个已经到达,正在等候");
cb.await();
} catch (Exception e) {
e.printStackTrace();
}
}
};
service.execute(runnable);
}
service.shutdown();
}
}
- public class CountdownLatchTest {
- public static void main(String[] args) {
- ExecutorService service = Executors.newCachedThreadPool();
- final CountDownLatch cdOrder = new CountDownLatch(1);
- final CountDownLatch cdAnswer = new CountDownLatch(3);
- for(int i=0;i<3;i++){
- Runnable runnable = new Runnable(){
- public void run(){
- try {
- System.out.println("线程" + Thread.currentThread().getName() +
- "正准备接受命令");
- cdOrder.await();
- System.out.println("线程" + Thread.currentThread().getName() +
- "已接受命令");
- Thread.sleep((long)(Math.random()*10000));
- System.out.println("线程" + Thread.currentThread().getName() +
- "回应命令处理结果");
- cdAnswer.countDown();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- };
- service.execute(runnable);
- }
- try {
- Thread.sleep((long)(Math.random()*10000));
- System.out.println("线程" + Thread.currentThread().getName() +
- "即将发布命令");
- cdOrder.countDown();
- System.out.println("线程" + Thread.currentThread().getName() +
- "已发送命令,正在等待结果");
- cdAnswer.await();
- System.out.println("线程" + Thread.currentThread().getName() +
- "已收到所有响应结果");
- } catch (Exception e) {
- e.printStackTrace();
- }
- service.shutdown();
- }
- }