Java中的Runnable,Callable,Future,FutureTask的比较

网友投稿 184 2023-06-10


Java中的Runnable,Callable,Future,FutureTask的比较

java中的Runnable,Callable,Future,FutureTask的比较

Java中存在Runnable、Callable、Future、FutureTask这几个与线程相关的类或者接口,在Java中也是比较重要的几个概念,我们通过下面的简单示例来了解一下它们的作用于区别。

Runnable

其中Runnable应该是我们最熟悉的接口,它只有一个run()函数,用于将耗时操作写在其中, 该函数没有返回值 。然后使用某个线程去执行该runnable即可实现多线程,Thread类在调用start()函数后就是执行的是Runnable的run()函数。Runnable的声明如下 :

@FunctionalInterface

public interface Runnable {

/**

* When an object implementing interface Runnable is used

* to create a thread, starting the thread causes the object's

* run method to be called in that separately executing

* thread.

*

* The general contract of the method run is that it may

* take any action whatsoever.

*

* @see java.lang.Thread#run()

*/

public abstract void run();

}

Callable

Callable与Runnable的功能大致相似,Callable中有一个call()函数,但是 call()函数有返回值 ,而Runnable的run()函数不能将结果返回给客户程序。Callable的声明如下 :

@FunctionalInterface

public interface Callable {

/**

* Computes a result, or throws an exception if unable to do so.

*

* @return computed result

* @throws Exception if unable to compute a result

*/

V call() throws Exception;

}

可以看到,这是一个泛型接口,call()函数返回的类型就是客户程序传递进来的V类型。

Future

Executor就是Runnable和Callable的调度容器,Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果、设置结果操作。get方法会阻塞,直到任务返回结果(Future简介)。Future声明如下:

* @see FutureTask

* @see Executor

* @since 1.5

* @author Doug Lea

* @param The result type returned by this Future's {@code get} method

*/

public interface Future {

/**

* Attempts to cancel execution of this task. This attempt will

* fail if the task has already completed, has already been cancelled,

* or could not be cancelled for some other reason. If successful,

* and this task has not started when {@code cancel} is called,

* this task should never run. If the task has already started,

* then the {@code mayInterruptIfRunning} parameter determines

* whether the thread executing this task should be interrupted in

* an attempt to stop the task.

*

*

After this method returns, subsequent calls to {@link #isDone} will

* always return {@code true}. Subsequent calls to {@link #isCancelled}

* will always return {@code true} if this method returned {@code true}.

*

* @param mayInterruptIfRunning {@code true} if the thread executing this

* task should be interrupted; otherwise, in-progress tasks are allowed

* to complete

* @return {@code false} if the task could not be cancelled,

* typically because it has already completed normally;

* {@code true} otherwise

*/

boolean cancel(boolean mayInterruptIfRunning);

/**

* Returns {@code true} if this task was cancelled before it completed

* normally.

*

* @return {@code true} if this task was cancelled before it completed

*/

boolean isCancelled();

/**

* Returns {@code true} if this task completed.

*

* Completion may be due to normal termination, an exception, or

* cancellation -- in all of these cases, this method will return

* {@code true}.

*

* @return {@code true} if this task completed

*/

boolean isDone();

/**

* Waits if necessary for the computation to complete, and then

* retrieves its result.

*

* @return the computed result

* @throws CancellationException if the computation was cancelled

* @throws ExecutionException if the computation threw an

* exception

* @throws InterruptedException if the current thread was interrupted

* while waiting

*/

V get() throws InterruptedException, ExecutionException;

/**

* Waits if necessary for at most the given time for the computation

* to complete, and then retrieves its result, if available.

*

* @param timeout the maximum time to wait

* @param unit the time unit of the timeout argument

* @return the computed result

* @throws CancellationException if the computation was cancelled

* @throws ExecutionException if the computation threw an

* exception

* @throws InterruptedException if the current thread was interrupted

* while waiting

* @throws TimeoutException if the wait timed out

*/

V get(long timeout, TimeUnit unit)

throws InterruptedException, ExecutionException, TimeoutException;

}

FutureTask

FutureTask则是一个RunnableFuture< V>,而RunnableFuture实现了Runnbale又实现了Futrue< V>这两个接口:

public class FutureTask implements RunnableFuture {

......

}

RunnableFuture

/**

* A {@link Future} that is {@link Runnable}. Successful execution of

* the {@code run} method causes completion of the {@code Future}

* and allows access to its results.

* @see FutureTask

* @see Executor

* @since 1.6

* @author Doug Lea

* @param The result type returned by this Future's {@code get} method

*/

public interface RunnableFuture extends Runnable, Future {

/**

* Sets this Future to the result of its computation

* unless it has been cancelled.

*/

void run();

}

另外FutureTask还可以包装Runnable和Callable< V>, 由构造函数注入依赖。

/**

* Creates a {@code FutureTask} that will, upon running, execute the

* given {@code Callable}.

*

* @param callable the callable task

* @throws NullPointerException if the callable is null

*/

