Java中的Runnable、Callable、Future、FutureTask的区别与示例

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

Runnable

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

public interface Runnable {
    public abstract void run();
}

Callable

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

public interface Callable<V> {

    V call() throws Exception;
}

可以看到,这是一个泛型接口,call()函数返回的类型就是客户程序传递进来的V类型。 Executor就是Runnable和Callable的调度容器,Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果、设置结果操作。get方法会阻塞,直到任务返回结果( Future简介 )。Future声明如下 :

public interface Future<T>
{
    V get() throws ...;
    V get(long timeout, TimeUnit unit) throws ...;
    void cancle(boolean mayInterrupt);
    boolean isCancelled();
    boolean isDone();
}
具体的实现类为java.util.concurrent.FutureTask<V>。

FutureTask

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

public class FutureTask<V> implements RunnableFuture<V>
   RunnableFuture

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

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

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
  }
可以看到,Runnable注入会被Executors.callable()函数转换为Callable类型,即FutureTask最终都是执行Callable类型的任务。该适配函数的实现如下 :
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;
    }
  }
      由于FutureTask实现了Runnable,因此它既可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行。并且还可以直接通过get()函数获取执行结果,该函数会阻塞,直到结果返回。

简单示例

package com.thread;

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;


/**
 * Runnable和Callable的区别
 * Runnable没有返回值
 * Callable有返回值,值是通过Future获得的。
 * 
 * FutureTask是一个RunnableFuture<V>,而RunnableFuture实现了Runnbale又实现了Futrue<V>这两个接口,
  可以包装Runnable和Callable<V>, 由构造函数注入依赖。
 * @author hadoop
 *
 */
public class RunnableFutureTask {
    static  ExecutorService mExecutor = Executors.newSingleThreadExecutor();
    
    /**
     * 效率低下的斐波那契数列,耗时操作。这里没有引用外部共享域,fibc方法是线程安全的,不用考虑同步
     * @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);
    }
    
    /**
     * Runnable,无返回值
     */
    static void runnableDemo(){
    	 new Thread(
    	    new Runnable() {
				@Override
				public void run() {
					System.out.println("Runnable demo:" + fibc(20));  
				}
			} 
    	).start();
    }
    
    
    /**
     * 其中Runnable实现的是void run()方法,无返回值;
     * Callable实现的是V call()方法,并且可以返回执行结果。
     * 其中Runnable可以提交给Thread来包装下,直接启动一个线程来执行,而Callable则一般都是提交给ExecutorService来执行
     */
    static void futureDemo(){
    	 try {
    		 /**
    		  * 提交Runnable则没有返回值,futurn没有数据
    		  * 使用submit提交任务会返回Future对象,而使用execute没有返回值。
    		  * submit提交Runnable任务本质上也是转化为Callable去执行
    		  */
			Future<?>  result = mExecutor.submit(new Runnable() {
				@Override
				public void run() {
				   fibc(20);	  
				}
			});
			System.out.println("future result from runnable:" + result.get());
			
			
			
			/**
			 * 提交Callable,有返回值,future中能够获取返回值
			 */
			Future<Integer> result2 = mExecutor.submit(new Callable<Integer>(){
				@Override
				public Integer call() throws Exception {
					// TODO Auto-generated method stub
					return fibc(20);
				}
			});
			System.out.println("future result from  callable:" + result2.get());
			
			
			/**
			 * FutureTask是一个RunnableFuture<V>,而RunnableFuture实现了Runnbale又实现了Futrue<V>这两个接口
			 * 同时包装了Runnable和Callable<V>, 由构造函数注入依赖。
			 * Runnable注入会被Executors.callable()函数转换为Callable类型,即FutureTask最终都是执行Callable类型的任务
			 */
			FutureTask<Integer> futureTask = new FutureTask<Integer>(
					new Callable<Integer>() {
							@Override
							public Integer call() throws Exception {
								// TODO Auto-generated method stub
								return fibc(20);
							}
			});
			//提交futureTask
			mExecutor.submit(futureTask);
			System.out.println("future result from futureTask:" + futureTask.get());
			
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
            e.printStackTrace();
		}
    }
    
    
    public static void main(String[] args) {
		  runnableDemo();
		  futureDemo();
		  
		    System.out.println("已经开启所有的子线程");  
		    mExecutor.shutdown();  
	        System.out.println("shutdown():启动一次顺序关闭,执行以前提交的任务,但不接受新任务。");  
	        while(true){  
	            if(mExecutor.isTerminated()){  
	                System.out.println("所有的子线程都结束了!");  
	                break;  
	            }  
	        }  
	}
}







  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

斗者_2013

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值