并发编程之创建线程的几种方式以及运行的详细解析

3.1 创建和运行线程

方法一,直接使用 Thread

// 创建线程对象
Thread t = new Thread() {public void run() {// 要执行的任务}
};
// 启动线程
t.start();

例如:

// 构造方法的参数是给线程指定名字,推荐
Thread t1 = new Thread("t1") {@Override// run 方法内实现了要执行的任务public void run() {log.debug("hello");}
};
t1.start();

输出:

19:19:00 [t1] c.ThreadStarter - hello

方法二,使用 Runnable 配合 Thread

把【线程】和【任务】(要执行的代码)分开

  • Thread 代表线程

  • Runnable 可运行的任务(线程要执行的代码)

Runnable runnable = new Runnable() {public void run(){// 要执行的任务}
};
// 创建线程对象
Thread t = new Thread( runnable );
// 启动线程
t.start(); 

例如:

// 创建任务对象
Runnable task2 = new Runnable() {@Overridepublic void run() {log.debug("hello");}
};
// 参数1 是任务对象; 参数2 是线程名字,推荐
Thread t2 = new Thread(task2, "t2");
t2.start();

输出:

9:19:00 [t2] c.ThreadStarter - hello

Java 8 以后可以使用 lambda 精简代码

// 创建任务对象
Runnable task2 = () -> log.debug("hello");
// 参数1 是任务对象; 参数2 是线程名字,推荐
Thread t2 = new Thread(task2, "t2");
t2.start();
Thread 与 Runnable 的关系

分析 Thread 的源码,理清它与 Runnable 的关系

//Runnable源码
public interface Runnable {public abstract void run();
}
//Thread源码(部分)
public class Thread implements Runnable {/* What will be run. */private Runnable target;public Thread(Runnable target) {init(null, target, "Thread-" + nextThreadNum(), 0);}private void init(ThreadGroup g, Runnable target, String name,long stackSize, AccessControlContext acc,boolean inheritThreadLocals) {//...this.target = target;//...}@Overridepublic void run() {if (target != null) {target.run();}}
小结
  • 方法1 是把线程和任务合并在了一起,方法2 是把线程和任务分开了

  • 用 Runnable 更容易与线程池等高级API 配合

  • 用 Runnable 让任务类脱离了 Thread 继承体系,更灵活

方法三,FutureTask 配合 Thread

FutureTask 能够接收 Callable 类型的参数,用来处理有返回结果的情况

// 创建任务对象
FutureTask<Integer> task3 = new FutureTask<>(() -> {log.debug("hello");return 100;
});
// 参数1 是任务对象; 参数2 是线程名字,推荐
new Thread(task3, "t3").start();
// 主线程阻塞,同步等待 task 执行完毕的结果
Integer result = task3.get();
log.debug("结果是:{}", result);

输出

19:22:27 [t3] c.ThreadStarter - hello
19:22:27 [main] c.ThreadStarter - 结果是:100

源码分析

//FutureTask源码(部分)
public class FutureTask<V> implements RunnableFuture<V> {/** The underlying callable; nulled out after running */private Callable<V> callable;/** The result to return or exception to throw from get() */private Object outcome; // non-volatile, protected by state reads/writespublic FutureTask(Callable<V> callable) {if (callable == null)throw new NullPointerException();this.callable = callable;this.state = NEW;       // ensure visibility of callable}public void run() {//...try {Callable<V> c = callable;if (c != null && state == NEW) {V result;boolean ran;try {result = c.call();ran = true;} catch (Throwable ex) {result = null;ran = false;setException(ex);}if (ran)set(result);}}//...}protected void set(V v) {if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {outcome = v;UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final statefinishCompletion();}}public V get() throws InterruptedException, ExecutionException {int s = state;if (s <= COMPLETING)s = awaitDone(false, 0L);return report(s);}private V report(int s) throws ExecutionException {Object x = outcome;if (s == NORMAL)return (V)x;if (s >= CANCELLED)throw new CancellationException();throw new ExecutionException((Throwable)x);}
}    
//Callable源码
@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;
}

说明:

  • FutureTask内置了一个Callable对象,初始化方法将指定的Callable赋给这个对象。

  • FutureTask实现了Runnable接口,并重写了Run方法,在Run方法中调用了Callable中的call方法,并将返回值赋值给outcome变量

  • get方法就是取出outcome的值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/540392.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql中用逗号隔开的某字段,如何判断其他表的字段值是否在这个字段中

因为要增加需求&#xff0c;需要将线上表中老数据&#xff0c;修改为新数据的规则。 线上两张表&#xff0c;sequence_number中is_use有3作废、2到期状态&#xff0c;需要根据这个状态和school_ai_authorization中的is_deleted修改新增的state字段。 sequence_number表结构&…

Mint_21.3 drawing-area和goocanvas的FB笔记(八)

FreeBASIC与TinyPTC绘图 TinyPTC是个操作非常简单的库&#xff0c;有各平台用的版本&#xff0c;linux平台版本又分为sdl版和gfx版&#xff0c;gfx版本比sdl版本速度快&#xff0c;尺寸不大&#xff0c;可操作的函数只有3个&#xff1a; ptc_open, ptc_update, ptc_close …

若依框架的使用

文章目录 0,项目介绍项目架构项目原型 1,前端2,后端3,数据库4,测试5,二开5.1 创建新module5.2 添加pom依赖5.3 添加测试代码5.4 测试5.5 跳过验证(后期要改回来)5.6 修改前端路由5.7 添加前端菜单5.7.1 一级菜单5.7.2 二级菜单5.7.3 测试 5.8 课程列表-后台5.8.0 项目结构5.8.1…

VisionPro安装教程

安装 前言: 私信获取软件安装包 一、 关闭电脑管家 关闭防火墙 二、 解压此文件 三、 解压完成 找到DISK1目录 在setup.exe文件 右键 以管理员身份运行 四、 等待 五、 点击 “下一步 六、 点击 下一步 七、 接受条款 点击下一步 八、 填写邮箱 九、 点击下一…

案例分析篇01:软件架构设计考点架构风格及质量属性(2024年软考高级系统架构设计师冲刺知识点总结系列文章)

专栏系列文章推荐: 2024高级系统架构设计师备考资料(高频考点&真题&经验)https://blog.csdn.net/seeker1994/category_12593400.html 【历年案例分析真题考点汇总】与【专栏文章案例分析高频考点目录】(2024年软考高级系统架构设计师冲刺知识点总结-案例分析篇-…

pytorch(十)循环神经网络

文章目录 卷积神经网络与循环神经网络的区别RNN cell结构构造RNN例子 seq2seq 卷积神经网络与循环神经网络的区别 卷积神经网络&#xff1a;在卷积神经网络中&#xff0c;全连接层的参数占比是最多的。 卷积神经网络主要用语处理图像、语音等空间数据&#xff0c;它的特点是局部…

复现文件上传漏洞

一、搭建upload-labs环境 将下载好的upload-labs的压缩包&#xff0c;将此压缩包解压到WWW中&#xff0c;并将名称修改为upload&#xff0c;同时也要在upload文件中建立一个upload的文件。 然后在浏览器网址栏输入&#xff1a;127.0.0.1/upload进入靶场。 第一关 选择上传文件…

Qt/QML编程之路:基于QWidget编程及各种2D/3D/PIC绘制的示例(45)

关于使用GWidget,这里有一个示例,看了之后很多图形绘制,控件使用,及最基本的QWidget编程都比较清楚了。ui的绘制: 运行后的界面如 工程中有非常丰富的关于各种图形的绘制,比如上图中circle,还有image。有下面一段readme的说明: # EasyQPainter Various operation pra…

AI预测福彩3D第9弹【2024年3月15日预测--第2套算法重新开始计算第1次测试】

我有一个彩友交流群&#xff0c;里面有很多热衷研究彩票技术的彩友&#xff0c;经过群里很多彩友的建议&#xff0c;我昨天晚上又设计了一套新的算法&#xff0c;这套算法加入了012路权重&#xff0c;将012路的权重按照开出概率设为不同的权重系数。 然后与第1套算法的进行相乘…

RabbitMq踩坑记录

1、连接报错&#xff1a;Broker not available; cannot force queue declarations during start: java.io.IOException 2.1、原因&#xff1a;端口不对 2.2、解决方案&#xff1a; 检查你的连接配置&#xff0c;很可能是你的yml里面的端口配置的是15672&#xff0c;更改为5672即…

STM32基础--中断应用

本文章里面假设中断就是异常&#xff0c;不做区分。 异常类型 F103 在内核水平上搭载了一个异常响应系统&#xff0c;支持为数众多的系统异常和外部中断。其中系统异常有 8 个&#xff08;如果把 Reset 和 HardFault 也算上的话就是 10 个&#xff09;&#xff0c;外部中断有…

upload-labs 0.1 靶机详解

下载地址https://github.com/c0ny1/upload-labs/releases Pass-01 他让我们上传一张图片&#xff0c;我们先尝试上传一个php文件 发现他只允许上传图片格式的文件&#xff0c;我们来看看源码 我们可以看到它使用js来限制我们可以上传的内容 但是我们的浏览器是可以关闭js功能的…