Future接口:做用为获取Callable接口的返回值java
FutureTask类为Future接口子类,该类独有的特色为在高并发状况下不论有多少个线程,均只执行一次任务。web
get()方法的做用为阻塞当前线程直到有返回值为止。安全
使用Future接口中get()方法的两种状况:并发
(1)提交线程的同时调用get()方法ide
class CallableTest implements Callable<String>{ private static Integer ticket=10; @Override public String call() throws Exception { while (ticket>0){ System.out.println(Thread.currentThread().getName()+"还剩"+ticket--+"张票"); } return "票已经卖完啦"; } } public class ThreadTest{ public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService service=Executors.newCachedThreadPool(); Callable<String> callable=new CallableTest(); for(int i=0;i<5;i++){ String str=service.submit(callable).get(); System.out.println(str); } service.shutdown(); } } /** pool-1-thread-1还剩10张票 pool-1-thread-1还剩9张票 pool-1-thread-1还剩8张票 pool-1-thread-1还剩7张票 pool-1-thread-1还剩6张票 pool-1-thread-1还剩5张票 pool-1-thread-1还剩4张票 pool-1-thread-1还剩3张票 pool-1-thread-1还剩2张票 pool-1-thread-1还剩1张票 票已经卖完啦 票已经卖完啦 票已经卖完啦 票已经卖完啦 票已经卖完啦 **/ //使用FutureTask类实现 class CallableTest implements Callable<String>{ private static Integer ticket=10; @Override public String call() throws Exception { while (ticket>0){ System.out.println(Thread.currentThread().getName()+"还剩"+ticket--+"张票"); } return "票已经卖完啦"; } } public class ThreadTest{ public static void main(String[] args) throws ExecutionException, InterruptedException { FutureTask<String> futureTask=new FutureTask<>(new CallableTest()); for(int i=0;i<5;i++){ new Thread(futureTask).start(); } } } /** Thread-1还剩10张票 Thread-1还剩9张票 Thread-1还剩8张票 Thread-1还剩7张票 Thread-1还剩6张票 Thread-1还剩5张票 Thread-1还剩4张票 Thread-1还剩3张票 Thread-1还剩2张票 Thread-1还剩1张票 */
由以上代码咱们能够看到,get()方法阻塞了主线程,线程1得到锁后执行完任务并返回返回值,其余线程不执行任务只返回返回值。svg
(2)提交线程以后调用get()方法高并发
class CallableTest implements Callable<String>{ private static Integer ticket=10; @Override public String call() throws Exception { while (ticket>0){ System.out.println(Thread.currentThread().getName()+"还剩"+ticket--+"张票"); } return "票已经卖完啦"; } } public class ThreadTest{ public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService service=Executors.newCachedThreadPool(); Callable<String> callable=new CallableTest(); Future<String> future=null; for(int i=0;i<5;i++){ future=service.submit(callable); } String str=future.get();//阻塞主线程,高并发执行任务,不安全 System.out.println(str); service.shutdown(); } } /** pool-1-thread-1还剩10张票 pool-1-thread-2还剩9张票 pool-1-thread-1还剩8张票 pool-1-thread-2还剩7张票 pool-1-thread-3还剩5张票 pool-1-thread-1还剩6张票 pool-1-thread-3还剩3张票 pool-1-thread-2还剩4张票 pool-1-thread-3还剩1张票 pool-1-thread-1还剩2张票 票已经卖完啦 **/
注意:支持处理Callable对象的两种方法
(1)FutureTask:高并发状况下线程任务只执行一次
(2)线程池的submit()方法可向线程池中提交Callable对象this
解题思路:spa
经过流程图的分析咱们不难看出,烧水与洗茶壶、洗茶杯、拿茶叶是能够并行的,两线程在泡茶处有交集。咱们能够将横行看做线程1,竖行看做线程2,所以线程1必须等待线程2执行完毕后才可执行泡茶操做(泡茶必须在拿到茶叶以后),故需在线程1中调用线程2的get方法对线程1进行阻塞,直到线程2完成任务后方可泡茶。线程
实现源代码:
//执行线程1任务 class Task1 implements Callable<String>{ private FutureTask<String> futureTask; public Task1(FutureTask<String> futureTask) {//经过构造方法将线程2传入 this.futureTask = futureTask; } @Override public String call() throws Exception { System.out.println("T1:洗水壶..."); TimeUnit.SECONDS.sleep(1); System.out.println("T1:烧开水..."); TimeUnit.SECONDS.sleep(15); String str=futureTask.get();//调用线程2的get()方法用于阻塞当前线程直到线程2任务结束 System.out.println("T1:泡茶"); return "上茶"; } } //执行线程2任务 class Task2 implements Callable<String>{ @Override public 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 "上好龙井"; } } public class ThreadTest{ public static void main(String[] args) throws ExecutionException, InterruptedException { FutureTask<String> ft2=new FutureTask<>(new Task2()); FutureTask<String> ft1=new FutureTask<>(new Task1(ft2)); new Thread(ft1).start(); new Thread(ft2).start(); System.out.println(ft1.get());//用于阻塞主线程 } } /** T1:洗水壶... T2:洗茶壶 T1:烧开水... T2:洗茶杯 T2:拿茶叶 T1:泡茶 上茶 **/