FutureTask并发详解,通俗易懂
最近做项目,使用到了FutureTask和主线程并发,应用到实际中还是挺实用的,特在此总结一下。
有不对之处,忘各位多多指出。
1 package com.demo; 2 3 import java.util.concurrent.Callable; 4 import java.util.concurrent.FutureTask; 5 6 public class FutureTaskTest { 7 8 public static void main(String[] args) throws Exception { 9 for (int i = 0; i < 10; i++) { 10 long currentTimeMillis = System.currentTimeMillis(); 11 FutureTask<String> future1 = new FutureTask<>(new MyTaskA()); 12 new Thread(future1).start();// 一定要先开启线程,如果主线程在开启线程前调用,就没了并发的效果,可以自行测试 13 Thread.sleep(100);// 主线程耗时100ms 14 String r1 = future1.get(); 15 System.out.println(r1); 16 System.err.println(i + "-----" + String.valueOf(System.currentTimeMillis() - currentTimeMillis) + "ms"); 17 } 18 } 19 20 static class MyTaskA implements Callable<String> { 21 @Override 22 public String call() throws Exception { 23 Thread.sleep(50);// 并发线程耗时50ms 24 return "testA"; 25 } 26 } 27 28 }
20-26行创建一个任务MyTaskA,实现的是Callable,主要是为了获取返回值(关于如何创建线程,这里就不在赘述);
11行创建FutureTask;
12行启动线程:此时任务MyTaskA就已经开始执行;
13行主线程执行耗时100ms的任务;
14行FutureTask获取返回值,该方法是会等待任务完成然后获取到返回值。
输出结果如下:
testA 0-----101ms testA 1-----100ms testA 2-----100ms testA 3-----100ms testA 4-----100ms testA 5-----100ms testA 6-----100ms testA 7-----100ms testA 8-----100ms testA 9-----100ms
上面就是一个线程和主线程并发执行,下面再看一个两个线程和主线程并发,其实差别不大
1 package com.demo; 2 3 import java.util.concurrent.Callable; 4 import java.util.concurrent.FutureTask; 5 6 public class FutureTaskTest { 7 8 public static void main(String[] args) throws Exception{ 9 for (int i = 0; i < 10; i++) { 10 long currentTimeMillis = System.currentTimeMillis(); 11 12 FutureTask<String> futureA = new FutureTask<>(new MyTaskA()); 13 FutureTask<String> futureB = new FutureTask<>(new MyTaskB()); 14 new Thread(futureA).start(); 15 new Thread(futureB).start(); 16 17 Thread.sleep(100); 18 System.out.println(futureA.get()+"---"+futureB.get()); 19 System.err.println(i+"-----"+String.valueOf(System.currentTimeMillis()-currentTimeMillis)+"ms"); 20 } 21 } 22 static class MyTaskA implements Callable<String>{ 23 @Override 24 public String call() throws Exception { 25 Thread.sleep(50);//并发线程耗时50ms 26 return "testA"; 27 } 28 } 29 static class MyTaskB implements Callable<String>{ 30 @Override 31 public String call() throws Exception { 32 Thread.sleep(50); 33 return "testB"; 34 } 35 } 36 37 38 }
执行结果如下
testA---testB 0-----103ms testA---testB 1-----100ms testA---testB 2-----100ms testA---testB 3-----100ms testA---testB 4-----100ms testA---testB 5-----101ms testA---testB 6-----100ms testA---testB 7-----101ms testA---testB 8-----100ms testA---testB 9-----101ms
上面使用Thread启动的FutureTask,咱们也可以用线程池,代码如下
package com.demo; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class FutureTaskTest { public static void main(String[] args) throws Exception { for (int i = 0; i < 10; i++) { long currentTimeMillis = System.currentTimeMillis(); ExecutorService executorService = Executors.newFixedThreadPool(2); Future<String> futureA = executorService.submit(new MyTaskA()); Future<String> futureB = executorService.submit(new MyTaskB()); Thread.sleep(100); System.out.println(futureA.get() + "---" + futureB.get()); System.err.println(i + "-----" + String.valueOf(System.currentTimeMillis() - currentTimeMillis) + "ms");
executorService.shutdown();//注意:用完之后一定要关闭线程池 } } static class MyTaskA implements Callable<String> { @Override public String call() throws Exception { Thread.sleep(50);// 并发线程耗时50ms return "testA"; } } static class MyTaskB implements Callable<String> { @Override public String call() throws Exception { Thread.sleep(50); return "testB"; } } }
输出结果如下
testA---testB 0-----104ms testA---testB 1-----101ms testA---testB 2-----101ms testA---testB 3-----101ms testA---testB 4-----100ms testA---testB 5-----102ms testA---testB 6-----101ms testA---testB 7-----101ms testA---testB 8-----101ms testA---testB 9-----101ms