java-线程等待/同步的五种方法

  1. 云栖社区>
  2. 博客>
  3. 正文

java-线程等待/同步的五种方法

小金子 2016-06-07 23:00:48 浏览396
展开阅读全文

在面试时,经常会有面试官问道,一个主线程有多个子线程,如何能使子线程的业务执行完成之后,再执行主线程业务逻辑。对于这个问题,本人能够想到的有五种方法,详细请移步源码

1、使用线程类自带的join方法,将子线程加入到主线程,在子线程执行完之后,在执行主线程逻辑。

例如

[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. public static void joinDemo()  
  2.         throws InterruptedException  
  3.     {  
  4.         System.out.println("=========Test with join=====");  
  5.         JoinWorker worker1 = new JoinWorker("worker1");  
  6.         JoinWorker worker2 = new JoinWorker("worker2");  
  7.         worker1.start();  
  8.         worker2.start();  
  9.         worker1.join();  
  10.         worker2.join();  
  11.         doSuperWork();  
  12.     }  

2、使用JDK的并发包中的CountDownLatch类, 使用CountDownLatch,每个线程调用其countDown方法使计数器-1,主线程调用await方法阻塞等待,直到CountDownLatch计数器为0时继续执行,例如

首先,定义子线程

[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. static class CountDownLatchWorker extends Thread  
  2.     {  
  3.         String workerName;  
  4.   
  5.         CountDownLatch latch;  
  6.   
  7.         public CountDownLatchWorker(String workerName, CountDownLatch latch)  
  8.         {  
  9.             this.workerName = workerName;  
  10.             this.latch = latch;  
  11.         }  
  12.   
  13.         public void run()  
  14.         {  
  15.             System.out.println("Sub Worker " + workerName + " do work begin at "  
  16.                                + sdf.format(new Date()));  
  17.             new ThreadWaitDemo().doSomeWork();// 做实际工作  
  18.             System.out.println("Sub Worker " + workerName + " do work complete at "  
  19.                                + sdf.format(new Date()));  
  20.             latch.countDown();// 完成之后,计数器减一  
  21.   
  22.         }  
  23.     }  

主线程中调研await方法阻塞等待,直到所有线程完成

[html] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. public static void countDownLatchDemo()  
  2.         throws InterruptedException  
  3.     {  
  4.         System.out.println("=========Test with CountDownLatch=====");  
  5.         CountDownLatch latch = new CountDownLatch(2);  
  6.         CountDownLatchWorker worker1 = new CountDownLatchWorker("worker1", latch);  
  7.         CountDownLatchWorker worker2 = new CountDownLatchWorker("worker2", latch);  
  8.         worker1.start();  
  9.         worker2.start();  
  10.         //主线程阻塞等待  
  11.         latch.await();  
  12.         doSuperWork();  
  13.     }  

3、使用JDK并发包CyclicBarrier,CyclicBarrier类似于CountDownLatch也是个计数器, 不同的是CyclicBarrier的await()方法没被调用一次,计数便会减少1,并阻塞住当前线程。当计数减至0时,阻塞解除,所有在此 CyclicBarrier 上面阻塞的线程开始运行。 在这之后,如果再次调用 await()方法,计数就又会变成 N-1,新一轮重新开始CyclicBarrier初始时还可带一个Runnable的参数,此Runnable任务在CyclicBarrier的数目达到后,所有其它线程被唤醒前被执行。

示例如下

[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. public static void cyclicBarrierDemo()  
  2.         throws InterruptedException, BrokenBarrierException  
  3.     {  
  4.         System.out.println("=========Test with CyclicBarrier=====");  
  5.         CyclicBarrier cb = new CyclicBarrier(2new Runnable()  
  6.         {  
  7.             // 将主线程业务放到CyclicBarrier构造方法中,所有线程都到达Barrier时执行  
  8.             @SuppressWarnings("static-access")  
  9.             public void run()  
  10.             {  
  11.                 new ThreadWaitDemo().doSuperWork();  
  12.             }  
  13.         });// 设定需要等待两个线程  
  14.         ExecutorService executor = Executors.newFixedThreadPool(2);  
  15.         CyclicBarrierWorker worker1 = new CyclicBarrierWorker("worker1", cb);  
  16.         CyclicBarrierWorker worker2 = new CyclicBarrierWorker("worker2", cb);  
  17.         executor.execute(worker1);  
  18.         executor.execute(worker2);  
  19.         executor.shutdown();  
  20.     }  

4、使用JDK并发包中的Executors框架,ExecutorService的的invokeAll方法调研callable集合,批量执行多个线程,在invokeAll方法结束之后,再执行主线程其他业务逻辑

示例如下

[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. public static void callableDemo()  
  2.         throws InterruptedException  
  3.     {  
  4.         System.out.println("=========Test with Callable=====");  
  5.         List<Callable<Integer>> callList = new ArrayList<Callable<Integer>>();  
  6.         ExecutorService exec = Executors.newFixedThreadPool(2);  
  7.         // 采用匿名内部类实现  
  8.         callList.add(new Callable<Integer>()  
  9.         {  
  10.             public Integer call()  
  11.                 throws Exception  
  12.             {  
  13.                 System.out.println("Sub Worker worker1 do work begin at " + sdf.format(new Date()));  
  14.                 new ThreadWaitDemo().doSomeWork();// 做实际工作  
  15.                 System.out.println("Sub Worker worker1 do work complete at "  
  16.                                    + sdf.format(new Date()));  
  17.                 return 0;  
  18.             }  
  19.         });  
  20.         callList.add(new Callable<Integer>()  
  21.         {  
  22.             public Integer call()  
  23.                 throws Exception  
  24.             {  
  25.                 System.out.println("Sub Worker worker2 do work begin at " + sdf.format(new Date()));  
  26.                 new ThreadWaitDemo().doSomeWork();// 做实际工作  
  27.                 System.out.println("Sub Worker worker2 do work complete at "  
  28.                                    + sdf.format(new Date()));  
  29.                 return 0;  
  30.             }  
  31.         });  
  32.         exec.invokeAll(callList);  
  33.         exec.shutdown();  
  34.         doSuperWork();  
  35.   
  36.     }  
5、这种过于恶心,只简单说一下方法,主线程创建一个线程List,将每个子线程保存到列表中,然后定期轮询列表中子线程状态,当所有线程都完成之后,再执行主线程逻辑

网友评论

登录后评论
0/500
评论
小金子
+ 关注