前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >并发编程系列之Callable和Runnable的不同?

并发编程系列之Callable和Runnable的不同?

作者头像
SmileNicky
发布2021-09-08 15:04:41
3661
发布2021-09-08 15:04:41
举报
文章被收录于专栏:Nicky's blog

本博客学习要点:

  • 1、了解Runnable的原理和不足
  • 2、掌握怎么使用Callable实现任务
  • 3、对比Runnable和Callable的不同

ps:基于Jdk1.8看源码

1、Runnable入门实例

并发编程系列之Callable和Runnable的不同?在学习并发多线程的过程中,很多读者都知道怎么实现Runnable,下面是一道经典的例子

代码语言:javascript
复制
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中的新特性

代码语言:javascript
复制
@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)、没有返回值 Runnablerun方法是void类型的,没有返回值,虽然可以在实现的run方法里写入日志文件或者修改某个共享的对象的办法,来达到保存线程执行结果的目的,不过这样实现确实比较麻烦。 实际上,在很多情况下执行一个子线程时,我们都希望能得到执行的任务的结果,可是 Runnable 不能返回一个返回值,这是它第一个非常严重的缺陷。
  • (2)不能抛出 checked Exception Runnable是不能抛出 checked Exception的,run方法是不允许在声明throws Exception的, 且run方法内无法 throw 出 checked Exception,除非使用try catch进行处理
代码语言:javascript
复制
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调用

使用线程池的方法:

代码语言:javascript
复制
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的方法:

代码语言:javascript
复制
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

代码语言:javascript
复制
@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 可以了解任务执行情况,或者取消任务的执行

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/09/01 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、Runnable入门实例
  • 2、Runnable有什么缺陷?
  • 3、Runnable 为什么设计成这样?
  • 4、Callable需要怎么调用?
  • 5、Callable 和 Runnable 的不同之处
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档