关闭

Java中CountDownLatch、CyclicBarrier、Thread.join方法基本应用

409人阅读 评论(0) 收藏 举报
分类:

在多线程程序设计中,经常会遇到一个线程等待一个或多个线程的场景,遇到这样的场景应该如何解决?

如果是一个线程等待一个线程,则可以通过await()和notify()来实现;
如果是一个线程等待多个线程,则就可以使用CountDownLatch和CyclicBarrier来实现比较好的控制。

(1)CyclicBarrier

需要所有的子任务都完成时,才执行主任务,这个时候就可以选择使用CyclicBarrier。

import java.util.concurrent.BrokenBarrierException;  
import java.util.concurrent.CyclicBarrier;  

public class BarrierTest {  

    private static final int THREAD_COUNT = 10;  

    private final static CyclicBarrier CYCLIC_BARRIER = new CyclicBarrier(THREAD_COUNT  ,  
        new Runnable() {  
            public void run() {  
                System.out.println("======>我是导游,本次点名结束,准备走下一个环节!");  
            }  
        }  
    );  

    public static void main(String []args)   
            throws InterruptedException, BrokenBarrierException {  
        for(int i = 0 ; i < 10 ; i++) {  
            new Thread(String.valueOf(i)) {  
                public void run() {  
                    try {  
                        System.out.println("我是线程:" + this.getName() + " 我们达到旅游地点!");  
                        CYCLIC_BARRIER.await();  
                        System.out.println("我是线程:" + this.getName() + " 我开始骑车!");  
                        CYCLIC_BARRIER.await();  
                        System.out.println("我是线程:" + this.getName() + " 我们开始爬山!");  
                        CYCLIC_BARRIER.await();  
                        System.out.println("我是线程:" + this.getName() + " 我们回宾馆休息!");  
                        CYCLIC_BARRIER.await();  
                        System.out.println("我是线程:" + this.getName() + " 我们开始乘车回家!");  
                        CYCLIC_BARRIER.await();  
                        System.out.println("我是线程:" + this.getName() + " 我们到家了!");  
                    } catch (InterruptedException e) {  
                        e.printStackTrace();  
                    } catch (BrokenBarrierException e) {  
                        e.printStackTrace();  
                    }  
                }  
            }.start();  
        }  
    }  
}  

运行结果:

我是线程:0 我们达到旅游地点!
我是线程:1 我们达到旅游地点!
我是线程:2 我们达到旅游地点!
我是线程:3 我们达到旅游地点!
我是线程:4 我们达到旅游地点!
我是线程:5 我们达到旅游地点!
我是线程:6 我们达到旅游地点!
我是线程:7 我们达到旅游地点!
我是线程:8 我们达到旅游地点!
我是线程:9 我们达到旅游地点!
======>我是导游,本次点名结束,准备走下一个环节!
我是线程:9 我开始骑车!
我是线程:0 我开始骑车!
我是线程:1 我开始骑车!
我是线程:2 我开始骑车!
我是线程:4 我开始骑车!
我是线程:3 我开始骑车!
我是线程:7 我开始骑车!
我是线程:8 我开始骑车!
我是线程:6 我开始骑车!
我是线程:5 我开始骑车!
======>我是导游,本次点名结束,准备走下一个环节!
我是线程:6 我们开始爬山!
我是线程:5 我们开始爬山!
我是线程:7 我们开始爬山!
我是线程:8 我们开始爬山!
我是线程:3 我们开始爬山!
我是线程:4 我们开始爬山!
我是线程:2 我们开始爬山!
我是线程:1 我们开始爬山!
我是线程:0 我们开始爬山!
我是线程:9 我们开始爬山!
======>我是导游,本次点名结束,准备走下一个环节!
我是线程:5 我们回宾馆休息!
我是线程:3 我们回宾馆休息!
我是线程:7 我们回宾馆休息!
我是线程:8 我们回宾馆休息!
我是线程:6 我们回宾馆休息!
我是线程:4 我们回宾馆休息!
我是线程:0 我们回宾馆休息!
我是线程:1 我们回宾馆休息!
我是线程:2 我们回宾馆休息!
我是线程:9 我们回宾馆休息!
======>我是导游,本次点名结束,准备走下一个环节!
我是线程:9 我们开始乘车回家!
我是线程:2 我们开始乘车回家!
我是线程:4 我们开始乘车回家!
我是线程:1 我们开始乘车回家!
我是线程:0 我们开始乘车回家!
我是线程:6 我们开始乘车回家!
我是线程:7 我们开始乘车回家!
我是线程:8 我们开始乘车回家!
我是线程:3 我们开始乘车回家!
我是线程:5 我们开始乘车回家!
======>我是导游,本次点名结束,准备走下一个环节!
我是线程:3 我们到家了!
我是线程:0 我们到家了!
我是线程:1 我们到家了!
我是线程:4 我们到家了!
我是线程:2 我们到家了!
我是线程:9 我们到家了!
我是线程:6 我们到家了!
我是线程:7 我们到家了!
我是线程:5 我们到家了!
我是线程:8 我们到家了!

