如何让主线程等待所有线程结束之后再执行
1、Future的机制,使用Future.get()阻塞等待结果(Future,FutureTask)
2、CountDownLatch同步工具类,此类的作用就是一个线程等待所有线程结束之后再执行
3、CompletableFuture 与Future机制类似,同样是使用get阻塞等待结果,不过此类可以使任务并行合并以及串行,相当于是Future的增强版
4、线程池的isTerminated方法,当调用shutdown()方法后,并且所有提交的任务完成后才会返回为true
5、Thread的join方法,等待主线程结束
Future机制
FutureTask
package com.alibaba.fescar.core.protocol.test;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class TestFuture {
public static void main(String[] args) {
FutureTask<Integer> futureTask = new FutureTask<Integer>(()-> {
System.out.println("当前线程执行");
return 1;
});
new Thread(futureTask).start();
try {
// 阻塞获取值
Integer integer = futureTask.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("主线程执行");
}
}
执行结果
Future
package com.alibaba.fescar.core.protocol.test;
import java.util.concurrent.*;
public class TestFuture {
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(1);
Future<Integer> task = pool.submit(() -> {
System.out.println("当前线程执行");
return 1;
});
try {
// 阻塞获取结果
Integer integer= task.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("主线程执行");
}
}
执行结果
结果分析:这里借用线程池提交任务,程序没有退出,是因为线程池没有shutdown,熟悉下线程池的submit方法
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
如上所示,线程池接受Callable 和Runnable任务,返回Future接口的上转型对象,和FutureTask同理,
有关于Runnable、Future、Callable、FutureTask 请参考文章:
Runnable、Future、Callable、FutureTask
CountDownLatch
package com.alibaba.fescar.core.protocol.test;
import java.util.concurrent.CountDownLatch;
public class TestCountDown {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
new Thread(() -> {
System.out.println("当前线程结束");
latch.countDown();
}).start();
latch.await();
System.out.println("主线程结束");
}
}
执行结果
latch.dountDown()调用,计数器会减一,latch.await()会阻塞主线程直到0放行
CompletableFuture
package com.alibaba.fescar.core.protocol.test;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class TestCompletableFuture {
public static void main(String[] args) throws ExecutionException, InterruptedException {
/**
* supplyAsync与runAsync的区别在于:supplyAsync有返回值,而runAsync没有返回值
*/
CompletableFuture<Integer> current1 = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程1执行");
return 3;
});
/**
* 合并两个任务,两个任务可以同时执行,都执行成功后,执行最后的BiFunction操作。
*/
CompletableFuture<Integer> current2 = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程2执行");
return 2;
}).thenCombine(current1,(res1,res2)->res1 * res2);
System.out.println(current2.get());
System.out.println("主线程执行");
}
}
执行结果
CompletableFuture实现了Future接口,当其get的时候同样阻塞主线程执行, CompletableFuture在于可以多任务串行,以及并行执行,操作空间更广
具体用法请参考文章:CompletableFuture用法
线程池的isTerminated方法
package com.alibaba.fescar.core.protocol.test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestThreadPool{
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(3);
pool.execute(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
pool.execute(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
pool.shutdown();
while (true) {
if (pool.isTerminated()) {
System.out.println("线程池中的任务执行结束");
break;
}
}
System.out.println("主线程结束");
}
}
执行结果
isTerminated,当调用shutdown()方法后,并且所有提交的任务完成后才会返回为true
Thread的join方法
package com.alibaba.fescar.core.protocol.test;
public class TestThreadJoin {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
try {
System.out.println("t1执行");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t1.start();
Thread t2 = new Thread(() -> {
try {
System.out.println("t2执行");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t2.start();
t1.join();
t2.join();
System.out.println("主线程结束");
}
}
执行结果
Thread中的join方法,用于等待本线程结束,同时阻塞其他线程,也叫插队线程,yeild线程礼让,让出执行权,wait 线程等待,释放锁, sleep线程休眠 不会释放锁