采用闭锁(CountDownLatch)控制线程的先后顺序(一)

  CountDownLatch俗称闭锁,可以初始化一个值,每执行一次countDown()操作,值减一,减为0时,在闭锁前等待的线程即可执行,但是闭锁的值不能恢复,即一次性。下面是api文档中的介绍:

  A CountDownLatch is initialized with a given count. The await methods block until the current count reaches zero due to invocations of the countDown() method, after which all waiting threads are released and any subsequent invocations of await return immediately. This is a one-shot phenomenon -- the count cannot be reset. If you need a version that resets the count, consider using a CyclicBarrier.

  可以应用在一个线程等待其他事件发生后,再继续向下操作的场景。CyclicBarrier是栅栏,可以等待所有的线程到达后,一同干下面的事,这在另一种应用场景,在下一篇中有介绍。看CountDownLatch实例:

package com.smikevon.concurrent.tools;

import java.util.concurrent.CountDownLatch;

/**
 * @description: 要求:妈妈炒菜,但是这个时候还没买菜,也没有酱油了。为了更快的吃上饭,妈妈,小明,小强,分别行动,
 *                  妈妈负责敲响做饭铃(铃响之前不许动),兄弟二人就可以出发,然后妈妈收拾厨房调好料,小明负责买菜,小强负责买酱油,协作完成此项工作
 *
 *                  CountDownLatch 保证了其他线程执行完,才开始主线程.
 *                  特点:所有的其他线程执行完,执行目标线程(即执行了await的线程)
 * @date       : 2014年9月17日 下午2:41:50
 */
public class TestCountDownLatch_01 {

