本文共 4261 字,大约阅读时间需要 14 分钟。
线程池之Future接口
1. Future
Future接口中的get()
会阻塞当前线程直到取得Callable
的返回值
API文档
要想讲的清楚多线程,怎么能少得了我们的12306呢?今天,又是卖火车票的一天…FutureTask 类是实现 Future ,实现 Runnable ,所以可以由 Executor 执行
FutureTask 可用于包装 Callable 或 Runnable 对象. 因为 FutureTask 实现 Runnable ,一个FutureTask可以提交到一个Executor执行
package com.ThreadPool;import java.util.concurrent.*;/** * @Author: Mr.Q * @Date: 2019-08-05 09:02 * @Description: */class CallableThread implements Callable{ private Integer tickets = 30; @Override public String call() throws Exception { for (int i = 0; i < tickets; i++) { if(tickets > 0) { System.out.println(Thread.currentThread().getName() +"还剩 "+tickets--+" 票..."); } } return Thread.currentThread().getName() + "票卖完了!"; }}public class FutureTest { public static void main(String[] args) throws ExecutionException, InterruptedException { // 线程池创建线程 ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2,5, 60,TimeUnit.SECONDS, new LinkedBlockingDeque ()); CallableThread callableThread = new CallableThread(); // Future接口接收 Callable的返回值 Future future = null; for (int i = 0; i < 5; i++) { // submit()提交需要返回值的任务 future = threadPoolExecutor.submit(callableThread); } //----------------- main - --------------- System.out.println(future.get()); threadPoolExecutor.shutdown(); }}
get()
会阻塞当前线程直到取得Callable
的返回值
此时,在main()
中调用get()
,导致当前线程(主线程)阻塞,直到线程池中的子线程执行完毕后,在执行!
Futurefuture = null; // 单线程模式 get()会阻塞当前线程,直到有返回值为止 for (int i = 0; i < 5; i++) { Future future0 = threadPoolExecutor.submit(callableThread); System.out.println(future0.get()); }
那么此时阻塞当前提交任务的线程,也就是说,它没有提交完任务,其他的线程都不能执行,都得等着. 表面上看我们在最大池中创建了5个线程,可实际上执行任务的只有一个,其他的都在阻塞. 此时为 单线程模式
2. FutureTask
FutureTask : 可以保证在多线程场景下,任务只会被一个线程执行,其他线程不再执行此任务;
在多线程并发下可以保证任务(传入的Callable
或 Runnable
)只执行一次 什么意思呢? 就是我现在要给在火车站柜台买票的每一个人,买一张票,我就请他去候车室喝咖啡(虽然这是不可能的)
如果,我让一个乘务员来做这件事(把乘务员抽象的看作是一个线程),他先得乘客卖票,然后再给乘客到候车室冲咖啡递上去,是不是很麻烦,效率很低?这要是到春运了,估计回家了,也就开学了…
那我再雇一个乘务员,一个负责卖票,另一个负责在候车室服务乘客,效率高,分工明确.
那么此时再看我们FutureTask
的作用
可以保证在多线程场景下,任务只会被一个线程执行,其他线程不再执行此任务
相当于负责售票的乘务员A不管服务乘客,负责服务乘客的乘务员B不管卖票;
而开始的时候,这两件事情都由乘务员C来负责,两个任务都得执行.
这就是FutureTask
的应用场景
那我们就用FutureTask
来实现一下泡茶的场景吧
import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.FutureTask;import java.util.concurrent.TimeUnit;/** * @Author: Mr.Q * @Date: 2019-08-07 09:17 * @Description: */// 线程1任务class StepOne implements Callable{ private FutureTask futureTask; public StepOne(FutureTask futureTask) { this.futureTask = futureTask; } @Override public String call() throws Exception { System.out.println("T1:洗水壶."); TimeUnit.SECONDS.sleep(1); System.out.println("T1:烧开水.."); TimeUnit.SECONDS.sleep(10); System.out.println("T1:等待茶叶..."); // 线程1阻塞到此处一直等到线程2返回为止 String str = futureTask.get(); System.out.println("T1:拿到茶叶...."); System.out.println("泡茶"); return "上茶~~~"; }}// 线程2任务class StepTwo implements Callable { @Override public String call() throws Exception { System.out.println("T2:洗茶壶*"); TimeUnit.SECONDS.sleep(1); System.out.println("T2:洗茶杯**"); TimeUnit.SECONDS.sleep(1); System.out.println("T2:拿茶叶***"); TimeUnit.SECONDS.sleep(3); return "龙井"; }}public class FutureThreadPoolDemo { public static void main(String[] args) throws ExecutionException, InterruptedException { FutureTask step2 = new FutureTask(new StepTwo()); //将线程2的龙井茶传给线程1 FutureTask step1 = new FutureTask(new StepOne(step2)); new Thread(step1).start(); new Thread(step2).start(); // 主线程在step1,step2执行完之后再执行 System.out.println(step1.get()); }}
执行过程:
好了,今天的养生课到这里就结束了,下课吧同学们…转载地址:https://iqqcode.blog.csdn.net/article/details/99226671 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!