并发编程——Runnable、Callable、Future和FutureTask详解
在Java中,通过继承Thread,重写其run方法,还有就是实现Runnable接口是最常见的新建线程的两种方式,唯一不足的是这两种方式在执行完run方法之后无法得到返回值,为了优化这种情况,继而出现了Callable和Future,通过它们可以在执行完任务之后得到任务执行结果。
1. Runnable
Runnable是一个函数式接口,被@FunctionalInterface
标识,接口里面只定义了一个返回void
类型的run方法,所以线程执行完成后是不会有返回值的。
2. Callable
可以看到Callable接口和Runnable一样也被@FunctionalInterface
标识,不同的是接口里面的call方法返回了一个泛型类型
,但是线程是异步执行的,两个线程是互不干扰的,那我们怎么在一个线程里面获取到其他任务执行之后的结果呢?Future接口这个时候就可以派上用场了。
3. Future
当使用Callable想获取返回值的时候就需要用到Future接口,使用Future可以监视任务的执行情况
,下面详细解释一下Future接口里面各个方法的作用:
cancel
用来取消任务,取消任务成功则返回true,否则返回false,mayInterruptIfRunning用来控制是否允许取消正在执行却没有执行完毕的任务,有以下几种情况:
- 任务
已经完成
,不管mayInterruptIfRunning设置为true还是false,方法返回都是false; - 任务
正在执行
,如果mayInterruptIfRunning设置为true,则返回true,如果mayInterruptIfRunning设置为false,则返回false; - 任务
还未执行
,不管mayInterruptIfRunning设置为true还是false,都返回true。
-
isCancelled
任务是否被取消成功 -
isDone
任务是否已经完成 -
get()
用来获取执行结果,get方法会使当前调用线程产生阻塞
,一直等到任务执行完毕才返回,然后继续向下执行代码。 -
get(long timeout, TimeUnit unit)
用来获取执行结果,可以指定时间,如果还没获取到结果,就直接返回null,这个就比get()方法好些,可以避免了获取不到结果让当前调用线程一直阻塞。
Future使用代码示例:
public class CallableDemo implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("CallableDemo call");
Thread.sleep(1000);
return "success";
}
}
public class FutureDemo {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executorService = Executors.newCachedThreadPool();
Future<String> future = executorService.submit(new CallableDemo ());
String result = future.get(); //产生阻塞
System.out.println(result);
}
}
4.FutureTask
FutureTask是Future接口的具体实现,从上面可以看出也实现了Runnable接口。
关于FutureTask的使用可以看如下代码:
import java.util.concurrent.*;
public class FutureTaskExample {
public static void main(String[] args) throws InterruptedException, ExecutionException {
// 创建一个任务
Callable<Integer> task = () -> {
Thread.sleep(2000);
return 42;
};
// 创建一个FutureTask并包装任务
FutureTask<Integer> futureTask = new FutureTask<>(task);
// 创建线程执行FutureTask
Thread thread = new Thread(futureTask);
thread.start();
// 主线程可以继续执行自己的流程
System.out.println("doing something...");
// 阻塞获取futureTask中任务的执行结果
Integer result = futureTask.get();
System.out.println("result: " + result);
}
}
上一篇 java内部类最全详解(成员内部类、局部内部类、匿名内部类、静态内部类)!!! |
记得点赞收藏哦!!!
| 下一篇 java面向对象三大特征 |