Java 线程池Future和FutureTask
Future表示一个任务的周期,并提供了相应的方法来判断是否已经完成或者取消,以及获取任务的结果和取消任务。
Future接口源码:
public interface Future<V> { boolean cancel(boolean mayInterruptIfRunning); boolean isCancelled(); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }
Future的demo
import java.util.ArrayList; import java.util.List; 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; public class Main { public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); List<Future<String>> resultList = new ArrayList<Future<String>>(); // 创建10个任务并执行 for (int i = 0; i < 10; i++) { // 使用ExecutorService执行Callable类型的任务,并将结果保存在future变量中 Future<String> future = executorService.submit(new TaskWithResult(i)); // 将任务执行结果存储到List中 resultList.add(future); } executorService.shutdown(); // 遍历任务的结果 for (Future<String> fs : resultList) { try { System.out.println(fs.get()); // 打印各个线程(任务)执行的结果 } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { executorService.shutdownNow(); e.printStackTrace(); return; } } } } class TaskWithResult implements Callable<String> { private int id; public TaskWithResult(int id) { this.id = id; } /** * 任务的具体过程,一旦任务传给ExecutorService的submit方法,则该方法自动在一个线程上执行。 * * @return * @throws Exception */ public String call() throws Exception { System.out.println("call()方法被自动调用,干活!!! " + Thread.currentThread().getName()); if (new Random().nextBoolean()) throw new TaskException("Meet error in task." + Thread.currentThread().getName()); // 一个模拟耗时的操作 for (int i = 999999999; i > 0; i--) ; return "call()方法被自动调用,任务的结果是:" + id + " " + Thread.currentThread().getName(); } } class TaskException extends Exception { public TaskException(String message) { super(message); } }
call()方法被自动调用,干活!!! pool-1-thread-2 call()方法被自动调用,干活!!! pool-1-thread-6 call()方法被自动调用,干活!!! pool-1-thread-1 call()方法被自动调用,任务的结果是:0 pool-1-thread-1 call()方法被自动调用,任务的结果是:1 pool-1-thread-2 call()方法被自动调用,干活!!! pool-1-thread-4 call()方法被自动调用,干活!!! pool-1-thread-9 call()方法被自动调用,干活!!! pool-1-thread-8 call()方法被自动调用,干活!!! pool-1-thread-10 call()方法被自动调用,干活!!! pool-1-thread-5 call()方法被自动调用,干活!!! pool-1-thread-3 call()方法被自动调用,干活!!! pool-1-thread-7 call()方法被自动调用,任务的结果是:2 pool-1-thread-3 call()方法被自动调用,任务的结果是:3 pool-1-thread-4 java.util.concurrent.ExecutionException: com.company.TaskException: Meet error in task.pool-1-thread-5 at java.util.concurrent.FutureTask.report(FutureTask.java:122) at java.util.concurrent.FutureTask.get(FutureTask.java:192) at com.company.Main.main(Main.java:29) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144) Caused by: com.company.TaskException: Meet error in task.pool-1-thread-5 at com.company.TaskWithResult.call(Main.java:56) at com.company.TaskWithResult.call(Main.java:40) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745)
FutureTask是一个具体的实现类,ThreadPoolExecutor的submit方法返回的就是一个Future的实现,这个实现就是FutureTask的一个具体实例,FutureTask帮助实现了具体的任务执行,以及和Future接口中的get方法的关联。
Demo:
import java.util.Date; import java.text.SimpleDateFormat; import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class Main { public static void main(String[] args) { SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 初始化一个Callable对象和FutureTask对象 Callable pAccount = new PrivateAccount(); FutureTask futureTask = new FutureTask(pAccount); // 使用futureTask创建一个线程 Thread pAccountThread = new Thread(futureTask); System.out.println("futureTask线程现在开始启动,启动时间为:" + df.format(new Date())); pAccountThread.start(); System.out.println("futureTask线程开始执行其他任务"); // 从其他账户获取总金额 int totalMoney = new Random().nextInt(100000); System.out.println("现在你在其他账户中的总金额为" + totalMoney); System.out.println("等待私有账户总金额统计完毕..."); // 测试后台的计算线程是否完成,如果未完成则等待 while (!futureTask.isDone()) { try { Thread.sleep(500); System.out.println("私有账户计算未完成继续等待..."); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("futureTask线程计算完毕,此时时间为" + df.format(new Date())); Integer privateAccountMoney = null; try { privateAccountMoney = (Integer) futureTask.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } System.out.println("您现在的总金额为:" + totalMoney +"||"+privateAccountMoney.intValue()); } } class PrivateAccount implements Callable { Integer totalMoney; @Override public Object call() throws Exception { Thread.sleep(5000); totalMoney = new Integer(new Random().nextInt(10000)); System.out.println("您当前有" + totalMoney + "在您的私有账户中"); return totalMoney; } }
futureTask线程现在开始启动,启动时间为:2016-11-30 16:34:57 futureTask线程开始执行其他任务 现在你在其他账户中的总金额为17113 等待私有账户总金额统计完毕... 私有账户计算未完成继续等待... 私有账户计算未完成继续等待... 私有账户计算未完成继续等待... 私有账户计算未完成继续等待... 私有账户计算未完成继续等待... 私有账户计算未完成继续等待... 私有账户计算未完成继续等待... 私有账户计算未完成继续等待... 私有账户计算未完成继续等待... 您当前有8776在您的私有账户中 私有账户计算未完成继续等待... futureTask线程计算完毕,此时时间为2016-11-30 16:35:02 您现在的总金额为:17113||8776
Demo2:
import java.util.Date; import java.text.SimpleDateFormat; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class Main { public static void main(String[] args) { SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); FutureTask<String> futureTask=new FutureTask<>(new Callable<String>() { //@Override public String call() throws Exception { // TODO Auto-generated method stub return "回调完成"; } }); Thread thread = new Thread(futureTask); System.out.println("启动时间为:" + df.format(new Date())); thread.start(); try { String str=futureTask.get(); if(str.equals("回调完成")) System.out.println("异步任务完成!"); else System.out.println("Completed!"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
启动时间为:2016-12-01 09:37:03
异步任务完成!
http://ifeve.com/futuretask-source/
http://www.liuinsect.com/2014/02/17/futuretask-%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/