join方法与countDownLatch与CyclicBarrier的区别
来源:互联网 发布:q币可以在淘宝买东西吗 编辑:程序博客网 时间:2024/06/06 19:54
join方法:
当前线程中调用thread.join()会导致当前线程阻塞,此时只有当thread线程执行完后,当前线程才能继续往下执行。
join的工作原理是,不停检查thread是否存活,如果存活则让当前线程永远wait,直到thread线程终止
可以看看join的源码:
public final synchronized void join(long l) throws InterruptedException { long l1 = System.currentTimeMillis(); long l2 = 0L; if(l < 0L) throw new IllegalArgumentException("timeout value is negative"); if(l == 0L)//当线程是存活状态,则会一直等待下去 for(; isAlive(); wait(0L)); else do { if(!isAlive()) break; long l3 = l - l2; if(l3 <= 0L) break; wait(l3); l2 = System.currentTimeMillis() - l1; } while(true); }
我们可以看看具体例子:
public class JoinTest extends Thread { //工作者名 private String name; //工作时间 private long time; public JoinTest(String name, long time) { this.name = name; this.time = time; } @Override public void run() { // TODO 自动生成的方法存根 try { System.out.println(name+"开始工作"); Thread.sleep(time); System.out.println(name+"工作完成,耗费时间="+time); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } } public static void main(String[] args) throws ParseException, InterruptedException{ JoinTest worker0 = new JoinTest("worker0", 5000); JoinTest worker1 = new JoinTest("worker1", 5000); JoinTest worker2 = new JoinTest("worker2", 5000); worker0.start(); worker1.start(); worker0.join(); worker1.join(); System.out.println("准备工作就绪"); worker2.start();
}
控制台输出顺序如下:
观察控制台,可以明确看出,只有当线程worker0,worker1执行完毕之后,worker2才会开始执行。
countDownLatch:
一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
**构造方法摘要**CountDownLatch(int count) 构造一个用给定计数初始化的 CountDownLatch。
方法摘要
- void | await()
使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断。 - boolean | await(long timeout, TimeUnit unit)
使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或超出了指定的等待时间。 - void | countDown()
递减锁存器的计数,如果计数到达零,则释放所有等待的线程。 - long | getCount()
返回当前计数。 - String | toString()
返回标识此锁存器及其状态的字符串。
CountDownLatch 的一个有用特性是,它不要求调用 countDown 方法的线程等到计数到达零时才继续,而在所有线程都能通过之前,它只是阻止任何线程继续通过一个 await。
countDown 递减锁存器的计数,如果计数到达零,则释放所有等待的线程。
如果当前计数大于零,则将计数减少。如果新的计数为零,出于线程调度目的,将重新启用所有的等待线程。
如果当前计数等于零,则不发生任何操作。
如上面join的例子,将之改成为CountDownLatch
public class JoinTest extends Thread { //工作者名 private String name; //工作时间 private long time; CountDownLatch count; public JoinTest(String name, long time,CountDownLatch count) { this.name = name; this.time = time; this.count = count; } @Override public void run() { System.out.println(name+"开始工作"); count.countDown(); System.out.println(name+"工作完成,耗费时间="+time); } } public static void main(String[] args) throws ParseException, InterruptedException { CountDownLatch count = new CountDownLatch(2); JoinTest worker0 = new JoinTest("worker0", 5000,count); JoinTest worker1 = new JoinTest("worker1", 5000,count); JoinTest worker2 = new JoinTest("worker2", 5000,count); worker0.start(); worker1.start(); count.await(); System.out.println("准备工作就绪"); worker2.start(); }
从控制台结果可以看出,执行效果还是一样的。count计数器为零之前,当前线程会一直在等待着。
项目中countDown可运用大批量数据处理,例如处理100万的数据,可以将100万拆分成100个线程放入线程池中,计数器为100,只有当这100万的数据全部处理完毕,线程往下执行,告之数据已经全部处理完毕
int rum = 0; CountDownLatch countDownLatch; public CountDownLatchTest(CountDownLatch countDownLatch,int rum) { this.countDownLatch = countDownLatch; this.rum = rum; } @Override public void run() { // TODO Auto-generated method stub super.run(); System.out.println("第"+rum+"批数据开始处理"); countDownLatch.countDown(); } public static void main(String[] args) throws InterruptedException { // TODO Auto-generated method stub //假设有100万的数据需要处理,分成10个线程处理 CountDownLatch count = new CountDownLatch(10); for(int i =0 ;i<10;i++){ CountDownLatchTest a = new CountDownLatchTest(count,i); a.start(); } //处理完成之前所有线程一直等待着 count.await(); System.out.println("处理完毕"); }
CyclicBarrier:
类似于CountDownLatch,它也是一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。
- CyclicBarrier(int parties)
创建一个新的CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,但它不会在启动 barrier 时执行预定义的操作。 - CyclicBarrier(int parties, Runnable barrierAction)
创建一个新的CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,并在启动 barrier时执行给定的屏障操作,该操作由最后一个进入 barrier 的线程执行。
方法摘要
int | await()
在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。
int | await(long timeout, TimeUnit unit)
在所有参与者都已经在此屏障上调用 await 方法之前将一直等待,或者超出了指定的等待时间。
int | getNumberWaiting()
返回当前在屏障处等待的参与者数目。
int | getParties()
返回要求启动此 barrier 的参与者数目。
boolean | isBroken()
查询此屏障是否处于损坏状态。
void | reset()
将屏障重置为其初始状态。
在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。
如果当前线程不是将到达的最后一个线程,出于调度目的,将禁用它,且在发生以下情况之一前,该线程将一直处于休眠状态:
● 最后一个线程到达;或者
● 其他某个线程中断当前线程;或者
● 其他某个线程中断另一个等待线程;或者
● 其他某个线程在等待 barrier 时超时;或者
● 其他某个线程在此 barrier 上调用 reset()。
如果当前线程:
● 在进入此方法时已经设置了该线程的中断状态;或者
● 在等待时被中断
则抛出 InterruptedException,并且清除当前线程的已中断状态。
如果在线程处于等待状态时 barrier 被 reset(),或者在调用 await 时 barrier 被损坏,抑或任意一个线程正处于等待状态,则抛出 BrokenBarrierException 异常。
如果任何线程在等待时被 中断,则其他所有等待线程都将抛出 BrokenBarrierException 异常,并将 barrier 置于损坏状态。
如果当前线程是最后一个将要到达的线程,并且构造方法中提供了一个非空的屏障操作,则在允许其他线程继续运行之前,当前线程将运行该操作。如果在执行屏障操作过程中发生异常,则该异常将传播到当前线程中,并将 barrier 置于损坏状态。
CyclicBarrier 处理方式可以看做并行,简单例子,比如赛跑,当所有运动员准备就绪时,裁判发枪了,所有人同时开始起跑,如果一个运动员还没准备好,那么裁判会让所有运动员会等他准备好之后再开始发枪。
public class CyclicBarrierTest{ public static void main(String[] args) throws IOException, InterruptedException { //如果将参数改为4,但是下面只加入了3个选手,这永远等待下去 //Waits until all parties have invoked await on this barrier. CyclicBarrier barrier = new CyclicBarrier(3); ExecutorService executor = Executors.newFixedThreadPool(3); executor.submit(new Thread(new Runner(barrier, "1号选手",5000))); executor.submit(new Thread(new Runner(barrier, "2号选手",10000))); executor.submit(new Thread(new Runner(barrier, "3号选手",3000))); executor.shutdown(); } }class Runner extends Thread { // 一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point) private CyclicBarrier barrier; private String name; private long time; public Runner(CyclicBarrier barrier, String name, long time) { super(); this.barrier = barrier; this.name = name; this.time = time; } @Override public void run() { try { Thread.sleep(time); System.out.println(name + " 准备好了..."); // barrier的await方法,在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。 System.out.println("在此之前已经有" +barrier.getNumberWaiting()+ "位选手 准备好了..."); barrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } System.out.println(name + " 裁判发枪,起跑!"); } }
- join方法与countDownLatch与CyclicBarrier的区别
- CountDownLatch与CyclicBarrier的区别
- CountDownLatch与CyclicBarrier的区别
- CountDownLatch与CyclicBarrier的区别
- CountDownLatch与CyclicBarrier区别
- CyclicBarrier与CountDownLatch区别
- CountDownLatch与CyclicBarrier二者很重要的区别
- Java中CountDownLatch与CyclicBarrier的区别
- countDownLatch与join的区别
- java 多线程 CountDownLatch与join()方法区别
- CountDownLatch理解一:与join的区别
- CountDownLatch理解:与join的区别
- CountDownLatch理解一:与join的区别
- CountDownLatch理解一:与join的区别
- CountDownLatch理解:与join的区别
- CountDownLatch理解一:与join的区别
- CountDownLatch与CyclicBarrier的介绍与使用
- CountDownLatch 与 CyclicBarrier应用
- 项目小结和单例模式下的toast
- K-th Number (POJ
- EditText常用属性
- LintCode 48 主元素 III
- veri
- join方法与countDownLatch与CyclicBarrier的区别
- 工作中的tips~(一)
- [深度学习]Wake-Sleep算法
- 关于RecyclerView实现瀑布流,上下滑动时item之间互换位置的问题
- Tomcat与Java Web开发的思维导图
- “玲珑杯”郑州轻工业学院第九届ACM程序设计大赛圆满结束
- #pragma once 与 #ifndef...#define...#endif的比较
- 脚本作业
- LeetCode (Next Permutation)