java创建线程总共有三种方式:
1.继承Thread类
2.实现runnable接口
3.实现Callable接口
他们三者的区别是Callable可以返回结果值,而前俩者无法返回结果值。假若我们的主线程需要子线程去执行异步操作获取数据作为某个函数的输入,我们可以使用Callable方式创建线程。
Callable方式创建线程:
//实现Callable接口
public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
Thread.sleep(1000);
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
return "结果";
}
}
//创建线程池
ExecutorService service = Executors.newCachedThreadPool();
Future<String> future = service.submit(new MyCallable());
try {
//获取结果
String result = future.get();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
Callable一般配合线程池使用,通过调用线程池的submit()方法返回Future对象,结果就是封装在Future对象中,而我们通过调用
future.get()
方法来获取我们的结果。get()
方法调用会引起主线程的阻塞(假如说子线程还未获取到结果返回,调用get()方法会引起主线程阻塞,直到子线程返回结果主线程才会往下执行),若子线程操作很耗时,主线程一直阻塞着,这显然违反了我们异步的原则。我希望这段时间主线程先去做别的操作,等子线程返回结果后再通知主线程,解决办法:
1.轮询:先让主线程执行其他操作,定时的调用future.isDone()
判断子线程是否操作完成。完成后再切回来执行。(这种方式不建议使用)
2.使用CompletableFuture
CompletableFuture介绍:
CompletableFuture是JDK1.8引入的,实现了Future, CompletionStage两个接口。
实际开发中,我们常常面对如下的几种场景:
1.针对Future的完成事件,不想简单的阻塞等待,在这段时间内,我们希望可以正常继续往下执行,所以在它完成时,我们可以收到回调即可。2.面对Future集合来讲,这其中的每个Future结果其实很难去描述它们之间的依赖关系,而往往我们希望等待所有的Future集合都完成,然后做一些事情。
3. 在异步计算中,两个计算任务相互独立,但是任务二又依赖于任务一的结果。
CompletableFuture的出现很好了解决这些问题
CompletableFuture基本使用:
public class MyCallable {
//静态方法
public static CompletableFuture<String> getMessage() {
//创建CompletableFuture对象
final CompletableFuture<String> completableFuture = new CompletableFuture