美文网首页
Java中的Runnable、Callable和Future的关

Java中的Runnable、Callable和Future的关

作者: 慕尼黑凌晨四点 | 来源:发表于2020-10-29 16:43 被阅读0次

前提

Java中多线程包下相关的接口有RunnableCallableFuture

  • Runnable

    public interface Runnable {
        void run();
    }
    
  • Callable

    public interface Callable<V> {
        V call() throws Exception;
    }
    

Runnable和Callable的区别

  1. Runnable执行方法是run(),Callable是call()
  2. Runnable无返回值且不会抛错;Callable带返回值且可以向外抛异常

这两个只是个接口,并不能用来进行线程相关操作。开辟线程还是要用Thread,而Thread又只能传Runnable,不支持传Callable,怎么破?

解决方法:创建一个类,让他实现Runnable接口,然后内部持有一个Callable对象。在Runnable的run方法中调用mCallable.call()方法。

妙啊~

这个类叫FutureTask

FutureTask

类图

类图

用法

Callable<String> callable = new Callable<String>() {
    public String call() throws Exception {
        //something to do...
        return "睡醒了";
    }
};
FutureTask<String> task = new FutureTask<String>(callable);
//FutureTask实现了Runnable接口,所以可以直接传给Thread
new Thread(task).start();
//获取到了返回值
String call = task.get();
System.out.println(call);

Future

可以看到FutureTask没有直接实现Runnable,而是继承RunnableFutureRunnableFuture来同时实现了Runnable和Future两个接口:

public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}

且看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;
}

说明FutureTask还额外实现了Future接口的相关功能。比如说Runnable的run方法中无返回值,要取到返回值的话就要用到Future中的get方法。

到这里三者的关系应该捋清楚了。

Runnable没返回值,Callable有返回值,但是Thread不接受Callable,所以有了FutureTaskFutureTask实现Runnable,传入Callable对象。这个时候还需要写一些相关的方法(比如取出返回值的方法),然后这些方法就收录到了Future接口中。

Future的另一个使用场景

线程池

线程池中线程来了又去,总有一个需要带返回值。

这个时候就要传入Callable了。

Callable<String> callable = new Callable<String>() {
    public String call() throws Exception {
        //something to do...
        return "睡醒了";
    }
};
ExecutorService executor = Executors.newFixedThreadPool(2);
Future<String> task = executor.submit(callable);
String call = task.get();
System.out.println(call);

executor.submit(callable)返回的也是一个Future<T> ,然后就可以获取到返回值了。

ps:其实内部调用的还是FutureTask,submit代码如下:

    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }

    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
        return new FutureTask<T>(callable);
    }

另补充一点:FutureTask()也可以传入Runnable,不过最后还是会把Runnable转换成Callable的。

用的是这个:

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;
        }
    }

反着来,实现Callable,内部持有Runnable😂

相关文章

网友评论

      本文标题:Java中的Runnable、Callable和Future的关

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