CountDownLatch使用countDown方法来触发其他等待线程再执行的问题

来源:互联网 发布:打击电信网络诈骗视频 编辑:程序博客网 时间:2024/05/21 10:56
对于CountDownLatch这个类之前了解过, 根据java 文档,其作用如下:
A synchronization aid that allows one or more threads to wait until
a set of operations being performed in other threads completes.

下面应该是常规用法:
CountDownLatch works by having a counter initialized with number of threads, 
which is decremented each time a thread complete its execution. 
When count reaches to zero, it means all threads have completed their execution, 
and thread waiting on latch resume the execution.

其步骤如下:
1. Main thread start
2. Create CountDownLatch with count N for N threads
3. Create and start N threads
4. Main thread wait on latch   - await()
5. N threads completes there tasks are returns  -countDown() to decrement count 
6. Main thread resume execution  -count == 0  


还有一种用法:
1. Main thread start
2. Create CountDownLatch with count 1 for N threads
3. Create and start N threads
4. N threads are waiting for latch with 1 count  -await()
5. Main thread count down  - countDown() to decrement count to 0
6. Main thread resume execution


在第二种用法中,第5步执行前应该有个等待的时间,让所有的线程都
执行到await。

比如下面的例子,用ExecutorService的submit来新建和启动线程,线程
在被submit 之后就已经执行了,而且主线程也会继续执行,很有可能有些
线程没有执行到await, 主线程就已经countDown了。


package thread;


import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;


/**
 * 利用两个 CountDownLatch 来计算10人跑步成绩平均值:
 *
 * 1) beginLatch 计数器为1, 在每个runner线程中调用beginLatch的await方法,
 *    等待主线程中beginLatch的countDown方法调用然后一起执行;
 *
 * 2) endLatch 计数器为10, 在主线程中调用endLatch的await方法,等待每个runner线程中调用endLatch的countDown  * 方法,将10递减为0后计算总成绩的平均值.
 *    
 */
public class TestCountDownLatch {


    public static void main(String[] args) throws Exception {
        //发令枪只响一次
        CountDownLatch beginLatch = new CountDownLatch(1);
        //有10个运动员
        int num = 10;
        CountDownLatch endLatch = new CountDownLatch(num);


        //每个运动员一个赛道
        ExecutorService es = Executors.newFixedThreadPool(num);


        List<Future<Integer>> futureList = new ArrayList<>();


        for (int i = 0; i < num; i++) {
            futureList.add(es.submit(new Runner(beginLatch, endLatch)));
        }


//        TimeUnit.MILLISECONDS.sleep(500); //预备时间, 多长时间能让运动员都准备好?
        System.out.println("Run");
        //发令枪响,开始跑步
        beginLatch.countDown();


        //等待所有人跑完全程
        endLatch.await();


        int sum = 0;


        for (Future<Integer> future : futureList) {
            sum += future.get(); //计算总成绩
        }


        System.out.println("Average score is: "+ sum / num);
        es.shutdown();
    }
}


class Runner implements Callable<Integer> {
    CountDownLatch begin;
    CountDownLatch end;


    public Runner(CountDownLatch begin, CountDownLatch end) {
        this.begin = begin;
        this.end = end;
    }


    @Override
    public Integer call() throws Exception {
        long threadId = Thread.currentThread().getId();
        //跑步的成绩
        int score = new Random().nextInt(25);
        //等待发令枪响
        System.out.println(threadId + " is ready");
        begin.await();
        System.out.println(threadId + " is running...");
        //跑步中
//        TimeUnit.MILLISECONDS.sleep(500);
        //跑步者已经跑完全程
        end.countDown();
        System.out.println(threadId + " is finished");
        return score;
    }
}




如果注释掉主线程中下面的这一段代码:
TimeUnit.MILLISECONDS.sleep(500); //预备时间, 多长时间能让运动员都准备好?


那么可能会出现抢跑的结果:
10 is ready
13 is ready
Run
14 is ready
14 is running...
14 is finished
11 is ready
11 is running...
11 is finished
15 is ready
15 is running...
15 is finished
17 is ready
17 is running...
17 is finished
19 is ready
19 is running...
19 is finished
12 is ready
16 is ready
16 is running...
16 is finished
12 is running...
12 is finished
10 is running...
10 is finished
13 is running...
13 is finished
18 is ready
18 is running...
18 is finished
Average score is: 11


如果不注释掉主线程中的等待时间,那么结果显示为都准备好了才跑:
11 is ready
15 is ready
17 is ready
13 is ready
19 is ready
10 is ready
14 is ready
18 is ready
12 is ready
16 is ready
Run
11 is running...
11 is finished
15 is running...
15 is finished
17 is running...
17 is finished
13 is running...
19 is running...
19 is finished
13 is finished
10 is running...
10 is finished
14 is running...
14 is finished
18 is running...
18 is finished
12 is running...
12 is finished
16 is running...
16 is finished

Average score is: 7


是这个等待时间不好确定. 一般可能会设置的超过需要的时间很多。








文中代码出自 《编写高质量代码改善Java程序的151个建议》

参考文章:

https://howtodoinjava.com/core-java/multi-threading/when-to-use-countdownlatch-java-concurrency-example-tutorial/






阅读全文
0 0
原创粉丝点击