除了线程池可以治理线程外,Future和Callable也可以治理线程。
Runnable缺陷
Runnable的run无返回值
不能抛出Checked Exception
我们通过下面实例去演示。
我们思考下为什么没有返回值呢?一般调用Runnable的类为Thread,Thread是JDK提供,我们无法做处理。
Callable接口提供了返回值。
Callable接口
Callable接口是可以有返回值和异常的,如下源码所示:
Feature类
Future可搭配Callable来使用。Feature是一个存储器
Future与Callable关系
我们可以通过Future的get方法来获取Callable接口执行的返回值;
我们可以通过Feature的isDone方法来判断Callable是否已经执行结束了,也可以取消这个任务。
call未执行完之前,用Feature的get时会阻塞,直到有返回结果
Future主要方法
主要方法如下:
1.get 任务执行完成了,则直接返回;任务未完成,get方法会进行阻塞直到任务完成;任务执行过程中抛出了异常时,get方法也会抛出异常,get只抛出ExecutionException;
任务取消时,get抛出CancellationException异常;任务超时时,抛出TimeoutException
2.get(long timeout,TimeUnit unit) 有超时的获取,参照上方法
3.cancel 取消任务执行;取消策略需要关注
4.isDone 判断线程是否执行完毕,执行完毕不代表成功执行。
5.isCancelled 是否取消
Future基本用法实例
我们给线程池提供一个任务,获取对应Future,见如下代码所示:
package com.yang.callable; import java.util.Random; import java.util.concurrent.*; public class OneFutureDemo { public static void main(String[] args) { ExecutorService executorService= Executors.newFixedThreadPool(10); Future<Integer> future = executorService.submit(new CallableTask<Integer>()); try { System.out.println(future.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } executorService.shutdown(); } static class CallableTask<I extends Number> implements Callable<Integer>{ @Override public Integer call() throws Exception { Thread.sleep(1000); return new Random().nextInt(); } } }
运行结果如下所示:
FutureLamda实例
我们使用Lamda来实现,请看下代码:
package com.yang.callable; import java.util.Random; import java.util.concurrent.*; public class FutureLamdaDemo { public static void main(String[] args) { ExecutorService executorService= Executors.newFixedThreadPool(10); Callable<Integer> callable=()->{ Thread.sleep(3000); return new Random().nextInt(); }; Future<Integer> future = executorService.submit(callable); try { System.out.println(future.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } executorService.shutdown(); } }
Future批量接收实例代码
Future批量接收Callable,实例代码如下所示:
package com.yang.callable; import java.util.ArrayList; import java.util.Random; import java.util.concurrent.*; public class MultiFutureDemo { public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(2); ArrayList<Future<Integer>> futureArrayList = new ArrayList<Future<Integer>>(); for (int i = 0; i < 10; i++) { futureArrayList.add(executorService.submit(new CallableTask())); } for (int i = 0; i < 10; i++) { try { Integer integer = futureArrayList.get(i).get(); System.out.println(integer); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } } static class CallableTask implements Callable<Integer>{ @Override public Integer call() throws Exception { Thread.sleep(3000); return new Random().nextInt(); } } }
运行结果如下所示:
Future在执行过程中抛出了异常实例
本实例演示get方法抛出了异常,实例代码如下所示:
package com.yang.callable; import java.util.concurrent.*; public class GetExecption { public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(2); Future<Integer> future=executorService.submit(new CallableTask()); try{ future.get(); }catch (IllegalArgumentException e){ System.out.println("线程内部抛出异常"); }catch (ExecutionException e){ System.out.println("执行过程中抛出异常"); } catch (InterruptedException e) { e.printStackTrace(); System.out.println("中断异常"); } } static class CallableTask implements Callable<Integer>{ @Override public Integer call() throws Exception { throw new IllegalArgumentException("不合法的参数异常"); } } }
执行结果如下:
Future的isDone实例
isDone演示如下所示:
package com.yang.callable; import java.util.concurrent.*; public class GetExecption { public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(2); Future<Integer> future=executorService.submit(new CallableTask()); try{ future.get(); }catch (IllegalArgumentException e){ System.out.println("线程内部抛出异常"); }catch (ExecutionException e){ System.out.println("执行过程中抛出异常"); } catch (InterruptedException e) { e.printStackTrace(); System.out.println("中断异常"); } System.out.println(future.isDone()); } static class CallableTask implements Callable<Integer>{ @Override public Integer call() throws Exception { throw new IllegalArgumentException("不合法的参数异常"); } } }
运行结果
Future获取任务超时实例
本实例演示get的超时方法,当超时后,我们取消这个任务。我们同事演示下cancel方法传入true或者false
package com.yang.callable; import java.util.Calendar; import java.util.concurrent.*; /** * 本实例演示Future超时 */ public class TimeoutFutureDemo { private static String defaultAdStr = "我是默认的"; public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(2); Future<String> future = executorService.submit(new FutureTask()); try { String s = future.get(2000, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { System.out.println("中断了"); } catch (ExecutionException e) { System.out.println("执行异常"); } catch (TimeoutException e) { System.out.println("超时了"); //控制是否要中断,true:允许中断 boolean cancelStatus = future.cancel(true); System.out.println(cancelStatus); } } static class FutureTask implements Callable<String> { @Override public String call() throws Exception { try { Thread.sleep(3000); } catch (InterruptedException e) { System.out.println("中断了,返回默认的"); return defaultAdStr; } return "外部获取的消息"; } } }
运行结果如下所示:
Cancel方法的总结
1.cancel方法支持传入true和false
2.当传入true时,需要考虑当前线程是否支持中断,中断后的业务逻辑是否正确
3.任务都已经开始,我们是否需要其执行完毕,需要则用false