概述
问题记录:
学习并发部分的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执行结束才会输出结果。
最后
以上就是含糊抽屉为你收集整理的Future与CountDownLatch使用的探讨问题记录:程序示例:结果讨论的全部内容,希望文章能够帮你解决Future与CountDownLatch使用的探讨问题记录:程序示例:结果讨论所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复