Runnable和Callable啥时候用?

编程入门 行业动态 更新时间:2024-10-18 06:13:59

<a href=https://www.elefans.com/category/jswz/34/1733842.html style=Runnable和Callable啥时候用?"/>

Runnable和Callable啥时候用?

提到 Java 就不得不说多线程了,就算你不想说,面试官也得让你说呀,对不对。那说到多线程,就不得提线程了(这不废话吗)。那说到线程,就不得不说RunnableCallable这两个家伙了。

说熟悉也是真熟悉,在刚学习多线程的时候,第一个例子大概就是下面这样子的。

new Thread(new Runnable() {@Overridepublic void run() {System.out.println("执行线程" + Thread.currentThread().getName());}
}).start();

    java编程时,有时会Runnable的身影,有时还会看到Callable的身影,这两位到底是什么,又有什么区别,什时候应该用 Runnable,什么时候又应该用 Callable。今天我们来看一下

Runnable

自从Java诞生,Runnable就存在了,元老中的元老了,在 1.5之前,如果你想使用线程,那必须要实现自 Runnable。因为到了 JDK1.5,JDK 才加入了Callable

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

        @FunctionalInterface标明这个接口是一个函数式接口。函数式接口是在 JDK8才加入的,为的就是实现函数式编程,就那种Lambada表达式。所以在 JDK1.7中,是没有@FunctionalInterface修饰的,简简单单。我们找到 JDK1.7的 Ruunable实现,是下面这样子。

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

        如果一个线程类要实现 Runnable 接口,则这个类必须定义一个名为 run 的无参数方法。实现了 Runnable 接口的类可以通过实例化一个 Thread 实例,并将自身作为目标传递来运行。

举个例子,首先定义一个RunnableThread类,并实现自(implements)Runnable接口,然后重写 run方法。

public class RunnableThread implements Runnable{@Overridepublic void run() {System.out.println("当前线程名称"+ Thread.currentThread().getName());}
}

启动代码如下:

RunnableThread runnableThread = new RunnableThread();
Thread thread = new Thread(runnableThread);
thread.start();

Callable

        Callable是在 JDK1.5才加入的,弥补 Runnable没有返回值的缺陷。

@FunctionalInterface
public interface Callable<V> {V call() throws Exception;
}

        和 Runnable类似的,@FunctionalInterface也是后来加入的,可以不考虑,只是为了函数式写法。Callable接口只有一个 call方法,并且有一个泛型返回值,可以返回任何类型。

// Callable示例
public class MyCallable implements Callable<Integer> {@Overridepublic Integer call() throws Exception {System.out.println("This is a Callable task.");return 123; // 返回一个整数}
}

调用代码如下:

ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Integer> future = executor.submit(new MyCallable());
Integer result = future.get(); // 获取任务执行的结果

RunnableCallable的区别

RunnableCallable都是Java中用于多线程编程的接口,它们之间的主要区别在于:

  1. 返回值:Runnablerun()方法没有返回值,而Callablecall()方法有一个泛型类型的返回值。

  2. 异常抛出:Runnablerun()方法不能抛出异常,而Callablecall()方法可以抛出异常,需要使用try-catch语句或者将异常向上抛出。

  3. 使用方式:Runnable通常作为启动线程的参数使用,而Callable通常作为提交任务到线程池中的参数使用,可以获取任务执行的结果。

RunnableCallable使用注意事项

在使用RunnableCallable时,需要注意以下几个事项:

  1. 返回值处理:Runnablerun()方法没有返回值,而Callablecall()方法有一个泛型类型的返回值。对于Callable任务,可以通过Future对象获取任务执行的结果。在获取结果时,可以选择等待任务执行完成(调用future.get())或者设置超时时间(调用future.get(timeout, unit))。

  2. 异常处理:Runnablerun()方法不能抛出异常,而Callablecall()方法可以抛出异常。在使用Callable时,需要注意捕获可能抛出的异常,并进行适当的处理。

  3. 线程池使用:通常情况下,Runnable任务适合使用Thread启动,而Callable任务适合使用线程池提交。线程池能够更好地管理和复用线程资源,提高程序的性能和效率。

  4. 任务取消:可以通过Future对象的cancel()方法取消正在执行的任务。但是需要注意,如果任务已经开始执行,可能无法立即中止。此外,如果任务已经完成或取消,再次调用cancel()方法将返回false

  5. 并发安全:在多线程环境下使用RunnableCallable时,需要注意数据的并发安全性。确保共享数据访问的正确性,可以采用同步机制(如synchronized关键字、Lock接口)或使用并发容器(如ConcurrentHashMapCopyOnWriteArrayList等)来保证线程安全。

  6. 线程间通信:RunnableCallable任务之间可以通过共享变量或者线程间通信机制进行交互。例如,可以使用wait()notifyAll()方法实现等待和唤醒的机制。

RunnableCallable如何取舍


        取舍的基本原则就是需不需要返回值,如果不需要返回值,那直接就选 Runnable,不用犹豫。如果有返回值的话,那更不用犹豫,不要想着借助共享变量的方式。 Runnable是不接受抛出异常的,Callable可以抛出异常。

        Runnable适合那种纯异步的处理逻辑。比如每天定时计算报表,将报表存储到数据库或者其他地方,只是要计算,不需要马上展示,展示内容是在其他的方法中单独获取的。

        比如那些非核心的功能,当核心流程执行完毕后,非核心功能就自己去执行吧,至于成不成功的,不是特别重要。例如一个购物下单流程,下单、减库存、加到用户的订单列表、扣款是核心功能,之后的发送APP通知、短信通知这些就启动新线程去干去吧。

更多消息资讯,请访问昂焱数据()

更多推荐

Runnable和Callable啥时候用?

本文发布于:2023-12-05 20:45:45,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1665245.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:Runnable   Callable

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!