可以看到await()的作用就是当所有的线程都运行到这个地方的时候,才能继续往下执行。

(2)CountDownLatch

CountDownLatch类是一个同步计数器,构造时传入int参数,该参数就是计数器的初始值,每调用一次countDown()方法,计数器减1,计数器大于0 时,await()方法会阻塞程序继续执行。

    import java.util.concurrent.CountDownLatch;  

    public class CountDownLatchTest {  

        private final static int GROUP_SIZE = 5;  

        public static void main(String []args) {  
            final CountDownLatch start_count_down = new CountDownLatch(1);  
            System.out.println("==========================>\n比赛开始:");  
            for(int i = 0 ; i < GROUP_SIZE ; i++) {  
                new Thread(String.valueOf(i)) {  
                    public void run() {  
                        System.out.println("第:" + this.getName() + " 号线程,我已经准备就绪!");  
                        try {  
                            start_count_down.await();// 计数器大于0,线程等待
                        } catch (InterruptedException e) {  
                            e.printStackTrace();  
                        }  
                        System.out.println("第:" + this.getName() + " 号线程,我已执行完成!");  
                    }  
                }.start();  
            }  
            try {  
                Thread.sleep(1000);  // 一秒之后,等所有线程准备就绪就开始
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
            System.out.println("各就各位,预备!");  
            start_count_down.countDown();// 计数器减1,变成了0,线程停止等待
        } 
    } 

运行结果如下:

==========================>
比赛开始:
第:0 号线程,我已经准备就绪!
第:1 号线程,我已经准备就绪!
第:2 号线程,我已经准备就绪!
第:3 号线程,我已经准备就绪!
第:4 号线程,我已经准备就绪!
各就各位,预备!
第:0 号线程,我已执行完成!
第:2 号线程,我已执行完成!
第:1 号线程,我已执行完成!
第:4 号线程,我已执行完成!
第:3 号线程,我已执行完成!

可以看到CyclicBarrier执行await方法之后,所有线程运行到这个地方会自动阻塞,当所有线程都到达之后,所有线程会自动向下接着运行。
CountDownLatch执行await后会查看计数器,如果计数器大于0就会阻塞,当执行coutDown之后,计数器就会减1,如果计数器不大于0,这样之前阻塞的线程就会进行执行,也就是说CountDownLatch是可控的。

(3)Thread.join()
Thread类中有一个join()方法,在一个线程中启动另外一个线程的join方法,当前线程将会挂起,而执行被启动的线程,知道被启动的线程执行完毕后,当前线程才开始执行。join方法定义在Thread类中,则调用者必须是一个线程。

class ThreadTesterA implements Runnable {  

    private int counter;  

    @Override  
    public void run() {  
        while (counter <= 10) {  
            System.out.print("Counter = " + counter + " ");  
            counter++;  
        }  
        System.out.println();  
    }  
}  

class ThreadTesterB implements Runnable {  

    private int i;  

    @Override  
    public void run() {  
        while (i <= 10) {  
            System.out.print("i = " + i + " ");  
            i++;  
        }  
        System.out.println();  
    }  
}  

public class ThreadTester {  
    public static void main(String[] args) throws InterruptedException {  
        Thread t1 = new Thread(new ThreadTesterA());  
        Thread t2 = new Thread(new ThreadTesterB());  
        t1.start();  
        t1.join(); // wait t1 to be finished  
        t2.start();  
        t2.join(); // in this program, this may be removed  
    }  
} 

t1启动后,调用join()方法,直到t1的计数任务结束,才轮到t2启动,然后t2也开始计数任务。可以看到,实例中,两个线程就按着严格的顺序来执行了。

参考文章:
http://blog.csdn.net/xieyuooo/article/details/8572543

0
0
查看评论

CountDownLatch和CyclicBarrier的应用场景

jdk1.5之后,java的concurrent包提供了一些并发工具类,比如CountDownLatch和CyclicBarrier,这里只讲它们的应用场景,暂不作原理剖析。 CountDownLatch:一个线程A等待其它线程都执行完毕后,线程A继续执行。这个线程A也可以是一组线程(使用同一个C...
  • suibo0912hf
  • suibo0912hf
  • 2015-09-15 09:07
  • 1035

java并发编程中CountDownLatch和CyclicBarrier的使用

java并发编程中CountDownLatch和CyclicBarrier的使用 <br /> <br />在多线程程序设计中,经常会遇到一个线程等待一个或多个线程的场景,遇到这样的场景应该如何解决?<br />如果是一个线程等待一个线程,则可...
  • hbzyaxiu520
  • hbzyaxiu520
  • 2011-02-14 12:47
  • 6417

线程执行顺序——CountDownLatch、CyclicBarrier 、join()、线程池

本文主要围绕一个问题展开:线程执行顺序,比如某个线程在其他线程并发执行完毕后最后执行。join介绍join()是Thread类的一个方法,join()方法的作用是等待这个线程结束。t.join()方法阻塞调用此方法的线程(calling thread),直到线程t完成,此线程再继续;通常用于在mai...
  • lzx_2011
  • lzx_2011
  • 2017-03-10 00:02
  • 921

CyclicBarrier和CountDownLatch区别

这两天写多线程时,用到了CyclicBarrier,下意识的认为CyclicBarrier和CountDownLatch作用很像,就翻阅资料查了一下,说一下他们的区别吧 CyclicBarrier和CountDownLatch 都位于java.util.concurrent 这个包下 ...
  • tolcf
  • tolcf
  • 2016-03-18 19:19
  • 6516

[沧海拾遗]java并发之CountDownLatch、Semaphore和CyclicBarrier

JAVA并发包中有三个类用于同步一批线程的行为,分别是CountDownLatch、Semaphore和CyclicBarrier。 CountDownLatch CountDownLatch是一个计数器闭锁,主要的功能就是通过await()方法来阻塞住当前线程,然后等待计数器减少到0了...
  • yanhandle
  • yanhandle
  • 2013-06-03 19:30
  • 6476

CountDownLatch、CyclicBarrier、Semaphore共同之处与区别以及各自使用场景

摘要: jdk1.5之后,java的concurrent包提供了一些并发工具类,比如CountDownLatch和CyclicBarrier,Semaphore。这里简要的比较一下他们的共同之处与区别,同时介绍一下他们的使用场景。 CountDownLatch:一个线程A或是组线程A等...
  • jackyechina
  • jackyechina
  • 2016-10-26 10:55
  • 2240

闭锁CountDownLatch和栅栏CyclicBarrier之异同举例

CountDownLatch和CyclicBarrier的主要联系和区别如下: 1.闭锁CountDownLatch做减计数,而栅栏CyclicBarrier则是加计数。 2.CountDownLatch是一次性的,CyclicBarrier可以重用。 3.CountDownLatch强调一个线程等...
  • gaolu
  • gaolu
  • 2015-05-29 09:02
  • 10783

CountDownLatch, CyclicBarrier, Phaser 总结

CountDownLatch的一个非常典型的应用场景是:有一个任务想要往下执行,但必须要等到其他的任务执行完毕后才可以继续往下执行。假如我们这个想要继续往下执行的任务调用一个CountDownLatch对象的await()方法,其他的任务执行完自己的任务后调用同一个CountDownLatch对象上...
  • walkerJong
  • walkerJong
  • 2016-02-03 15:55
  • 753

CountDownLatch理解一:与join的区别

首先,我们来看一个应用场景1: 假设一条流水线上有三个工作者:worker0,worker1,worker2。有一个任务的完成需要他们三者协作完成,worker2可以开始这个任务的前提是worker0和worker1完成了他们的工作,而worker0和worker1是可以并行他们各自的工作的。 如果...
  • zhutulang
  • zhutulang
  • 2015-09-17 00:21
  • 6559

CountDownLatch与CyclicBarrier详解

1. CountDownLatch 1.1 简介 CountDownLatch是一个同步辅助类,通过它可以完成类似于阻塞当前线程的功能,即:一个线程或多个线程一直等待,直到其他线程执行的操作完成。CountDownLatch用一个给定的计数器来初始化,该计数器的操作是原子操作,即同时只能有一个线...
  • xianymo
  • xianymo
  • 2015-07-13 17:34
  • 1125
    关于我
    目前就职于百度
    研究方向:Android,机器学习
    联系方式QQ:2979218500


      欢迎关注微信公众号:DroidMind
      精品内容独家发布平台
      呈现与博客不一样的技术干货
    个人资料
    • 访问:535456次
    • 积分:8469
    • 等级:
    • 排名:第2801名
    • 原创:288篇
    • 转载:48篇
    • 译文:22篇
    • 评论:70条