Future与CountDownLatch使用的探讨

问题记录:

学习并发部分的Future与CountDownLatch时有个疑惑:既然Future对象的get方法会挂起等待到该线程执行完并返回结果时才执行,那么有时候为什么还需配合使用CountDownLatch呢?通过一个例子来直观对比下。

程序示例:

基本程序来自帖子:https://blog.csdn.net/wild46cat/article/details/91352666

我们在该程序上做进一步的小测试。

work线程会执行工作并返回工作时长给boss:

package day2.testfuture;

import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;

/**
 * @Author Worm
 * @Date 2020/10/6 10:37
 * @Version 1.0
 **/

public class WorkerWithResult implements Callable<Integer> {

    private CountDownLatch downLatch;

    private int workId;


    public WorkerWithResult(CountDownLatch downLatch, int workId) {

        this.downLatch = downLatch;

        this.workId = workId;

    }


    @Override

    public Integer call() throws Exception {

        int randomSleepTime = -1;

        try {

            System.out.println(workId + " is working...");

            randomSleepTime = new Random().nextInt(3000);
//测试着取消睡眠
//            Thread.sleep(randomSleepTime);

            System.out.println(workId + " finish the job.");

        } finally {

            downLatch.countDown();

            return randomSleepTime;

        }

    }

}

boss线程会接受所有worker的工作时长,接收时以list传入他的构造器:

package day2.testfuture;

import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * @Author Worm
 * @Date 2020/10/6 10:38
 * @Version 1.0
 **/
public class BossWithResult implements Runnable {

    private CountDownLatch downLatch;

    //保存每个工人的工作时间

    private List<Future> workTimeUseList;


    public BossWithResult(CountDownLatch downLatch, List<Future> workTimeUseList) {

        this.downLatch = downLatch;

        this.workTimeUseList = workTimeUseList;

    }


    @Override

    public void run() {

        try {

            System.out.println("i am boss,i wait the job ok");

//如果不用CountDownLatch,worker,boss线程并发执行。
// 那么在这里如果先执行到workTimeFuture.get()时,就是自动挂起等着,哪个完成了输出哪个。
// 如果用了CountDownLatch,worker,boss线程并发执行。
// 但是boss会在这里等着所有工人完工,workTimeFuture.get()输出就会很整齐

//            downLatch.await();

            System.out.println("job ok haha.....");

            for (Future<Integer> workTimeFuture : workTimeUseList) {

                System.out.println("work time is :" + workTimeFuture.get());

            }

        } catch (InterruptedException | ExecutionException e) {

            e.printStackTrace();

        }

    }

}

 

boss线程与四个worker线程是并发执行的:

package day2.testfuture;

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

/**
 * @Author Worm
 * @Date 2020/10/6 10:38
 * @Version 1.0
 **/

public class LatchDemo {

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        /**
         * 下面的程序使用的future对每个worker工作的时间进行统计,最后通过latch的countDown到0,
         * 通知boss,boss通过future传递的值能够知道每个worker的工作时间。
         * 这里有一点需要注意,在给boss传递参数的时候,可以让boss直接获得future中的值,但是如果使用
         * 这种方式,就没有必要使用latch了,因为在每个worker的值时需要使用future.get(),能够创建完成
         * 参数的时候,worker线程应该已经结束了。所以就没有必要使用latch了。
         *
         * 如果像下面程序传递的是future,然后在boss的线程中对future进行取值,就是需要latch的。因为在boss线程开
         * 开始的时候future没有执行完成,需要latch最后countDown到0,才能保证所有的future中都有结果了。

         */

        CountDownLatch downLatch = new CountDownLatch(4);

        ExecutorService executor = Executors.newFixedThreadPool(4);

        Future<Integer> future = executor.submit(new WorkerWithResult(downLatch, 1));

        Future<Integer> future1 = executor.submit(new WorkerWithResult(downLatch, 2));

        Future<Integer> future2 = executor.submit(new WorkerWithResult(downLatch, 3));

        FutureTask<Integer> futureTask = new FutureTask<>(new WorkerWithResult(downLatch, 4));

        executor.submit(futureTask);

        List<Future> workTimeList = new ArrayList<>();

        workTimeList.add(future);

        workTimeList.add(future1);

        workTimeList.add(future2);

        workTimeList.add(futureTask);

        executor.submit(new BossWithResult(downLatch, workTimeList));

        executor.shutdown();

    }

}

 

结果讨论

我们如果在boss中不使用 downLatch.await()结果如下:

可以发现不使用CountDownLatch时,虽然在boss中get结果时如果结果还没计算出来boss就会挂起等待到结果出来,但是总的来说是worker计算出一个结果时boss就有可能输出该结果(boss恰好抢到CPU执行权)。

当使用downLatch.await()时,boss线程会等到所有worker执行结束才会输出结果。

 

 
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值