Runnable和Callable啥时候用?

2023-10-21 22:36
文章标签 callable runnable 啥时候

本文主要是介绍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通知、短信通知这些就启动新线程去干去吧。

更多消息资讯,请访问昂焱数据(https://www.ayshuju.com)

这篇关于Runnable和Callable啥时候用?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/257401

相关文章

【硬刚Java并发】JUC基础(五):实现 Callable 接口

本文是对《【硬刚大数据之学习路线篇】从零到大数据专家的学习指南(全面升级版)》的Java并发部分补充。 1 Callable 接口 Java 5.0 在 java.util.concurrent 提供了一个新的创建执行线程的方式:Callable 接口 Callable 接口类似于 Runnable,两者都是为那些其实例可能被另一个线程执行的类设计的。但是 Runnable 不会返回结果

Java并发编程:Callable和Future使用

在Java中,创建线程一般有两种方式,一种是继承Thread类,一种是实现Runnable接口。然而,这两种方式的缺点是在线程任务执行结束后,无法获取执行结果。我们一般只能采用共享变量或共享存储区以及线程通信的方式实现获得任务结果的目的。 不过,Java中,也提供了使用Callable和Future来实现获取任务结果的操作。Callable用来执行任务,产生结果,而Future用来获得结果。 C

实现多线程有两种方法: Thread类继承和Runnable接口实现

l 创建线程的第一种方式:继承Thread类。 步骤: 1,定义类继承Thread。 2,复写Thread类中的run方法。 目的:将自定义代码存储在run方法。让线程运行。//run();仅仅是对象调用方法。而线程创建了,并没有运行。 3,调用线程的start方法, 该方法两个作用:启动线程,调用run方法。 Demo d = new Demo();//创建好一个线程

【Python报错已解决】`TypeError: ‘numpy.ndarray‘ object is not callable`

引言: 在编程中,你是否遇到过尝试调用一个Numpy数组对象时出现了TypeError: 'numpy.ndarray' object is not callable的报错?这个问题通常是由于误将Numpy数组当成了一个函数来调用。接下来,我们将分析这个问题并提供解决方案。 一、问题描述: 1.1 报错示例: import numpy as np# 创建一个Numpy数组arra

继承Thread和实现Runnable

如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。 实现Runnable接口比继承Thread类所具有的优势: 1):适合多个相同的程序代码的线程去处理同一个资源 2):可以避免java中的单继承的限制 3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立 直接看代码,以下依次为: 1、继承Thread的demo 2

Callable Future Executor

一般通过继承Thread还有实现Runnable,都不可以有返回值,不可以声明检查异常。 Callable和Future,通过ExecutorService的submit方法执行Callable,并返回给Future,这里返回值只有一个,ExecutorService继承自Executor,通过使用Executor执行器来操作。 public class CallableAndFuture {

Callable使用示例

package com.expgiga.JUC;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.FutureTask;/** * 一、创建执行线程的方式三:实现Callable接口。 * 相较于实现Runnab

多线程--Thread和Runnable区别

线程的创建有两种方式,分别是继承Thread类和实现Runnable接口,那么这两种方式有什么相同点,以及区别在何处呢?   首先通过两个实例还看一下他们的相同之处:   实例1:使用继承Thread类    创建子类MultiExtendThread:     public class MultiExtendThread extends Thread {private int

Java多线程(二)——Callable、Future和FutureTask

在上一章节我们介绍了Java实现多线程最常用的两种方式,但是那两种方式实现线程的时候并不能返回线程的执行结果。然而有些场景我们需要得到线程的执行结果,比如要计算每个部门的这个月的工资,然后进行总计(假设有n个部门,计算每个部门的工资需要花费m个小时,计算总计需要k个小时)。那么有以下两种方案供选择“: n个部门工资计算和总计都安排给一个人来做,需要花费n*m+k小时;每个部门工资计算都分别安排给

Java 继承Thread 和 实现Runnable的关联

在java中创建线程的最常用的两种方法 1.继承Thread类 2.继承Runnable接口 但是实现了Runnable接口之后,这个类不能自己启动,需要将其传递给一个Thread实例对象,然后通过Thread对象的start() 方法进行启动,因为只有Thread类中的 native 方法,才能够真正申请系统资源,启动一个单独的线程,启动的结果是这个Thread对象的 run() 方法被调用