当前位置:首页 > 开发 > 编程语言 > 多线程 > 正文

并发编程陷阱系列(八)不要吞食CountDownLatch的线程异常

发表于: 2013-05-23   作者:Copperfield   来源:转载   浏览:
摘要:  之前的文章中已经介绍了无处不在的InterruptedException的处理方式了,使用CountDownLatch也会有类似的问题(正确的处理方式见下面代码: Thread.currentThread().interrupt()),顺便复习下CountDownLatch的使用方法。   在一些应用中,有多个线程,某个线程会在其他线程执行完毕之后才开始执行。 比如,想

 之前的文章中已经介绍了无处不在的InterruptedException的处理方式了,使用CountDownLatch也会有类似的问题(正确的处理方式见下面代码: Thread.currentThread().interrupt()),顺便复习下CountDownLatch的使用方法。

 

在一些应用中,有多个线程,某个线程会在其他线程执行完毕之后才开始执行。

比如,想象有一个程序先下载一堆网页,压缩然后通过EMAIL发送出去。如果要用多线程来实现,压缩网页的程序不能在下载完成后启动。

如何处理呢?一个非常简便的方法就是使用java.util.concurrent中的CountDownLatch。

在CountDownLatch中,你可以定义一个数字,每次操作完成后数字都会减一。如果所有操作都完成了,这个数字变成0,使用同一个CountDownLatch作为同步工具的其他线程可以调用await方法完成任务。

然我们看一个简单的例子,第一个类是一个简单的Runnable。在我们的例子中,这个类没什么用处,只是采取随机休眠的方式模拟一些任务的执行。

import java.util.Random;
import java.util.concurrent.CountDownLatch;
 
public class Worker implements Runnable {
 
    private CountDownLatch countDownLatch;
 
    public Worker(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }
 
    @Override
    public void run() {
        try {
            Thread.sleep(getRandomSeconds()); // sleep random time to simulate long running task
            System.out.println("Counting down: " + Thread.currentThread().getName());
            this.countDownLatch.countDown();
        } catch (InterruptedException ex) {
            Thread.currentThread().interrupt();
        }
    }
 
    // returns a long between 0 and 9999
    private long getRandomSeconds() {
        Random generator = new Random();
        return Math.abs(generator.nextLong() % 10000);
    }
}

 

 唯一有意思的是这一行调用:

 

this.countDownLatch.countDown();

一旦任务执行完毕,countDownLatch中的计数器就会减一。

 

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
 
public class WorkManager {
 
    private CountDownLatch countDownLatch;
    private static final int NUMBER_OF_TASKS = 5;
 
    public WorkManager() {
        countDownLatch = new CountDownLatch(NUMBER_OF_TASKS);
    }
 
    public void finishWork() {
        try {
            System.out.println("START WAITING");
            countDownLatch.await();
            System.out.println("DONE WAITING");
        } catch (InterruptedException ex) {
            Thread.currentThread().interrupt();
        }
    }
 
    public void startWork() {
        ExecutorService executorService = Executors.newFixedThreadPool(NUMBER_OF_TASKS);
 
        for (int i = 0; i < NUMBER_OF_TASKS; i++) {
            Worker worker = new Worker(countDownLatch);
            executorService.execute(worker);
        }
        executorService.shutdown();
    }
 
    public static void main(String[] args) {
        WorkManager workManager = new WorkManager();
        System.out.println("START WORK");
        workManager.startWork();
        System.out.println("WORK STARTED");
        workManager.finishWork();
        System.out.println("FINISHED WORK");
    }
}

 

 

startWork方法使用ExecutorService执行Runnable类。

 

在finishWork方法中,await方法会一直等待,直到CountDownLatch内部的计数器为0时,await后的方法才会继续执行下去。

执行结果:

 

START WORK
WORK STARTED
START WAITING
Counting down: pool-1-thread-3
Counting down: pool-1-thread-4
Counting down: pool-1-thread-1
Counting down: pool-1-thread-5
Counting down: pool-1-thread-2
DONE WAITING
FINISHED WORK

 

参考:http://markusjais.com/how-to-use-java-util-concurrent-countdownlatch/

 

 

并发编程陷阱系列(八)不要吞食CountDownLatch的线程异常

  • 0

    开心

    开心

  • 0

    板砖

    板砖

  • 0

    感动

    感动

  • 0

    有用

    有用

  • 0

    疑问

    疑问

  • 0

    难过

    难过

  • 0

    无聊

    无聊

  • 0

    震惊

    震惊

版权所有 IT知识库 CopyRight © 2009-2015 IT知识库 IT610.com , All Rights Reserved. 京ICP备09083238号