    public static void main(String[] args) {

        //响铃的次数
        final int BellRingCount = 1;
        //需要买菜的次数
        final int MaterialCount = 1;
        //需要买酱油的次数
        final int SoysauceCount = 1;

        final CountDownLatch bellRingLatch = new CountDownLatch(BellRingCount);
        final CountDownLatch buyMaterialLatch = new CountDownLatch(MaterialCount);
        final CountDownLatch buySoySauceLath = new CountDownLatch(SoysauceCount);

        new Thread(new Runnable() {
            public void run() {
                try {
                    System.out.println("准备做饭了哦!");
                    System.out.println("ding ding ding !!!");

                    /**
                     * 这条代码和下面的顺序颠倒就会导致死锁
                     */
                    bellRingLatch.countDown();
                    //等待菜和酱油都买回来了
                    buyMaterialLatch.await();
                    buySoySauceLath.await();

                    System.out.println("我是妈妈,菜和酱油都齐了,我开始做饭喽!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        },"妈妈").start();

        //小明等待铃响就去买菜
        new Thread(new Runnable() {
            public void run() {
                try {
                    System.out.println("我是小明,我准备去买菜(to go)!");
                    bellRingLatch.await();
                    System.out.println("我是小明,我已经买到了菜(get back)!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                buyMaterialLatch.countDown();
            }
        },"小明").start();

        new Thread(new Runnable() {
            public void run() {
                try {
                    System.out.println("我是小强,我准备去打酱油(to go)!");
                    bellRingLatch.await();
                    System.out.println("我是小强,我已经打到了酱油(get back)!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                buySoySauceLath.countDown();
            }
        },"小强").start();

    }

}

这里每个线程都持有一个闭锁,初始值为1,实际上这样做有些繁琐,因为小明和小强的行为模式一致,都是等待妈妈发出号令后出发,都是跑回来以后,妈妈才开始做饭,因此可以将两个闭锁合二为一。详情请看下一篇

时间: 2024-10-12 17:03:33

采用闭锁(CountDownLatch)控制线程的先后顺序(一)的相关文章

关于CountDownLatch控制线程的执行顺序

在上一篇文章中说过使用thread.join()方法.newSingleThreadExecutor单线程池来控制线程执行顺序.在文章的末尾我提出了一种构想,可否使用经典的生产者和消费者模型来控制执行顺序.在本文中,我将使用CountDownLatch来解决这个问题. 上图是countDownLatch的原理示意图.官方文档给出的解释是:CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程执行完后再执行.上图中线程A调用方法await()之后,进行阻塞,然后线

采用闭锁(CountDownLatch)控制线程的先后顺序(二)

还是上一篇的应用场景,将小明与小强持有的闭锁,合二为一,优化后的代码如下: package com.smikevon.concurrent.tools; import java.util.concurrent.CountDownLatch; /** * @description: 要求:妈妈炒菜,但是这个时候还没买菜,也没有酱油了.为了更快的吃上饭,妈妈,小明,小强,分别行动, * 妈妈负责敲响做饭铃(铃响之前不许动),兄弟二人就可以出发,然后妈妈收拾厨房调好料,小明负责买菜,小强负责买酱油,协

如何控制线程的执行顺序

错误示例: 1 public class Test { 2 public static void main(String[] args){ 3 thread1.start(); 4 thread2.start(); 5 thread3.start(); 6 } 7 8 static Thread thread1 = new Thread(new Runnable() { 9 @Override 10 public void run() { 11 System.out.println("threa

使用 CountDownLatch 控制多个线程执行顺序

有时候会有这样的需求,多个线程同时工作,然后其中几个可以随意并发执行,但有一个线程需要等其他线程工作结束后,才能开始.举个例子,开启多个线程分块下载一个大文件,每个线程只下载固定的一截,最后由另外一个线程来拼接所有的分段,那么这时候我们可以考虑使用CountDownLatch来控制并发. CountDownLatch是JAVA提供在java.util.concurrent包下的一个辅助类,可以把它看成是一个计数器,其内部维护着一个count计数,只不过对这个计数器的操作都是原子操作,同时只能有一

深入浅出 Java Concurrency (10): 锁机制 part 5 闭锁 (CountDownLatch)[转]

此小节介绍几个与锁有关的有用工具. 闭锁(Latch) 闭锁(Latch):一种同步方法,可以延迟线程的进度直到线程到达某个终点状态.通俗的讲就是,一个闭锁相当于一扇大门,在大门打开之前所有线程都被阻断,一旦大门打开所有线程都将通过,但是一旦大门打开,所有线程都通过了,那么这个闭锁的状态就失效了,门的状态也就不能变了,只能是打开状态.也就是说闭锁的状态是一次性的,它确保在闭锁打开之前所有特定的活动都需要在闭锁打开之后才能完成. CountDownLatch是JDK 5+里面闭锁的一个实现,允许一

Java 并发专题 :闭锁 CountDownLatch 之一家人一起吃个饭

最近一直整并发这块东西,顺便写点Java并发的例子,给大家做个分享,也强化下自己记忆. 每天起早贪黑的上班,父母每天也要上班,话说今天定了个饭店,一家人一起吃个饭,通知大家下班去饭店集合.假设:3个人在不同的地方上班,必须等到3个人到场才能吃饭,用程序如何实现呢? 作为一名资深屌丝程序猿,开始写代码实现: package com.zhy.concurrency.latch; public class Test1 { /** * 模拟爸爸去饭店 */ public static void fath

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

CountDownLatch和CyclicBarrier的主要联系和区别如下: 1.闭锁CountDownLatch做减计数,而栅栏CyclicBarrier则是加计数. 2.CountDownLatch是一次性的,CyclicBarrier可以重用. 3.CountDownLatch强调一个线程等多个线程完成某件事情.CyclicBarrier是多个线程互等,等大家都完成. 4.鉴于上面的描述,CyclicBarrier在一些场景中可以替代CountDownLatch实现类似的功能. 另外,值

线程的执行顺序

线程的执行完全是自发的去抢CPU时间片,谁先抢到谁就先去执行package com.pers.xiancheng; public class Test implements Runnable { int count;//默认是0 static Object obj = new Object(); @Override public void run() { //synchronized块锁定的是整个对象 synchronized (obj) {//synchronized 是用来获得对象锁,只有获

并发编程——闭锁CountDownLatch 与 栅栏CyclicBarrier

Java并发编程实践 目录 并发编程—— ConcurrentHashMap 并发编程—— 阻塞队列和生产者-消费者模式 并发编程——闭锁CountDownLatch 与 栅栏CyclicBarrier 概述 第1部分 闭锁 第2部分 栅栏 参考 第1部分 闭锁 闭锁是一种同步工具类,可以延迟线程的进度直到其到达终止状态.闭锁的作用相当于一扇门:在闭锁到达结束状态之前,这扇门一直是关闭的,并且没有任何线程能通过,当到达结束状态时,这扇门会打开并允许所有的线程通过.当闭锁到达结束状态后,将不会再改