1.同步计数器CountDownLatch
2.线程通过Callable返回结果,通过Future获取结果
3.通过CompletableFuture管理多线程(基于jdk1.8)
CountDownLatch:
有一个正数计数器。
countDown()方法对计数器做减操作。直到所有的计数器归0(或中断或超时),await线程才会继续,否则一直阻塞。能保证以CountDownLatch所标记的前置任务都完成后,主任务再执行。
通过Callable类对象得到返回结果。用future得到Callable的返回。多个线程任务用线程池管理。调用3个任务里全部得到结果后,再把结果一并组装成list,用CountDownLatch统计3个线程的完成情况。通过await设置服务超时时间。
class Task implements Callable<String>{
private CountDownLatch latch;
private String taskName;
public Task(CountDownLatch latch, String taskName){
this.latch = latch;
this.taskName = taskName;
}
public String call() throws Exception{
try {
//省略3个url里得到结果的步骤,结果模拟演示为为API Result
return "APT Result " + taskName;
}
finally {
latch.countDown();//减小计数
System.out.println(taskName + " " + latch.getCount());
}
}
}
public class CountDownLatchDemo {
public static void main(String[] args){
ExecutorService executorService = Executors.newCachedThreadPool();
List<String> resultList = new ArrayList<>();
CountDownLatch latch = new CountDownLatch(3);
Future<String> future1 = executorService.submit(new Task(latch, "Task1"));
Future<String> future2 = executorService.submit(new Task(latch, "Task2"));
Future<String> future3 = executorService.submit(new Task(latch, "Task3"));
try {
latch.await(4000,TimeUnit.MILLISECONDS);
System.out.println("Count Down All Finished");
resultList.add(future1.get());
resultList.add(future2.get());
resultList.add(future3.get());
}catch (Exception e){
e.printStackTrace();
}
executorService.shutdown();
Iterator<String> it = resultList.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
}
}
输出:
Task2 1
Count Down All Finished
Task3 0
Task1 2
APT Result Task1
APT Result Task2
APT Result Task3
//Count一定在result前面
Future局限性和实际需求:
每个Future是独立的,多个Future很难关联
实际上要合并多个线程计算结果
多个线程并发,谁先返回就用谁的结果
CompletableFuture:
基于jdk1.8
1.在supplyAsnc方法中定义要执行的任务
2.通过thenAccept方法,消费之前线程的结果
public class CompletableFutrueDemo {
/**
* 第一个线程得到结果"result"可以在第二个线程中使用
* @param args
*/
public static void main(String[] args){
CompletableFuture.supplyAsync(()->{return "result";}).
thenAccept(v -> { System.out.println("Use the result: "+ v);});
}
}
输出:
Use the result: result
3.通过thenCombine方法整合多个线程的返回结果
public class CompletableFutureCombine {
public static void main(String[] args){
String combineResult = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
}catch (InterruptedException e){
e.printStackTrace();
}
return "part1";
}).thenCombine(CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
}catch (InterruptedException e){
e.printStackTrace();
}
return "part2";
}),(result1,result2)->{return result1 + " " + result2;}).join();
System.out.println(combineResult);
}
}
输出:
part1 part2
4.通过applyToEither方法,使用先返回的结果
public class CompletableFutureUseFast {
public static void main(String[] args){
String result = CompletableFuture.supplyAsync(()->{
try {
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
return "Running 1 second";
}).applyToEither(CompletableFuture.supplyAsync(()->{
try {
Thread.sleep(3000);
}catch (InterruptedException e){
e.printStackTrace();
}
return "Running 3 seconds";
}),(s)->{return s;}).join();
System.out.println(result);
}
}
输出:
Running 1 second
说辞:可以找个业务点说到CountDownLatch
CompletableFuture一般未必使用,但是要了解
总结:
1.了解通过CountDownLatch管理多线程协作的方法
2.了解通过Callable返回线程结果的方法
3.掌握用CompletableFuture类管理多线程间依赖的做法