美文网首页
Callable,Future和FutureTask

Callable,Future和FutureTask

作者: LZhan | 来源:发表于2019-12-09 15:52 被阅读0次
1 Callable

Callable与Runnable不同(Runnable不能返回任务执行结果并且不能抛出异常),
Callable是个泛型参数化接口,并且能返回线程的执行结果,且能在无法正常计算时抛出异常


Callable.png

<1> Callable并不像Runnable那样通过Thread的start方法就能启动实现类的run方法,所以它通常利用ExecutorService的submit方法去启动call方法执行任务,而ExecutorService的submit又返回一个Future类型的结果,因此Callable通常也与Future一起使用

 ExecutorService pool = Executors.newCachedThreadPool();
     Future<String> future = pool.submit(new Callable{
           public void call(){
                   //TODO
           }
    });

或者利用FutureTask封装Callable,再由Thread去启动(少用)

FutureTask<String> task = new FutureTask(new Callable{
        public void call(){
              //TODO
        }
  });
 Thead thread = new Thread(task);
 thread.start();

<2> 通过Executors.callbale(Runnable task,T result)可以执行Runnable并返回"结果",但是这个结果并不是Runnable的执行结果(Runnable的run方法是void类型),而是执行者预定义的结果,这点可以从其实现原理RunnableAdpter源码看出

public static <T> Callable<T> callable(Runnable task, T result) {
     if (task == null)
          throw new NullPointerException();
       return new RunnableAdapter<T>(task, result);//通过RunnableAdapter实现
}
    
static final class RunnableAdapter<T> implements Callable<T> {
     final Runnable task;
     final T result;
     RunnableAdapter(Runnable task, T result) {
            this.task = task;
            this.result = result;
     }
     public T call() {
        task.run();
        return result; //将传入的结果的直接返回
     }
   }

实例:

        final Integer[] result={null};

        Runnable runnable=new Runnable() {
            @Override
            public void run() {
                result[0]=1111;
            }
        };

        //定义一个线程池
        ExecutorService executorService= Executors.newCachedThreadPool();

        //1.Executors.callable(runnable) 转换成Callable<Object>,Future返回null
        Callable<Object> callable=Executors.callable(runnable);
        Future future=executorService.submit(callable);
        //输出运行结果,肯定是null
        System.out.println("Executors.callable(runnable) 的future = " + future.get());

        //2.Executors.callable(runnable,result) 转换成Callable<V>,future有值
        Callable<Integer> callable1=Executors.callable(runnable,result[0]);
        Future future1=executorService.submit(callable1);
        System.out.println("Executors.callable(runnable, result) 的future = " + future1.get());

执行结果:

Runnable与Callable不同点:

  1. Runnable不返回任务执行结果,Callable可返回任务执行结果
  2. Callable在任务无法计算结果时抛出异常,而Runnable不能
  3. Runnable任务可直接由Thread的start方法或ExecutorService的submit方法去执行
2 Future

Future就是对于具体的Runable或者Callable任务的执行结果进行取消、查询是否完成、获取结果。必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果。

  • cancel(boolean mayInterruptIfRunning):试图取消执行的任务,如果取消任务成功则返回true,如果取消任务失败则返回false。
    参数mayInterruptIfRunning表示是否允许取消正在执行却没有执行完毕的任务,如果设置true,则表示可以取消正在执行过程中的任务。
    如果任务已经完成,则无论mayInterruptIfRunning为true还是false,此方法肯定返回false,即如果取消已经完成的任务会返回false;
    如果任务正在执行,若mayInterruptIfRunning设置为true,则返回true,若mayInterruptIfRunning设置为false,则返回false;
    如果任务还没有执行,则无论mayInterruptIfRunning为true还是false,肯定返回true。

  • isCancelled():判断任务是否在正常执行完前被取消的,如果是则返回true

  • isDone():判断任务是否已完成

  • get():等待计算结果的返回,这个方法会产生阻塞,会一直等到任务执行完毕才返回,如果计算被取消了则抛出

  • get(long timeout,TimeUtil unit):设定计算结果的返回时间,如果在规定时间内没有返回计算结果则抛出TimeOutException
    使用Future的好处:

  1. 获取任务的结果,判断任务是否完成,中断任务
  2. Future的get方法很好的替代的了Thread.join或Thread,join(long millis)
  3. Future的get方法可以判断程序代码(任务)的执行是否超时,如:
 try{
      future.get(60,TimeUtil.SECOND);
 }catch(TimeoutException timeout){
      log4j.log("任务越野,将被取消!!");
      future.cancel();
 }

总结:自Java1.5之后,通过Callable和Future的配合使用,可以在任务执行完毕之后得到任务的执行结果

3 FutureTask

FutureTask实现RunableFuture接口,这个接口的定义如下:

public interface RunnableFuture<V> extends Runnable, Future<V> {  
    void run();  
}

可以看到这个接口实现了Runnable和Future接口,接口中的具体实现由FutureTask来实现。这个类的两个构造方法如下:

   public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }

    public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
    }

如上提供了两个构造函数,一个以Callable为参数,另外一个以Runnable为参数。这些类之间的关联对于任务建模的办法非常灵活,允许你基于FutureTask的Runnable特性(因为它实现了Runnable接口),把任务写成Callable,然后封装进一个由执行者调度并在必要时可以取消的FutureTask

实例:

public class FutureTaskExample {
    public static void main(String[] args) {

        MyCallable callable1 = new MyCallable(1000);
        MyCallable callable2 = new MyCallable(2000);

        FutureTask<String> futureTask1 = new FutureTask<String>(callable1);
        FutureTask<String> futureTask2 = new FutureTask<String>(callable2);

        ExecutorService executor = Executors.newFixedThreadPool(2);
        executor.execute(futureTask1);
        executor.execute(futureTask2);

        while (true) {
            try {
                if (futureTask1.isDone() && futureTask2.isDone()) { //两个任务全都完成
                    System.out.println("Done");
                    executor.shutdown();                            //关闭线程池和服务
                    return;
                }

                if (!futureTask1.isDone()) { // 任务1没有完成,会等待,直到任务完成
                    System.out.println("FutureTask1 output=" + futureTask1.get());
                }
                System.out.println("Waiting for FutureTask2 to complete");
                String s = futureTask2.get(200L, TimeUnit.MILLISECONDS);
                if (s != null) {
                    System.out.println("FutureTask2 output=" + s);
                }

            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            } catch (TimeoutException e) {
                //do nothing
            }
        }
    }

    private static class MyCallable implements Callable<String> {

        private long waitTime;

        public MyCallable(int timeInMillis) {
            this.waitTime = timeInMillis;
        }

        @Override
        public String call() throws Exception {
            Thread.sleep(waitTime);
            return Thread.currentThread().getName();
        }
    }
}

结果显示:

相关文章

网友评论

      本文标题:Callable,Future和FutureTask

      本文链接:https://www.haomeiwen.com/subject/pkdbgctx.html