Runnable主要有两个缺陷:
不能返回一个返回值 不能抛出异常
这两点Callable都能做到;
Future和Callable配合使用:可以用Future.get来获取Callable接口返回的执行结果,还可以通过Future.isDone()来判断任务是否已完成以及取消这个任务,限时获取任务的结果
在call()未执行完毕之前,调用get()的线程(假定此时是主线程)会被阻塞,直到call()方法返回了结果后,此时future.get()才会得到该结果,然后主线程才会切换到runnable状态
所以Future是一个存储器,它存储了call()这个任务的结果,而这个任务的执行时间是无法提前确定的,因为这完全取决于call()方法执行的情况
get()方法:获取结果,future一旦调用get方法,就会阻塞,直到返回结果
get方法的行为取决于Callable任务的状态,只有以下这5种情况:
示例1:get的基本用法 Onefuture.java
package future; import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; /** * 描述: 演示一个Future的使用方法 */ public class OneFuture { public static void main(String[] args) { ExecutorService service = Executors.newFixedThreadPool(10); Future<Integer> future = service.submit(new CallableTask()); try { System.out.println(future.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } service.shutdown(); } static class CallableTask implements Callable<Integer> { @Override public Integer call() throws Exception { Thread.sleep(3000); return new Random().nextInt(); } } }运行结果
示例2: Future用法的lamda形式
package future; import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; /** * 描述: 演示一个Future的使用方法,lambda形式 */ package future; import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; /** * 描述: 演示一个Future的使用方法,lambda形式 */ public class OneFutureLambda { public static void main(String[] args) { ExecutorService service = Executors.newFixedThreadPool(10); Callable<Integer> callable = ()->{ Thread.sleep(3000); return new Random().nextInt(); }; Future<Integer> future = service.submit(callable); try { System.out.println(future.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } service.shutdown(); } }运行结果
示例3: 多个任务,用future的数组获取结果
package future; import java.util.ArrayList; import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; /** * 描述: 演示批量提交任务时,用List来批量接收结果 */ public class MultiFutures { public static void main(String[] args) throws InterruptedException { ExecutorService service = Executors.newFixedThreadPool(20); ArrayList<Future> futures = new ArrayList<>(); for (int i = 0; i < 20; i++) { Future<Integer> future = service.submit(new CallableTask()); futures.add(future); } Thread.sleep(5000); for (int i = 0; i < 20; i++) { Future<Integer> future = futures.get(i); try { Integer integer = future.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(); } } }运行结果
示例4:抛出异常
package future; import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; /** * 描述: 演示get方法过程中抛出异常,for循环为了演示抛出Exception的时机:并不是说一产生异常就抛出,直到我们get执行时,才会抛出。 */ public class GetException { public static void main(String[] args) { ExecutorService service = Executors.newFixedThreadPool(20); Future<Integer> future = service.submit(new CallableTask()); try { for (int i = 0; i < 5; i++) { System.out.println(i); Thread.sleep(500); } System.out.println(future.isDone()); future.get(); } catch (InterruptedException e) { e.printStackTrace(); System.out.println("InterruptedException异常"); } catch (ExecutionException e) { e.printStackTrace(); System.out.println("ExecutionException异常"); } } static class CallableTask implements Callable<Integer> { @Override public Integer call() throws Exception { throw new IllegalArgumentException("Callable抛出异常"); } } }运行结果
示例5 超时获取
package future; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; /** * 描述: 演示get的超时方法,需要注意超时后处理,调用future.cancel()。演示cancel传入true和false的区别,代表是否中断正在执行的任务。 */ public class Timeout { private static final Ad DEFAULT_AD = new Ad("无网络时候的默认广告"); private static final ExecutorService exec = Executors.newFixedThreadPool(10); static class Ad { String name; public Ad(String name) { this.name = name; } @Override public String toString() { return "Ad{" + "name='" + name + '\'' + '}'; } } static class FetchAdTask implements Callable<Ad> { @Override public Ad call() throws Exception { try { Thread.sleep(3000); } catch (InterruptedException e) { System.out.println("sleep期间被中断了"); return new Ad("被中断时候的默认广告"); } return new Ad("旅游订票哪家强?找某程"); } } public void printAd() { Future<Ad> f = exec.submit(new FetchAdTask()); Ad ad; try { ad = f.get(2000, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { ad = new Ad("被中断时候的默认广告"); } catch (ExecutionException e) { ad = new Ad("异常时候的默认广告"); } catch (TimeoutException e) { ad = new Ad("超时时候的默认广告"); System.out.println("超时,未获取到广告"); boolean cancel = f.cancel(true); System.out.println("cancel的结果:" + cancel); } exec.shutdown(); System.out.println(ad); } public static void main(String[] args) { Timeout timeout = new Timeout(); timeout.printAd(); } }运行结果1:当cancel参数为false
运行结果2: 当cancel参数为true
可以用FutureTask获得future和任务的结果
package future; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; /** * 描述: 演示FutureTask的用法 */ public class FutureTaskDemo { public static void main(String[] args) { Task task = new Task(); FutureTask<Integer> integerFutureTask = new FutureTask<>(task); // new Thread(integerFutureTask).start(); ExecutorService service = Executors.newCachedThreadPool(); service.submit(integerFutureTask); try { System.out.println("task运行结果:"+integerFutureTask.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } } class Task implements Callable<Integer> { @Override public Integer call() throws Exception { System.out.println("子线程正在计算"); Thread.sleep(3000); int sum = 0; for (int i = 0; i < 100; i++) { sum += i; } return sum; } }