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

article/2025/4/29 17:00:06

文章目录

      • 1. Runnable接口实例
      • 2. Callable接口原理
      • 3. Callnable接口实例
      • 4. FutureTask是什么?
      • 5. 线程池中 submit() 和 execute() 方法有什么区别?

Runnable接口源码:

@FunctionalInterface
public interface Runnable {// 这个run()方法返回值为void,没有受检异常的异常声明,出现异常只能内部捕获public abstract void run();
}

Callable接口源码:

@FunctionalInterface
public interface Callable<V> {// 这个call()方法有返回值,且声明了受检异常,可以直接抛出Exception异常V call() throws Exception;
}

Runnable接口和Callable接口的区别:

(1) Runnable接口中的唯一抽象方法run()方法没有返回值,Callable接口中的唯一抽象方法call()方法有返回值;

(2) Runnable接口的run()方法没有受检异常的异常声明,即异常只能在内部捕获,不能继续上抛, Callable接口的call()方法声明了受检异常,可直接抛出Exception异常,并且可以不予捕获;

(3) Callable实例不能和Runnable实例一样,直接作为Thread线程实例的target来使用;

(4) 异步执行任务在大多数情况下是通过线程池去提交的,而Runnable接口和Callable接口都可以应用于线程池;

(5) Callable接口支持返回执行结果,此时需要调用FutureTask.get()方法实现,此方法会阻塞主线程直到获取‘将来’结果;当不调用此方法时,主线程不会阻塞!

注意:异步执行任务在大多数情况下是通过线程池去提交的,而很少通过创建一个新的线程去提交(即通过Thread类的方式执行start()方法)。

下面实例解析以上不同点:

1. Runnable接口实例

首先,通过实现Runnable接口的方式创建一个异步执行任务:

public class RunnableTask implements Runnable  {// 线程体:需要线程异步执行的任务@Overridepublic void run() {System.out.println("实现Runnable接口来编写异步执行任务");// run()方法内出现异常,只能捕获不能直接抛出try {Thread.sleep(1000) ;} catch (InterruptedException e) {e.printStackTrace();}}
}

方式1:通过Thread类创建线程,将Runnable接口的实现类作为Thread线程实例的target来使用,执行异步任务

public class RunnableDemo {public static void main(String[] args) {Runnable target = new RunnableTask();// 通过Thread类创建一个新线程,并启动Thread thread = new Thread(target);thread.start();}
}

方式2:通过线程池创建线程,并提交异步执行任务

public class RunnableDemo2 {// 通过线程池创建3个线程private static ExecutorService executorService = Executors.newFixedThreadPool(3);public static void main(String[] args) throws ExecutionException, InterruptedException {// 1、通过线程池的execute()方法提交异步执行任务,没有返回结果executorService.execute(new RunnableTaskDemo());// 2、通过线程池的submit()方法提交异步执行任务,有返回结果Future<?> submit = executorService.submit(new RunnableTaskDemo());// 获取返回结果System.out.println(submit.get()); // null}
}

2. Callable接口原理

Callable接口实例没有办法作为Thread线程实例的target来使用。既然如此,那么该如何使用Callable接口创建线程呢?因此需要一个在Callable接口与Thread线程之间起到搭桥作用的重要接口。

1、RunnableFuture接口源码:

public interface RunnableFuture<V> extends Runnable, Future<V> {void run();
}

RunnableFuture接口实现了2个目标:

(1) RunnableFuture通过继承Runnable接口,从而保证了其实例可以作为Thread线程实例的target目标;
(2) RunnableFuture通过继承Future接口,从而保证了可以获取未来的异步执行结果。

那有些同学可能疑惑了,Future接口又是什么?Future接口至少提供了3大功能:

(1) 能够取消异步执行中的任务;
(2) 判断异步任务是否执行完成;
(3) 获取异步任务完成后的执行结果;

2、Future接口的源码:

public interface Future<V> {// 取消异步执行中的任务boolean cancel(boolean mayInterruptIfRunning);boolean isCancelled();// 判断异步任务是否执行成功boolean isDone();// 获取异步任务完成后的结果V get() throws InterruptedException, ExecutionException;V get(long timeout, TimeUnit unit)throws InterruptedException, ExecutionException, TimeoutException;
}

Future接口中的方法:

  • get():获取异步任务执行的结果。注意,这个方法的调用是阻塞性的。如果异步任务没有执行完成,异步结果获取线程(调用线程)会一直被阻塞,一直阻塞到异步任务执行完成,其异步结果返回给调用线程。