public FutureTask(Callable callable) {

if (callable == null)

throw new NullPointerException();

this.callable = callable;

this.state = NEW; // ensure visibility of callable

}

/**

* Creates a {@code FutureTask} that will, upon running, execute the

* given {@code Runnable}, and arrange that {@code get} will return the

* given result on successful completion.

*

* @param runnable the runnable task

* @param result the result to return on successful completion. If

* you don't need a particular result, consider using

* constructions of the form:

* {@code Future> f = new FutureTask(runnable, null)}

* @throws NullPointerException if the runnable is null

*/

public FutureTask(Runnable runnable, V result) {

this.callable = Executors.callable(runnable, result);

this.state = NEW; // ensure visibility of callable

}

可以看到,Runnable注入会被Executors.callable()函数转换为Callable类型,即FutureTask最终都是执行Callable类型的任务。该适配函数的实现如下 :

/**

* Returns a {@link Callable} object that, when

* called, runs the given task and returns the given result. This

* can be useful when applying methods requiring a

* {@code Callable} to an otherwise resultless action.

* @param task the task to run

* @param result the result to return

* @param the type of the result

* @return a callable object

* @throws NullPointerException if task null

*/

public static Callable callable(Runnable task, T result) {

if (task == null)

throw new NullPointerException();

return new RunnableAdapter(task, result);

}

RunnableAdapter适配器

/**

* A callable that runs given task and returns given result

*/

static final class RunnableAdapter implements Callable {

final Runnable task;

final T result;

RunnableAdapter(Runnable task, T result) {

this.task = task;

this.result = result;

}

public T call() {

task.run();

return result;

}

}

由于FutureTask实现了Runnable,因此它既可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行。并且还可以直接通过get()函数获取执行结果,该函数会阻塞,直到结果返回。

因此FutureTask既是Future、Runnable,又是包装了Callable(如果是Runnable最终也会被转换为Callable ), 它是这两者的合体。

完整示例:

package com.stay4it.rx;

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;

import java.util.concurrent.FutureTask;

public class FutureTest {

public static class Task implements Runnable {

@Override

public void run() {

// TODO Auto-generated method stub

System.out.println("run");

}

}

public static class Task2 implements Callable {

@Override

public Integer call() throws Exception {

System.out.println("call");

return fibc(30);

}

}

/**

* runnable, 无返回值

*/

public static void testRunnable(){

ExecutorService executorService = Executors.newCachedThreadPool();

Future future = (Future) executorService.submit(new Task());

try {

System.out.println(future.get());

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (ExecutionException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

executorService.shutdown();

}

/**

* Callable, 有返回值

*/

public static void testCallable(){

ExecutorService executorService = Executors.newCachedThreadPool();

Future future = (Future) executorService.submit(new Task2());

try {

System.out.println(future.get());

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (ExecutionException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

executorService.shutdown();

}

/**

* FutureTask则是一个RunnableFuture,即实现了Runnbale又实现了Futrue这两个接口,

* 另外它还可以包装Runnable(实际上会转换为Callable)和Callable

* ,所以一般来讲是一个符合体了,它可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行

* ,并且还可以通过v get()返回执行结果,在线程体没有执行完成的时候,主线程一直阻塞等待,执行完则直接返回结果。

*/

public static void testFutureTask(){

ExecutorService executorService = Executors.newCachedThreadPool();

FutureTask futureTask = new FutureTask(new Task2());

executorService.submit(futureTask);

try {

System.out.println(futureTask.get());

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (ExecutionException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

executorService.shutdown();

}

/**

* FutureTask则是一个RunnableFuture,即实现了Runnbale又实现了Futrue这两个接口,

* 另外它还可以包装Runnable(实际上会转换为Callable)和Callable

* ,所以一般来讲是一个符合体了,它可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行

* ,并且还可以通过v get()返回执行结果,在线程体没有执行完成的时候,主线程一直阻塞等待,执行完则直接返回结果。

*/

public static void testFutureTask2(){

ExecutorService executorService = Executors.newCachedThreadPool();

FutureTask futureTask = new FutureTask(new Runnable() {

@Override

public void run() {

// TODO Auto-generated method stub

System.out.println("testFutureTask2 run");

}

},fibc(30));

executorService.submit(futureTask);

try {

System.out.println(futureTask.get());

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (ExecutionException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

executorService.shutdown();

}

public static void main(String[] args) {

testCallable();

}

/**

* 效率低下的斐波那契数列, 耗时的操作

*

* @param num

* @return

*/

static int fibc(int num) {

if (num == 0) {

return 0;

}

if (num == 1) {

return 1;

}

return fibc(num - 1) + fibc(num - 2);

}

}

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:分享一道关于闭包、bind和this的面试题
下一篇:Java for循环几种写法整理
相关文章

 发表评论

暂时没有评论,来抢沙发吧~