java并发编程学习:如何等待多个线程执行完成后再继续后续处理(synchronized、join、FutureTask、CyclicBarrier)...

多线程应用中,经常会遇到这种场景:后面的处理,依赖前面的N个线程的处理结果,必须等前面的线程执行完毕后,后面的代码才允许执行。

在我不知道CyclicBarrier之前,最容易想到的就是放置一个公用的static变量,假如有10个线程,每个线程处理完上去累加下结果,然后后面用一个死循环(或类似线程阻塞的方法),去数这个结果,达到10个,说明大家都爽完了,可以进行后续的事情了,这个想法虽然土鳖,但是基本上跟语言无关,几乎所有主流编程语言都支持。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package  yjmyzz.test;
 
 
public  class  ThreadLockTest {
 
     public  static  int  flag =  0 ; //公用变量
 
     public  static  void  main(String[] args)  throws  Exception {
         ThreadLockTest testObj =  new  ThreadLockTest();
         final  int  threadNum =  10 ;
 
         for  ( int  i =  0 ; i < threadNum; i++) {
             new  Thread( new  MyRunable(i, testObj)).start();
         }
 
         while  ( true ) {
             if  (testObj.flag >= threadNum) {
                 System.out.println( "-----------\n所有thread执行完成!" );
                 break ;
             }
             Thread.sleep( 10 );
         }
     }
 
     static  class  MyRunable  implements  Runnable {
         int  _i =  0 ;
         ThreadLockTest _test;
 
         public  MyRunable( int  i, ThreadLockTest test) {
             this ._i = i;
             this ._test = test;
         }
 
         @Override
         public  void  run() {
             try  {
                 Thread.sleep(( long ) (Math.random() *  10 ));
                 System.out.println( "thread "  + _i +  " done" );
                 //利用synchronized获得同步锁
                 synchronized  (_test) {
                     _test.flag +=  1 ;
                 }
                 System.out.println( "thread "  + _i +  " => "  + _test.flag); //测试用
             catch  (Exception e) {
                 e.printStackTrace();
             }
         }
     }
}

输出结果:

thread 0 done
thread 0 => 1
thread 9 done
thread 9 => 2
thread 1 done
thread 1 => 3
thread 3 done
thread 3 => 4
thread 7 done
thread 7 => 5
thread 6 done
thread 6 => 6
thread 2 done
thread 2 => 7
thread 4 done
thread 4 => 8
thread 8 done
thread 8 => 9
thread 5 done
thread 5 => 10
-----------
所有thread执行完成!

 

除了这个方法,还可以借助FutureTask,达到类似的效果,其get方法会阻塞线程,等到该异步处理完成。缺点就是,FutureTask调用的是Callable,必须要有返回值,所以就算你不想要返回值,也得返回点啥

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package  yjmyzz.test;
 
import  java.util.concurrent.Callable;
import  java.util.concurrent.ExecutionException;
import  java.util.concurrent.FutureTask;
 
public  class  FutureTaskTest {
 
     public  static  void  main(String[] args)  throws  ExecutionException, InterruptedException {
 
         FutureTask<String>[] tasks =  new  FutureTask[ 10 ];
 
         for  ( int  i =  0 ; i < tasks.length; i++) {
             final  int  j = i;
             tasks[i] =  new  FutureTask<String>( new  Callable<String>() {
                 @Override
                 public  String call()  throws  Exception {
                     Thread.sleep(( long ) (Math.random() *  100 ));
                     return  "task"  + j +  " done" ;
                 }
             });
             new  Thread(tasks[i]).start();
         }
 
         for  ( int  i =  0 ; i < tasks.length; i++) {
             System.out.println(tasks[i].get()); //依次等待所有task执行完毕
         }
 
         System.out.println( "-----------\n所有task执行完成!" );
 
     }
}

执行结果:

task0 done
task1 done
task2 done
task3 done
task4 done
task5 done
task6 done
task7 done
task8 done
task9 done
-----------
所有task执行完成!

  

此外,Thread的Join方法也可以实现类似的效果,主要代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public  static  void  main(String[] args)  throws  Exception {
 
     final  int  threadNum =  10 ;
     Thread[] threads =  new  Thread[threadNum];
 
     for  ( int  i =  0 ; i < threadNum; i++) {
         threads[i] =  new  Thread( new  MyRunable(i));
         threads[i].start();
     }
 
     for  ( int  i =  0 ; i < threadNum; i++) {
         threads[i].join();
     }
 
     System.out.println( "-----------\n所有thread执行完成!" );
 
}

 

当然,这个需求最“正统”的解法应该是使用CyclicBarrier,它可以设置一个所谓的“屏障点”(或称集合点),好比在一项团队活动中,每个人都是一个线程,但是规定某一项任务开始前,所有人必须先到达集合点,集合完成后,才能继续后面的任务。  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package  yjmyzz.test;
 
import  java.util.concurrent.CyclicBarrier;
 
public  class  ThreadTest {
 
     public  static  void  main(String[] args)  throws  Exception {
 
         final  int  threadNum =  10 ;
         CyclicBarrier cb =  new  CyclicBarrier(threadNum +  1 ); //注意:10个子线程 + 1个主线程
 
         for  ( int  i =  0 ; i < threadNum; i++) {
             new  Thread( new  MyRunable(cb, i)).start();
         }
 
         cb.await();
         System.out.println( "-----------\n所有thread执行完成!" );
     }
 
     static  class  MyRunable  implements  Runnable {
         CyclicBarrier _cb;
         int  _i =  0 ;
 
         public  MyRunable(CyclicBarrier cb,  int  i) {
             this ._cb = cb;
             this ._i = i;
         }
 
         @Override
         public  void  run() {
             try  {
                 Thread.sleep(( long ) (Math.random() *  100 ));
                 System.out.println( "thread "  + _i +  " done,正在等候其它线程完成..." );
                 _cb.await();
             catch  (Exception e) {
                 e.printStackTrace();
             }
         }
     }
}

thread 9 done,正在等候其它线程完成...
thread 5 done,正在等候其它线程完成...
thread 0 done,正在等候其它线程完成...
thread 6 done,正在等候其它线程完成...
thread 4 done,正在等候其它线程完成...
thread 2 done,正在等候其它线程完成...
thread 3 done,正在等候其它线程完成...
thread 8 done,正在等候其它线程完成...
thread 7 done,正在等候其它线程完成...
thread 1 done,正在等候其它线程完成...
-----------
所有thread执行完成!

 

参考文章:

http://ifeve.com/concurrency-cyclicbarrier/

http://ifeve.com/thread-synchronization-utilities-5/

http://ifeve.com/semaphore-countdownlatch-cyclicbarrier-phaser-exchanger-in-java/  

http://ifeve.com/thread-management-7/

转载于:https://www.cnblogs.com/tuojunjie/p/7390700.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值