第二部分:并发工具类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来解决。

posted @ 2021-07-08 17:02  SpecialSpeculator  阅读(61)  评论(0编辑  收藏  举报