Java线程之FutureTask与Future浅析

一、Future使用

FutureTask是Future和Callable的结合体。传统的代码是这样写的

Future f = executor.submit(new Callable());

然后通过Future来取得计算结果。但是,若开启了多个任务,我们无从知晓哪个任务最先结束。因此,若要实现“当某任务结束时,立刻做一些事情,例如记录日志”这一功能,就需要写一些额外的代码。例如一般的Future使用。

多任务:

 1 package zmx.multithread.test.reentrantlock;
 2
 3
 4 import java.util.Random;
 5 import java.util.concurrent.Callable;
 6 import java.util.concurrent.ExecutionException;
 7 import java.util.concurrent.ExecutorService;
 8 import java.util.concurrent.Executors;
 9 import java.util.concurrent.Future;
10 import java.util.concurrent.FutureTask;
11 import java.util.concurrent.TimeUnit;
12
13 public class T1 {
14     public static void main(String[] args) throws InterruptedException, ExecutionException {
15
16          ExecutorService executor2= Executors.newFixedThreadPool(5);
17          class Task implements Callable<String>{
18             @Override
19             public String call() throws Exception {
20
21                 Random rand = new Random();
22                 TimeUnit.SECONDS.sleep(rand.nextInt(10));
23                 return  Thread.currentThread().getName();
24             }
25          }
26
27          List<Future<String>> results = new ArrayList<Future<String>>();
28          for(int i=0;i<5;i++){
29              Future<String> f =  executor2.submit(new Task());
30              results.add(f);
31          }
32
33          boolean flag =true;
34          while(flag) {
35
36             for(Iterator<Future<String>> iter  = results.iterator();iter.hasNext();){
37                 Future<String> f =iter.next();
38                 if(f.isDone()){
39                     System.out.println(f.get());
40                     iter.remove();
41
42                 }
43             }
44             if(results.size()==0){
45                 flag =false;
46             }
47
48         }
49
50         System.out.println("执行完毕");
51
52         executor2.shutdownNow();
53
54
55
56     }
57
58 }

执行结果:

pool-1-thread-4
pool-1-thread-2
pool-1-thread-1
pool-1-thread-5
pool-1-thread-3
执行完毕

二、FutureTask

上述使用遍历的方式解决多任务结果,但是不是最优的效果,FutureTask正是为此而存在,它有一个回调函数protected void done(),当任务结束时,该回调函数会被触发。因此,只需重载该函数,即可实现在线程刚结束时就做一些事情。

代码如下:

 1 public class Test {
 2     public static void main(String[] args) {
 3         ExecutorService executor = Executors.newCachedThreadPool();
 4         for(int i=0; i<5; i++) {
 5             Callable<String> c = new Task();
 6             MyFutureTask ft = new MyFutureTask(c);
 7             executor.submit(ft);
 8         }
 9         executor.shutdown();
10     }
11
12 }
13
14 class MyFutureTask extends FutureTask<String> {
15
16     public MyFutureTask(Callable<String> callable) {
17         super(callable);
18     }
19
20     @Override
21     protected void done() {
22         try {
23             System.out.println(get() + " 线程执行完毕!~");
24         } catch (InterruptedException | ExecutionException e) {
25             // TODO Auto-generated catch block
26             e.printStackTrace();
27         }
28     }
29
30
31 }
32
33 class Task implements Callable<String> {
34
35     @Override
36     public String call() throws Exception {
37         Random rand = new Random();
38         TimeUnit.SECONDS.sleep(rand.nextInt(12));
39         return Thread.currentThread().getName();
40     }
41 }

结果如下:

pool-1-thread-4 线程执行完毕!
pool-1-thread-3 线程执行完毕!
pool-1-thread-5 线程执行完毕!
pool-1-thread-2 线程执行完毕!
pool-1-thread-1 线程执行完毕!

原文地址:https://www.cnblogs.com/yuandluck/p/9510949.html

时间: 2024-10-27 11:36:12

Java线程之FutureTask与Future浅析的相关文章

Java线程之Callable和Future

