第二部分:并发工具类23->多线程实现最优烧水泡茶
1.如何使用线程池
ThreadPoolExecutor是否提供了获取任务执行结果的功能呢
2.如何获取任务执行结果
3个sumit方法+1个futureTask工具类
Future<?> submit(Runnable task);
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task,T result);
1.sumit方法的参数是Runnable接口,run方法是没有返回值,所以submit方法的返回future只可以用来判断是否已经结束,类似thread.join()
2.submit方法的参数是Callable接口,它只有一个call方法,并且这个方法是有返回值,方法返回的future对象可以通过调用其get方法获取任务执行结果
3.submit方法的参数是Runnable接口+泛型result,f.get()返回值就是传给submit()方法的参数result。Runnable接口的实现类要有有参Result的构造函数,run函数中修改result对象
future接口,有5个方法,
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
get();
get(long timeout,TimeUnit unit);
3.FutureTask工具类
FutureTask是工具类,Future是接口
FutureTask是对Runnable或者Callable接口的实现类进行的再次封装,可以直接使用获取返回结果
两个构造函数
FutureTask(Callable<V> callable);
FutureTask(Runnable runnable,V result);
范例
FutureTask<Integer> futureTask = new FutureTask<>( () -> 1 + 2);
ExecutorService es = Executors.newCachedThreadPool();
es.submit(futureTask);
Integer result = futureTask.get();
4.两个线程协作
线程T1等待T2执行完,再执行T1 的其余动作
// 创建任务T2的FutureTask
FutureTask<String> ft2
= new FutureTask<>(new T2Task());
// 创建任务T1的FutureTask
FutureTask<String> ft1
= new FutureTask<>(new T1Task(ft2));
// 线程T1执行任务ft1
Thread T1 = new Thread(ft1);
T1.start();
// 线程T2执行任务ft2
Thread T2 = new Thread(ft2);
T2.start();
// 等待线程T1执行结果
System.out.println(ft1.get());
// T1Task需要执行的任务:
// 洗水壶、烧开水、泡茶
class T1Task implements Callable<String>{
FutureTask<String> ft2;
// T1任务需要T2任务的FutureTask
T1Task(FutureTask<String> ft2){
this.ft2 = ft2;
}
@Override
String call() throws Exception {
System.out.println("T1:洗水壶...");
TimeUnit.SECONDS.sleep(1);
System.out.println("T1:烧开水...");
TimeUnit.SECONDS.sleep(15);
// 获取T2线程的茶叶
String tf = ft2.get();
System.out.println("T1:拿到茶叶:"+tf);
System.out.println("T1:泡茶...");
return "上茶:" + tf;
}
}
// T2Task需要执行的任务:
// 洗茶壶、洗茶杯、拿茶叶
class T2Task implements Callable<String> {
@Override
String call() throws Exception {
System.out.println("T2:洗茶壶...");
TimeUnit.SECONDS.sleep(1);
System.out.println("T2:洗茶杯...");
TimeUnit.SECONDS.sleep(2);
System.out.println("T2:拿茶叶...");
TimeUnit.SECONDS.sleep(1);
return "龙井";
}
}
// 一次执行结果:
T1:洗水壶...
T2:洗茶壶...
T1:烧开水...
T2:洗茶杯...
T2:拿茶叶...
T1:拿到茶叶:龙井
T1:泡茶...
上茶:龙井
5.总结
future类比现实世界的提货单,拿到提货单后,没必要在店里一直待着,可以去干别的事
多线程可以将串行任务并行化,提高性能。任务之间有依赖关系,当前任务依赖前一个任务的执行结果,可以用future来解决。
原创:做时间的朋友