并发编程系列之Callable和Runnable的不同?
Posted smileNicky
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了并发编程系列之Callable和Runnable的不同?相关的知识,希望对你有一定的参考价值。
本博客学习要点:
- 1、了解Runnable的原理和不足
- 2、掌握怎么使用Callable实现任务
- 3、对比Runnable和Callable的不同
ps:基于Jdk1.8看源码
1、Runnable入门实例
并发编程系列之Callable和Runnable的不同?在学习并发多线程的过程中,很多读者都知道怎么实现Runnable,下面是一道经典的例子
public static void main(String[] args) {
Thread t = new Thread(new RunnableTask ());
t.start();
}
static class RunnableTask implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
2、Runnable有什么缺陷?
对于Callable,可能有些读者就不是很熟悉了,在上一章节多线程基础知识的学习中,我们知道了Runnable和Callable其实可以用来表示多线程的任务,而在多线程的方法中,我们是没有找到可以传入Callable对象的具体方法的
然后Callable要怎么使用?为什么要设计出Callable?Runnable是不是有什么缺陷?ok,还是先看看Runnable的源码:可以看出Runable其实就是一个接口,同时使用了java的函数式函数@FunctionalInterface
,所以是可以支持lambda表达式的,这是jdk8中的新特性
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}
然后Runnable有什么缺陷?
-
(1)、没有返回值
Runnable
的run
方法是void
类型的,没有返回值,虽然可以在实现的run
方法里写入日志文件或者修改某个共享的对象的办法,来达到保存线程执行结果的目的,不过这样实现确实比较麻烦。
实际上,在很多情况下执行一个子线程时,我们都希望能得到执行的任务的结果,可是 Runnable 不能返回一个返回值,这是它第一个非常严重的缺陷。 -
(2)不能抛出 checked Exception
Runnable是不能抛出 checked Exception的,run方法是不允许在声明throws Exception的, 且run方法内无法 throw 出 checked Exception,除非使用try catch进行处理
Runnable runnable = new Runnable() {
/**
* run方法是不允许在声明throws Exception的,
* 且run方法内无法 throw 出 checked Exception,
* 除非使用try catch进行处理
*/
@Override
public void run() {
try {
throw new IOException();
}catch (IOException e) {
e.printStackTrace();
}
}
};
}
3、Runnable 为什么设计成这样?
知道了Runnable的缺陷后,我们可能会好奇为什么之前这样设计?假设run方法可以抛出checked Exception,也可以有返回值,也无济于事,因为run方法调用,我们是通过Thread类或者是线程池IUC的api去调用的,所以我们是不可以在外层就捕获到Exception的。
就算它能有一个返回值,我们也很难把这个返回值利用到,如果真的想弥补 Runnable 的这两个缺陷,可以用下面的补救措施,也就是使用 Callable
4、Callable需要怎么调用?
调用Callable任务有两种使用方法,一种是使用线程池,另外一种是使用FutureTask调用
使用线程池的方法:
public static void callableExecutorService() throws InterruptedException, ExecutionException {
ExecutorService service = new ThreadPoolExecutor(10, 10,
60L, TimeUnit.SECONDS,
new ArrayBlockingQueue(10));
Future<Integer> future = service.submit(new CallableTask());
Thread.sleep(3000);
System.out.println("future is done?" + future.isDone());
if (future.isDone()) {
System.out.println("callableTask返回参数:"+future.get());
}
service.shutdown();
}
static class CallableTask implements Callable<Integer> {
@Override
public Integer call() {
return ThreadLocalRandom.current().ints(0, (99 + 1)).limit(1).findFirst().getAsInt();
}
}
使用FutureTask的方法:
public static void callableFutureTask() throws InterruptedException, ExecutionException {
CallableTask task = new CallableTask();
FutureTask futureTask = new FutureTask(task);
Thread t = new Thread(futureTask);
t.start();
Thread.sleep(1000L);
System.out.println("task result:" + futureTask.get());
}
static class CallableTask implements Callable<Integer> {
@Override
public Integer call() {
return ThreadLocalRandom.current().ints(0, (99 + 1)).limit(1).findFirst().getAsInt();
}
}
5、Callable 和 Runnable 的不同之处
对于Runnable前面已经介绍过,使用现在翻下Callable的源码:可以看出Callable本质也是一个接口,也和Runnable一样也支持函数式接口,不过不同的是Callable使用了V
这个泛型,所以是可以支持返回值的,而且也有throws Exception,所以可以获取到checked Exception
@FunctionalInterface
public interface Callable<V> {
/**
* 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;
}
ok,可以归纳一下Callable和Runnable的不同:
1、方法名,Runnable的方法名是run,而Callable的方法名是call
2、抛出异常,Runnable不支持抛出异常,而Callable支持抛出checked Exception
3、返回值,Runnable不支持返回值,而Callable是支持返回值的
4、是否支持Future使用,Runnable不支持,Callable是可以组合线程池或者FutureTask一起使用,同时可以将结果返回给Future,通过 Future 可以了解任务执行情况,或者取消任务的执行
以上是关于并发编程系列之Callable和Runnable的不同?的主要内容,如果未能解决你的问题,请参考以下文章
Java并发多线程编程——Callable和Runnable接口的区别
Callable, Runnable, Future, FutureTask