`
men4661273
  • 浏览: 275638 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Java的Thread,Runnable、Callable、Future、FutureTask、Executors,ExecutorService

阅读更多

定义解释 

 

Runnable:接口,线程任务的接口定义,一个run方法,无返回值,创建的线程无法获取返回值。

Callable<T>:接口,线程任务的接口定义,一个call方法,有返回值,返回值类型为指定的泛型。

Future<T>:接口,是Callable、Runnable(FutureTask可以将Runnable转换为Callable类型)的调度容器,它可以对执行的线程进行取消,查询是否完成,获取结果等操作,get方法获取结果会阻塞,直到任务返回结果。

FutureTask<T>:类,实现RunnableFuture接口的类,RunnableFuture继承了Runnable、Future<T>,所以相当于是实现类Runnable、Callable<T>接口的一个实现类,相当于具有Runnable和Future的功能。

Thread:类,实现Runnable接口的类,所以具有Runnable的特性,它的功能还有包装线程任务,作为异步任务的执行者,管理异步任务。

Executors:类,创建各种线程池,还有将Runnable转换为Callable的方法等。

ExecutorService:接口,各种类型线程池的接口定义。

 

所以创建线程有三种方式:

1、实现Runnable接口,交给Thread实例或者线程池去执行,无法获取任务执行结果。
2、Thread实现了Runnable接口,所以可以继承Thread类,直接执行或者交给线程池去执行,无法获取任务执行结果。
3、实现Callable<T>接口,并使用FutureTask<T>进行包装,交给Thread实例或者线程池去执行,可以获取到任务执行结果,但是使用get获取任务执行结果时会阻塞,直到任务返回结果。
FutureTask可以包装一个Runnable实例,实质上是将Runnable转换成了一个Callable,并赋予默认返回值。
//FutureTask的一个构造方法:
public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
}
 
//Executors的callable方法,返回一个RunnableAdapter实例:
public static <T> Callable<T> callable(Runnable task, T result) {
        if (task == null)
            throw new NullPointerException();
        return new RunnableAdapter<T>(task, result);
}
 
//RunnableAdapter是Executors的静态内部类,实现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;
        }
}
来看下线程的实现方法: 
方法一(TaskA实现Runnable接口):
Thread thread = new Thread(new TaskA());
thread.start();
 
方法二(Task继承Thread类):
TaskB task = new TaskB();
task.start();
 方法三(实现Callable接口结合FutureTask):
TaskC task = new TaskC();
//带有返回值的线程
FutureTask<Integer> future = new FutureTask<Integer>(task);
Thread thread = new Thread(future);
thread.start();
System.out.println("获取Callable任务的返回值:" + future.get());
//FutureTask也可以运行Runnable任务,FutureTask会在构造方法里面将Runnable转换为Callable, 指定的返回值为 线程的返回值
FutureTask<Integer> future1 = new FutureTask<Integer>(new TaskA(), 2);
thread = new Thread(future1);
thread.start();
System.out.println("获取Runnable任务的返回值:" + future1.get());
 补充一个使用线程池调度的方式:
//创建一个同时只能执行一个任务的线程池
ExecutorService service = Executors.newSingleThreadExecutor();
TaskA taskA = new TaskA();
TaskB taskB = new TaskB();
//execute只能执行Runnable类型的任务,没有返回值
service.execute(taskA);
service.execute(taskB);
//submit执行Runnable类型的任务,返回值为null
Future<?> future = service.submit(taskA);
System.out.println("获取Runnable任务的返回值:" + future.get());
future = service.submit(taskA,2);
System.out.println("获取Runnable任务的返回值:" + future.get());
TaskC taskCallable = new TaskC();
future = service.submit(taskCallable);
System.out.println("获取Callable任务的返回值:" + future.get());
 
最后比较以下三种方式的特点:
1、Runnable方式:只提供任务实例, 需要依赖任务调度器执行,无返回值。
2、Thread方式:实现了Runnable接口,可以包装任务实例,并作为任务调度器直接执行,无返回值。也可以说Thread是间接地通过实现Runnable接口才具备了创建线程任务的功能,哈哈。但是由于Thread可以作为线程任务调度执行器,所以他具有线程管理的功能,比如join,interrupt等。
3、Callable方式:跟Runnable相似,但可以获取线程执行的返回值,但是获取返回值时会阻塞,直到线程任务返回。
所以只创建任务的话,一般用Runnable,多个线程之间进行通信交互时,用Thread,需要获取返回值时,用Callable
以上为个人理解,如有不对请拍砖,谢谢~
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics