java 在线程执行器中执行任务并且返回结果
是什么?为什么?怎么做?
一、是什么
记得之前写过future获取异步线程执行结果:
http://www.xie4ever.com/2017/03/23/java-future%E8%8E%B7%E5%8F%96%E7%BA%BF%E7%A8%8B%E5%BC%82%E6%AD%A5%E6%89%A7%E8%A1%8C%E7%9A%84%E7%BB%93%E6%9E%9C/
上次是直接使用线程执行带返回结果的线程。这次我们尝试交给线程执行器执行。
二、为什么
原因同:
http://www.xie4ever.com/2017/03/28/java-threadpoolexecutor%E5%88%9B%E5%BB%BA%E7%BA%BF%E7%A8%8B%E6%89%A7%E8%A1%8C%E5%99%A8/
三、怎么做
1.简单例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
package testThreadPoolExecutorRunTask; import java.util.Date; 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 test { /** * @param args */ public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(2); count count1 = new count(); count count2 = new count(); count count3 = new count(); Future<Integer> future1 = executorService.submit(count1); Future<Integer> future2 = executorService.submit(count2); Future<Integer> future3 = executorService.submit(count3); try { System.out.println("future1:" + future1.get()); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { System.out.println("future2:" + future2.get()); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { System.out.println("future3:" + future3.get()); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); } executorService.shutdown(); } } class count implements Callable<Integer> { public Integer call() throws Exception { // TODO Auto-generated method stub System.out.println(Thread.currentThread().getName() + " start on " + new Date().getTime()); Thread.sleep(3000); int num = 0; for (int i = 0; i < 10000; i++) { num = num + i; } System.out.println(Thread.currentThread().getName() + " end on " + new Date().getTime()); return num; } } |
大致流程就是这样,代替了直接操作线程的方式。
这里创建了一个只有两条线程大小的线程池,但是现在存在三个任务,就如何执行?
1 |
ExecutorService executorService = Executors.newFixedThreadPool(2); |
我的理解:
线程池只能同时分配两条线程,所以先来先得,优先执行前两个任务。当某一个任务执行完毕,线程回到线程池中,就会被分配去执行第三个任务。
运行结果也证明了这一点:
1 2 3 4 5 6 7 8 9 |
pool-1-thread-1 start on 1490756914518 pool-1-thread-2 start on 1490756914518 pool-1-thread-2 end on 1490756917518 pool-1-thread-2 start on 1490756917519 pool-1-thread-1 end on 1490756917520 future1:49995000 future2:49995000 pool-1-thread-2 end on 1490756920520 future3:49995000 |
2.复杂一点的例子
使用上次的情景:
老师让三个学生做一道题,每隔一段时间看看学生做完没有,如果学生没做完,就提醒一下做题方法,如果学生做完了,就拿给老师检查。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
package testThreadPoolExecutorRunTask; 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 teach { public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); List<Future<Integer>> futures = new ArrayList<Future<Integer>>(); for (int i = 0; i < 3; i++) { student student = new student(); Future<Integer> future = executorService.submit(student); futures.add(future); } try { Thread.sleep(5000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } for (int i = 0; i < futures.size(); i++) { Future<Integer> future = futures.get(i); if (future.isDone()) { try { System.out.println("the result is " + future.get() + " , well done"); futures.remove(future); i--; } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); } } else { System.out.println("isn't done ! teacher give directions"); } } try { Thread.sleep(6000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } for (Future<Integer> future : futures) { try { System.out.println("the result is " + future.get() + " , well done"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); } } executorService.shutdown(); } } class student implements Callable<Integer> { public Integer call() throws Exception { // TODO Auto-generated method stub System.out.println(Thread.currentThread().getName() + " start counting"); int time = new Random().nextInt(10); System.out.println(Thread.currentThread().getName() + " need " + time + "s"); int num = 0; for (int i = 0; i < 10000; i++) { num = num + i; } Thread.sleep(time * 1000); System.out.println(Thread.currentThread().getName() + " finish counting"); return num; } } |
比较需要注意的是这里:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
for (int i = 0; i < futures.size(); i++) { Future<Integer> future = futures.get(i); if (future.isDone()) { try { System.out.println("the result is " + future.get() + " , well done"); futures.remove(future); i--; } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); } } else { System.out.println("isn't done ! teacher give directions"); } } |
移除元素后需要i–,否则会报出java.util.ConcurrentModificationException异常。
运行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
pool-1-thread-2 start counting pool-1-thread-1 start counting pool-1-thread-3 start counting pool-1-thread-3 need 7s pool-1-thread-1 need 1s pool-1-thread-2 need 2s pool-1-thread-1 finish counting pool-1-thread-2 finish counting the result is 49995000 , well done the result is 49995000 , well done isn't done ! teacher give directions pool-1-thread-3 finish counting the result is 49995000 , well done |
四、总结
要体会线程执行器的思想。