前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java-多线程:Callable接口和Runnable接口之间的区别

Java-多线程:Callable接口和Runnable接口之间的区别

作者头像
Fisherman渔夫
发布2020-02-18 16:23:40
7K0
发布2020-02-18 16:23:40
举报
文章被收录于专栏:渔夫渔夫

Callable接口和Runnable接口之间的区别

一、源代码角度分析两接口间的区别

想学习好Future设计模式,我们应当首先将Callable、以及Runnable接口之间的区别弄明白: 不妨首先给出他们俩的源代码:

代码语言: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;
}

以及:

代码语言: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();
}

由他们本身的接口定义我们就能够看出它们的区别:

  1. 如上面代码所示,callable的核心是call方法,允许返回值,runnable的核心是run方法,没有返回值
  2. call方法可以抛出异常,但是run方法不行
  3. 因为runnable是java1.1就有了,所以他不存在返回值,后期在java1.5进行了优化,就出现了callable,就有了返回值和抛异常
  4. callable和runnable都可以应用于executors。而thread类只支持runnable

它们的相同点:

  1. 两者都是接口
  2. 两者都需要调用Thread.start启动线程

二、从使用场景来分析两接口间区别:

2.1 Runnnable接口的使用场景

1)传递给线程对象执行任务;

2)作为线程池方法execute()的入口参数来执行任务;

具体的实现又可以细分,具体如下面代码块所示:

代码语言:javascript
复制
/**
 * @author Fisherman
 */
public class TheWayOfUsingRunnable {
    public static void main(String[] args) {
        //1)lambda表达式形式传递给线程构造器
        Runnable runnable1 = () -> {
            System.out.println("我是使用lambda表达式实现的Runnable对象实现 version1");
        };

        Thread thread1 = new Thread(runnable1);
        thread1.start();

        Thread thread1_1 = new Thread(() -> {
            System.out.println("我是使用lambda表达式实现的Runnable对象实现 version2");
        });
        thread1_1.start();

        //2)匿名内部类的方式实现Runnable对象的传入Thread构造器

        new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("我是使用匿名内部类的方式实现的Runnable对象实现");
                    }
                }
        ).start();

        //3)使用实现了Runnable接口的对象实例传入Thread构造器
        RunnableTask runnableTask = new RunnableTask();
        new Thread(runnableTask).start();

        //4)Runnable类以及其子类作为线程任务提交给线程池,通过线程池维护的工作者线程来执行。
        Runnable runnable2 = () -> {
            System.out.println("我是使用lambda表达式实现的Runnable对象实现 不同的是:用于线程池的实现");
        };
        ExecutorService executor = Executors.newCachedThreadPool();
        executor.execute(runnable2);
        executor.shutdown();
    }

    /**RunnableTask
     * Runnable接口子类的实现类:RunnableTask
     */
    private static class RunnableTask implements Runnable{
        @Override
        public void run() {
            System.out.println("实现了Runnable接口的子类的对象实现");
        }

        //额外写一个方法:get
        public String get(){
            return "I am Fisherman.";
        }
    }

}

2.2 Callable接口的使用场景

callable对象实例可以作为线程池的submit()方法入口参数

代码语言:javascript
复制
public class TheWayOfUsingCallable {
    public static void main(String[] args) {
        //callable对象实例可以作为线程池的submit()方法入口参数
        ExecutorService executor = Executors.newCachedThreadPool();
        IntegerCallableTask integerCallableTask = new IntegerCallableTask();
        Future<Integer> future = executor.submit(integerCallableTask);
        executor.shutdown();
        try {
            System.out.println(future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}
class IntegerCallableTask implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        Thread.sleep(1000);
        for (int i = 0; i < 101; i++) {
            sum += i;
        }
        return sum;
    }
}

 从上述代码块的执行结果来看,main线程会一直等到执行完call()方法中的所有代码才会继续执行main线程中接下来的代码(等待发生在方法:future.get())。但是Runnable接口和Callable接口在线程池上的应用实际上是十分类似的。

 但是单单比较Runnable接口和Callable接口的区别意义是不大的,而且也是不够全面的,因为关于比较两个接口的区别问题本身也是在我在学习Future设计模式中提出的问题,所以接下来会分析Future接口以及FutureTask类上Runnable接口和Callable接口的异同,这样一来我们可以对此有一个更深层次的认识;但是不妨,将此内容放在我的另外一篇博客中。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Callable接口和Runnable接口之间的区别
    • 一、源代码角度分析两接口间的区别
      • 二、从使用场景来分析两接口间区别:
        • 2.1 Runnnable接口的使用场景
          • 2.2 Callable接口的使用场景
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档