本篇说明的是Callable和Future,它俩很有意思的,一个产生结果,一个拿到结果.        Callable接口类似于Runnable,从名字就可以看出来了,但是Runnable不会返回结果,并且无法抛出返回结果的异常,而Callable功能更强大一些,被线程执行后,可以返回值,这个返回值可以被Future拿到,也就是说,Future可以拿到异步执行任务的返回值, 下面来看一个简单的例子: 1 public class CallableAndFuture { 2 public sta

Java线程之Lock

重入锁 Java中的重入锁(即ReentrantLock)与Java内置锁一样,是一种排它锁.使用synchronized的地方一定可以用ReentrantLock代替. 重入锁需要显示请求获取锁,并显示释放锁.为了避免获得锁后,没有释放锁,而造成其它线程无法获得锁而造成死锁,一般建议将释放锁操作放在finally块里,如下所示. 1 2 3 4 5 6 try{ renentrantLock.lock(); } finally { renentrantLock.unlock(); } 如果重入

java多线程之Callable、Future和FutureTask

Java并发编程:Callable.Future和FutureTask 在前面的文章中我们讲述了创建线程的2种方式,一种是直接继承Thread,另外一种就是实现Runnable接口. 这2种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果. 如果需要获取执行结果,就必须通过共享变量或者使用线程通信的方式来达到效果,这样使用起来就比较麻烦. 而自从Java 1.5开始,就提供了Callable和Future,通过它们可以在任务执行完毕之后得到任务执行结果. 今天我们就来讨论一下Callabl

线程之Callable、Future 和FutureTask使用及源码分析

一.Callable 我们知道启动线程有以下两种方式(jdk源码注释中官方定义只有两种启动方式,callable不算线程启动方式) 原文链接:http://www.studyshare.cn/blog-front/blog/details/1141 (1).new Thread().start() (2).new Thread(new Runnable()).start(); 以上两种方式中的run()方法的返回值是void类型,即没有返回值,如果我们需要在业务线程中执行业务代码后需要将结果进行

Java线程之CompletionService批处理任务

如果你向Executor提交了一个批处理任务,并且希望在它们完成后获得结果,怎么办呢? 为此你可以保存与每个任务相关联的Future,然后不断地调用 timeout为零的get,来检验Future是否完成.这样做固然可以,但却相当乏味.幸运的是,还有一个更好的方法:完成服务 (Completion service). CompletionService整合了Executor和BlockingQueue的功能. 你可以将Callable任务提交给它去执行,然 后使用类似于队列中的take和poll

Java线程之CompletionService

CompletionService的使用 当我们使用ExecutorService创建一个线程池时, 如果执行了多个Callable任务后, 每个Callable任务都会产生一个Future, 如果我们需要处理这些任务产生的结果, 那么就需要将这些Future放入一个线性表中, 用于之后的数据处理. 有了CompletionService, 我们就不用人为地去创建线性表来存这些Future了, CompleService是一个更高级的EexcutorService, 它自身自带一个线程安全的线性

java 线程之-volatile

前言-发奋忘食,乐以忘优,不知老之将至. 介绍:在java中用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的最的值[注意:不要被这个都字误导.稍后做详细解释].volatile很容易被[误用],用来进行[原子性]操作. 解释:在java的虚拟机运行的机制中,java的线程运行程序的时候,为了保证程序运行的效率问题,每个线程运行的时候,虚拟机会单独为这个线程分配一块临时内存区域,我们可以称之为[当前线程专用内存] 而线程会把自己运行过程中所需要的变量加载到[当前线程专用

java 线程之concurrent中的常用工具 CyclicBarrier

一.CyclicBarrier CyclicBarrier是一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point).在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用.因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier. CyclicBarrier类似于CountDownLatch也是个计数器, 不同的是CyclicBarrier数的是调用了CyclicBa

Java线程之 InterruptedException 异常

在测试Runnable 的时候,在run中使用了Thread.sleep(100),代码如下: while(true) { Thread.sleep(100); if(tickets>0) System.out.println("Thread name is "+Thread.currentThread().getName()+"还剩下="+tickets--); } 但是出现了下面的问题 Unhandled exception type Interrupte