Future、FutureTask、Runnable、Callable的关系
发布日期:2021-09-12 09:57:55 浏览次数:17 分类:技术文章

本文共 5009 字,大约阅读时间需要 16 分钟。

以及并在此基础上加了一些其他知识点。

一、Runnable

1、实现该接口并重写run方法2、利用该类的对象创建线程3、线程启动时就会自动调用该对象的run方法

通常在开发中结合ExecutorService使用,将任务的提交与任务的执行解耦开,同时也能更好地利用Executor提供的各种特性

缺点:

1.Runnable接口不能抛出异常,只能内部消化;2.Runnable接口没有返回值

注意:
因为Java单继承多实现,所以相对于集成Thread类,实现Runnable接口要更好。

ExecutorService executor = Executors.newCachedThreadPool();executor.submit(new Runnable() {

 public void run()
  {
   //TODO
 } });executor.shutdown();

ExecutorService继承(扩展)了Executor接口,添加了一些用于生命周期管理的方法。

public interface ExecutorService extends Executor{
   
void shutdown();//平稳的关闭,不再接收新的任务、同时等待已经提交的任务执行
List  shutdownNow();//执行暴力的关闭,尝试取消所有运行的任务,并且不再启动队列中尚未启动的任务
boolean isShutDown();//如果此执行程序已关闭,则返回 true
boolean isTerminated();//查询ExecutorService是否已经终止
boolean awaitTermination(long timeout, TimeUint unit) throws InterruptedException;
//通常调用awaitTermination后会立即调用shutdown,产生同步关闭ExecutorServicce
Future  submit(Runnable task);
//提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。该 Future 的 get 方法在成功 完成时将会返回 null。 抛出RejectedExecutionException - 如果任务无法安排执行 ,NullPointerException - 如果该任务为 null
.....}

二、Callable接口

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

public interface Callable
   
     {

    
   V call() throws Exception;}

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

ExecutorService pool = Executors.newCachedThreadPool();Future
   
     future = pool.submit(new Callable{

    
 public void call(){
 //TODO
  }});

Runnable与Callable不同点:

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

三、Future

Future保存异步计算的结果,可以在我们执行任务时去做其他工作,并提供了以下几个方法

  • cancel(boolean mayInterruptIfRunning):试图取消执行的任务,参数为true时直接中断正在执行的任务,否则直到当前任务执行完成,成功取消后返回true,否则返回false
  • isCancel():判断任务是否在正常执行完前被取消的,如果是则返回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(); }

四、FutureTask

先看FutureTask的实现

public class FutureTask
   
     implements RunnableFuture
    
   

FutureTask实现了RunnableFuture接口,我们再来看下RunnableFuture接口:

public interface RunnableFuture
   
     extends Runnable, Future
    
      {

     
   void run();}

可以看出RunnableFuture继承了Runnable接口和Future接口,而FutureTask实现了RunnableFuture接口。所以它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。
FutureTask提供了2个构造器:

public FutureTask(Callable
   
     callable) {
   }public FutureTask(Runnable runnable, V result) {
   }
   

代码例子

1、Callable+Future获取执行结果

public class Test {

   public static void main(String[] args) {
   ExecutorService executor = Executors.newCachedThreadPool();
Task task = new Task();
Future  result = executor.submit(task);
executor.shutdown();
 try {
   Thread.sleep(1000);
} catch (InterruptedException e1) {
   e1.printStackTrace();
}
 System.out.println("主线程在执行任务");
 try {
   System.out.println("task运行结果"+result.get());
} catch (InterruptedException e) {
   e.printStackTrace();
} catch (ExecutionException e) {
   e.printStackTrace();
}
 System.out.println("所有任务执行完毕");
}}class Task implements Callable {
   @Override
public Integer call() throws Exception {
   System.out.println("子线程在进行计算");
Thread.sleep(3000);
int sum = 0;
for(int i=0;i<100;i++)
sum += i;
return sum;
}}

2、Callable+FutureTask获取执行结果

public class Test {

   public static void main(String[] args) {
   //第一种方式
ExecutorService executor = Executors.newCachedThreadPool();
Task task = new Task();
FutureTask  futureTask = new FutureTask (task);
executor.submit(futureTask);
executor.shutdown();
 //第二种方式,注意这种方式和第一种方式效果是类似的,只不过一个使用的是ExecutorService,一个使用的是Thread
/*Task task = new Task();
FutureTask  futureTask = new FutureTask (task);
Thread thread = new Thread(futureTask);
thread.start();*/
 try {
   Thread.sleep(1000);
} catch (InterruptedException e1) {
   e1.printStackTrace();
}
 System.out.println("主线程在执行任务");
 try {
   System.out.println("task运行结果"+futureTask.get());
} catch (InterruptedException e) {
   e.printStackTrace();
} catch (ExecutionException e) {
   e.printStackTrace();
}
 System.out.println("所有任务执行完毕");
}}class Task implements Callable {
   @Override
public Integer call() throws Exception {
   System.out.println("子线程在进行计算");
Thread.sleep(3000);
int sum = 0;
for(int i=0;i<100;i++)
sum += i;
return sum;
}}

转载地址:https://blog.csdn.net/weixin_38367817/article/details/103794071 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:六、取消与关闭
下一篇:五、结构化并发应用程序之任务执行(Executor)

发表评论

最新留言

第一次来,支持一个
[***.33.2.18]2022年04月20日 21时16分39秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

最新文章