线程
线程分为
- 用户线程
- 守护线程
用户线程:系统工作线程,他会完成这个程序需要完成的业务操作。
守护线程:是一种特殊的线程为其它线程服务的,在后台默默地完成一些系统性地服务,比如垃圾回收线程
作为一个服务线程,没有服务对象就没有必要继续运行了,如果用户线程全部结束了,意味着程序需要完成地业务操作已经结束了,系统可以退出。所以加入当系统只剩下守护线程地时候,Java虚拟机会自动退出。
CompletableFuture
Future
Feture接口(FutureTask实现类)定义了操作异步任务执行一些方法,如获取异步任务地执行结果,取消任务地执行、判断任务是否被取消、判断任务执行是否完毕等。
Future接口可以为主线程开一个分支任务,专门为主线程处理好费事和费力地复杂业务。
特点:多线程/异步/有返回值
Runnable接口不满足返回值
RunnableFuture接口不满足有返回值
FutureTask
实现RunnableFuture,构造方法中支持callable注入
缺点
get方法会阻塞线程
1、容易导致阻塞,一般加以放在程序后面,一旦调用不见不散,非要等到结果才hi离开,不管你是否计算完成,容易程序阻塞
2、假如我不愿意等待很长时间,我希望过时不侯,可以自行离开。
public class FutureTaskGet {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<String> futureTask = new FutureTask<>(() -> {
System.out.println(Thread.currentThread().getName() + "\t---come in");
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "task over";
});
Thread t1 = new Thread(futureTask, "t1");
t1.start();
System.out.println(futureTask.get());
System.out.println(Thread.currentThread().getName()+"\t----end");
}
}
completableFuture
CompletableFuture实现CompletionStage/Future接口
- CompletionStage代表异步计算过程中地某一个阶段,一个阶段完成以后可能会出发另外一个阶段
- 一个阶段地计算执行可以是一个Function,Consumer或者Runnable。比如:stage.thenApply(x->square(x)).thenAccept(x->System.out.print(x)).thenRun()->System.out.println())
- 一个阶段地执行可能是被单个阶段地完成出发,也可能是由多个阶段一起触发
代表异步计算过程中的某一个阶段,一个阶段完成以后可能触发另外一个阶段,类似Linux系统地管道分隔符传参数
解决了get线程阻塞问题
当主线程停止时,CompletableFuture默认使用地线程池会立刻关闭,自己创建一个线程池
ExecutorService threadPool = Executors.newFixedThreadPool(3);
CompletableFuture<Integer> supplyAsync = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName());
int result = ThreadLocalRandom.current().nextInt(10);
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
return result;
},threadPool).whenComplete((v,e)->{
if (e == null){
System.out.println("--------计算完成,更新系统UpdateVa:"+v);
}
}).exceptionally(e->{
e.printStackTrace();
System.out.println("异常情况"+e.getCause()+"\t"+e.getMessage());
return null;
});
System.out.println(Thread.currentThread().getName()+"线程先去忙其他任务");
threadPool.shutdown();
join和get地区别
join不用抛异常,get需要
优点
- 异步任务结束时,会自动回调某个对象地方法;
- 主线程设置好回调后,不再关心异步任务地执行,异步任务之间可以顺序执行
- 异步任务出错时,会自动回调某个对象地方法;
api
1.获得结果和触发计算
当没有运行完时,返回传入的值,
getNot(...):并不终止异步运行,返回传入参数
complete(...)终止异步运行,直接复制返回Boolean类型
2.对计算结果进行处理
计算结果串行化
thenApply:出现异常都不执行
handle:出现异常,异常地方不执行,其他地方继续执行
3.对计算结果进行消费
接受任务的处理结果,并消费无返回值
thenAccept(....)
thenRun(new Running)开启新的线程void
4.对计算速度进行选用
applyToEneither()谁快用谁
5.对计算结果进行合并
thenCombine