  • get(Long timeout,TimeUnit unit):设置时限,(调用线程)阻塞性地获取异步任务执行的结果。该方法的调用也是阻塞性的,但是结果获取线程(调用线程)会有一个阻塞时长限制,不会无限制地阻塞和等待,如果其阻塞时间超过设定的timeout时间,该方法将抛出异常,调用线程可捕获此异常。

  • boolean isDone():获取异步任务的执行状态。如果任务执行结束,就返回true。

  • boolean isCancelled():获取异步任务的取消状态。如果任务完成前被取消,就返回true。

  • boolean cancel(boolean mayInterruptRunning):取消异步任务的执行。

总体来说,Future是一个对异步任务进行交互、操作的接口。但是Future仅仅是一个接口,通过它没有办法直接完成对异步任务的操作,JDK提供了一个默认的实现类——FutureTask。

3、FutureTask类 :

RunnableFuture只是一个接口,无法直接创建对象,如果需要创建对象,就需用到它的实现类——FutureTask。所以说,FutureTask类才是真正的在Thread与Callable之间搭桥的类。FutureTask类实现了RunnableFuture接口,而RunnableFuture接口又继承了Runnable接口和Future接口,因此它可以作为Thread线程实例的target目标,也可以获取异步执行结果;

public class FutureTask<V> implements RunnableFuture<V> {}

FutureTask内部有一个Callable类型的成员——callable实例属性:

private Callable<V> callable;

callable实例属性用来保存并发执行的Callable类型的任务,并且callable实例属性需要在FutureTask实例构造时进行初始化:

public FutureTask(Callable<V> callable) {if (callable == null) throw new NullPointerException();// callable实例属性需要在FutureTask实例构造时进行初始化this.callable = callable;this.state = NEW;       // ensure visibility of callable
}
public FutureTask(Runnable runnable, V result) {this.callable = Executors.callable(runnable, result);this.state = NEW;       // ensure visibility of callable
}

FutureTask类实现了Runnable接口,在其run()方法的实现版本中会执行callable成员的call()方法:

public void run() {if (state != NEW ||!UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread()))return;try {Callable<V> c = callable;if (c != null && state == NEW) {V result;boolean ran;try {// 在run()方法中执行call()方法result = c.call();ran = true;} catch (Throwable ex) {// ...}if (ran) set(result);}} finally {// ...}
}

FutureTask内部还有另一个非常重要的Object类型的成员——outcome实例属性:

private Object outcome;

FutureTask的outcome实例属性用于保存callable成员call()方法的异步执行结果。在FutureTask类的run()方法完成callable成员的call()方法的执行之后,其结果将被保存在outcome实例属性中,供FutureTask类的get()方法获取。
在这里插入图片描述

3. Callnable接口实例

首先,通过实现Runnable接口的方式创建一个异步执行任务:

public class CallableTaskDemo implements Callable {// call()方法有返回值,并且可以抛出Exception异常@Overridepublic String call() throws Exception {System.out.println("实现Callable接口来编写异步执行任务");Thread.sleep(1000);return "返回线程执行结果";}
}

方式1:通过Thread类创建线程执行异步任务

public class CallableDemo {public static void main(String[] args) throws ExecutionException, InterruptedException {// 创建异步执任务实例Callable callable = new CallableTaskDemo();// 初始化callable实例属性FutureTask futureTask = new FutureTask(callable);// 创建线程执行异步任务Thread thread = new Thread(futureTask);thread.start();System.out.println("获取异步执行任务结果:"+futureTask.get());// 获取异步执行任务结果:返回线程执行结果}
}

方式2:通过线程池创建线程,并提交异步执行任务:

public class CallableDemo2 {// 通过线程池创建3个线程private static ExecutorService executorService = Executors.newFixedThreadPool(3);public static void main(String[] args) throws ExecutionException, InterruptedException {// 通过线程池的submit()方法提交异步执行任务,有返回结果Future submit = executorService.submit(new CallableTaskDemo());// 获取返回结果System.out.println(submit.get());}
}

4. FutureTask是什么?

Future是一个对异步任务进行交互、操作的接口。但是Future仅仅是一个接口,通过它没有办法直接完成对异步任务的操作,JDK提供了一个默认的实现类——FutureTask。

对于Calleble来说,Future和FutureTask均可以用来获取任务执行结果,不过Future是个接口,FutureTask是Future的具体实现,而且FutureTask还间接实现了Runnable接口,也就是说FutureTask可以作为Runnable任务提交给线程池。

5. 线程池中 submit() 和 execute() 方法有什么区别?

两者都是将一个线程任务添加到线程池中并执行;
1、excutor没有返回值,submit有返回值,并且返回执行结果Future对象
2、excutor不能提交Callable任务,只能提交Runnable任务,submit两者任务都可以提交
3、在submit中提交Runnable任务,会返回执行结果Future对象,但是Future调用get方法将返回null(Runnable没有返回值)


http://chatgpt.dhexx.cn/article/3pGSBply.shtml

相关文章

Callable 接口

Callable 接口 是 java.util.concurrent.下的一个泛型接口 , 只有一个call () 方法 , 它是有返回值的 , 我们可以获取多线程执行的结果 , 使用 Callable接口 和 FutureTask 的组合 , 可以实现利用 FutureTask 来跟踪异步计算的结果 获取多线程的方式 1. 继承 Thread 类 2. 实…

Java用Callable接口创建线程

一、概述 使用Callable接口创建线程能够返回数据。与Runnable接口创建线程的方式有点类似&#xff0c;也是需要通过Thread类来创建线程。由于Thread类的构造函数中没有Callable接口&#xff0c;选用了FutureTask类来作为连接创建线程。  FutureTask类实现了RunnableFuture接口…

JUC-多线程(5.获得线程的第三种方式)学习笔记

文章目录 获得线程的第三种方式 &#xff1a; Callable接口 1. 前言1. 获得多线程的方法几种&#xff1f;2. 以下两种获得线程的方式的异同 2. 使用1. 重写 call 方法2.创建线程3.获取返回值 3. 原理1. 简述2. 解释3. 结论 获得线程的第三种方式 &#xff1a; Callable接口 1.…

Callable接口

文章目录 Callable概述Future 接口FutureTask使用 Callable 和 Future小结(重点) Callable概述 目前我们学习了有两种创建线程的方法-一种是通过创建 Thread 类&#xff0c;另一种是通过使用 Runnable 创建线程。但是&#xff0c;Runnable 缺少的一项功能是&#xff0c;当线程…

webshell管理工具之中国蚁剑

实验环境物理机即可 实验工具&#xff1a;中国蚁剑&#xff0c;phpstudy,dvwa网站 一&#xff1a;打开phpstudy开启apache和mysql 1&#xff1a;将dvwa网站放到www目录下 2&#xff1a;用浏览器进行访问 3&#xff1a;登录dvwa网站进行低等级下的文件上传 4&#xff1a;编写…

WebSell管理工具--中国蚁剑安装教程以及初始化

简介&#xff1a;中国蚁剑是一款开源的跨平台WebShell网站管理工具 蚁剑的下载安装&#xff1a; GitHub项目地址&#xff1a;https://github.com/AntSwordProject/ Windows下载安装&#xff1a; 百度网盘下载链接&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1A5wK…

15 一句话代码 中国蚁剑 中国蚁剑

title 文章目录 前言一、一句话代码 webshell php.php post 注入 二、中国蚁剑 &#xff08;需要下载两个 1&#xff1a;软件 2&#xff1a;解释器&#xff09;三、Burp &#xff08;burp_suite_pro_v2021.8.2&#xff09;4.更新的话 前言 提示&#xff1a; 123 一、一句话代…

VMware之kali安装中国蚁剑

简介 中国蚁剑是一款开源的跨平台网站管理工具&#xff0c;它主要面向于合法授权的渗透测试安全人员以及进行常规操作的网站管理员。是一款非常优秀的webshell管理工具,其核心是当年的中国菜刀。中国蚁剑推崇模块化的开发思想&#xff0c;遵循开源&#xff0c;其主要核心功能主…

蚁剑连接php3,利用中国蚁剑无文件连接 phpstudy 后门方法

利用中国蚁剑无文件连接 phpstudy 后门方法 0x01 描述 Phpstudy 是一款 PHP 调试环境的程序集成包, 集成了最新的 Apache,PHP,phpMyAdmin,ZendOptimizer 等多款软件一次性安装, 无需配置, 即装即用. 由于其免费且方便的特性, 在国内有着近百万的 PHP 语言学习者, 开发者用户. 后…

WebShell --中国蚁剑,黑客之剑

文章目录 一、介绍1.1 简介1.2 编码/解码器 二、下载安装三、使用3.1 管理Webshell3.2 自定义UA3.2.1 UA更改 方法一3.2.2 UA更改 方法二 声明&#xff1a;请于合法授权环境下进行使用&#xff0c;请勿用于非法操作&#xff01; 一、介绍 1.1 简介 开源、跨平台网站管理工具&a…

蚁剑连接php3,中国蚁剑antSword RCE漏洞,建议所有用户升级

4月12日凌晨,有用户在中国蚁剑GitHub上提交了issue,称发现中国蚁剑存在XSS漏洞,借此可引起RCE。据悉,该漏洞是因为在webshell远程连接失败时,中国蚁剑会返回错误信息,但因为使用的是html解析,导致xss漏洞。 当通过中国蚁剑连接webshell,出现连接失败情况时,中国蚁剑会…

【简单工具】中国蚁剑V2.0下载安装到上手

目录 1 安装及设置1.1 下载1.2 安装1.3 相关设置 2 第一个Shell2.1 实验环境2.2 实验步骤2.3 思考 3 总结参考文献 1 安装及设置 1.1 下载 下载蚁剑加载器。在蚁剑官方github下载&#xff0c;网址为https://github.com/AntSwordProject/AntSword-Loader&#xff0c;根据自己系…

中国蚁剑的下载以及安装教程

一&#xff0c;中国蚁剑下载 唯一官方github下载地址&#xff1a; AntSwordProject GitHub 加载器&#xff1a; GitHub - AntSwordProject/AntSword-Loader: AntSword 加载器 核心源码&#xff1a; GitHub - AntSwordProject/antSword: 中国蚁剑是一款跨平台的开源网站管…

攻防兼备:中国蚁剑使用指南及特征流量

中国蚁剑是菜刀的升级版本&#xff0c;线现下主流的Webshell连接工具之一&#xff0c;有着较广泛的使用&#xff0c;本篇文章会教给大家蚁剑的使用方法以及不同加密方式的流量特征&#xff0c;兼顾攻防两端。 蚁剑下载安装参考&#xff1a;中国蚁剑(antSword)下载、安装、使用…

中国蚁剑下载安装教程

启动中国蚁剑 1 、 下载主程序 文件名&#xff1a;antSword.zip 链接&#xff1a; https://pan.baidu.com/s/1wRmj_cB1sLkJ_npRCYO8Xw 提取码&#xff1a;8888 下载以后解压&#xff0c;比如放在 E:\dev_runApp\security\antsword\antSword-master 如下图所示&#xff1a; …

中国蚁剑下载和安装

既然都听说过中国蚁剑&#xff0c;就不夸啦~~ 下载地址 AntSwordProject GitHub 如果gitup进不去&#xff0c;附上百度网盘连接&#xff1a;链接&#xff1a;https://pan.baidu.com/s/163nL2VXFNQsBmzrpWVcNXQ?pwd6666 提取码&#xff1a;6666 解压后就可以直接打开 运行后…

中国蚁剑 配置使用

1.编写一句话木马&#xff0c;并命名为muma.php 2&#xff0e;利用靶机的文件上传漏洞&#xff0c;将此木马文件&#xff08; Webshell )上传至靶机 1&#xff09;打开dvwa网站 2&#xff09;成功登录DVWA网站后&#xff0c;在网站主页左侧菜单选择 DVWA Security&#xff0c;…

中国蚁剑运用

访问之前创建的dvwa靶场 更改安全等级为low并且提交 写一句话马 <?php eval($_POST[cmd]); ?> 生成文件名为shell.php 上传此文件 显示成功 获得上传路径 打开中国蚁剑 右键空白处选择添加数据 URL地址为之前获得的路径地址 连接密码输入写的shell.php中内容cm…

中国蚁剑(AntSword)安装

安装 首先&#xff0c;蚁剑分为两个部分&#xff0c;一个是核心源码&#xff0c;另一个是加载器&#xff0c;所以我们需要下载源码和加载器 源码&#xff1a;https://github.com/AntSwordProject/antSword/releases/tag/2.1.14加载器&#xff1a;https://github.com/AntSword…

中国蚁剑安装

中国蚁剑安装 一、下载中国蚁剑安装包 1、下载地址&#xff1a; https://github.com/AntSwordProject/ https://github.com/AntSwordProject/AntSword-Loader2、选择版本 二、kali系统下安装步骤 一、上传你所下载的linux 版本的中国蚁剑 1、打开kali终端 找到你上传的中…