JavaWeb3-线程的3种创建方式7种写法
目录
1.方式一:继承Thread(2种写法)
写法①(常规):
a.使用jconsole观察线程
b.启动线程——start方法
PS:(常见面试题)start 方法与 run 方法的区别:
写法②(简化):匿名方式创建子对象
2.方式二:实现Runnable接口(3种写法)
写法③(常规):
写法④(变种):匿名Runnable方式(匿名内部类)
写法⑤(变种):使用Lambda匿名Runable方式(更简单)
3.方式三:实现Callable接口(带返回值可为任意类型)(2种写法)
写法⑥(常规):Callable + FutureTask(一个容器,用来接收线程执行的返回值)
写法⑦(简单):匿名Callable
1.方式一:继承Thread(2种写法)
写法①(常规):
/*** 继承 Thread 创建线程*/
public class ThreadDemo3 {public static void main(String[] args) {//获得当前的线程Thread mainThread = Thread.currentThread();System.out.println("主线程的名称:" + mainThread.getName());//创建线程Thread thread = new MyThread();//开启线程thread.start();}
}class MyThread extends Thread {@Override //需要重写run方法public void run() {//具体的业务执行代码Thread thread = Thread.currentThread(); //得到当前运行的线程try {Thread.sleep(60 * 60 * 1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程的名称:" + thread.getName()); //打印当前线程的名称}
}
a.使用jconsole观察线程
启动上面程序后:












b.启动线程——start方法
- 通过覆写 run ⽅法创建⼀个线程对象,但线程对象被创建出来并不意味着线程就开始运⾏了。(相当于提供给线程要做的事情的指令清单。 线程对象可以认为是把李四、王五叫过来了)
- 调⽤ start ⽅法, 才真的在操作系统的底层创建出⼀个线程。 (就是喊⼀声:”⾏动起来!“,线程才真正独⽴去执⾏了)
PS:(常见面试题)start 方法与 run 方法的区别:
public class ThreadDemo3 {public static void main(String[] args) {//创建线程Thread thread = new MyThread();//开启线程thread.start(); // thread.run();} }class MyThread extends Thread {@Overridepublic void run() {System.out.println("你好,线程");} }二者执行结果都是:
二者具体区别:
区别一:【方法性质不同】run 是一个普通方法,而 start 是开启新线程的方法。
- 调用 run 方法相当于执行普通方法 run,其实是调用当前主程序 main 来执行方法体的,(所有的main方法都会创建一个名为main的线程)并不会开启新线程;
- 而调用 start 方法是真正开启一个新线程来执行任务。
public class ThreadDemo3 {public static void main(String[] args) {//创建线程Thread thread = new MyThread();//开启线程thread.start(); // thread.run();} }class MyThread extends Thread {@Overridepublic void run() {Thread thread = Thread.currentThread();System.out.println(thread.getName());} }start:
run:
区别二:【执行速度不同】调用 run 方法会立即执行任务,调用 start 方法是将线程的状态改为就绪状态,不会立即执行。
- run 方法也叫做线程体,它里面包含了具体要执行的业务代码,当调用 run 方法时,会立即执行 run 方法中的代码(如果当前线程时间片未用完);
- 而调用 start 方法时,是启动一个线程并将线程的状态设置为就绪状态,并不会立即执行。
区别三:【调用次数不同】run 方法可以被重复调用,而 start 方法只能被调用一次。
- 因为 run 方法是普通方法,而普通方法是可以被多次调用的,所以 run 方法可以被调用多次;
- 而start 方法是创建新线程来执行任务,因为线程只能被创建一次,且线程状态是不可逆的。当线程调用了第一个 start 方法之后,线程的状态就会从新建状态 NEW,变为就绪状态 RUNNABLE,此时再次调用 start 方法,JVM 就会判断出当前的线程已经不等于新建状态,从而抛出 IllegalThreadStateException 非法线程状态异常。
start方法源码:
【Thread 在 start 的实现源码中做了判断看当前线程的状态是不是等于 0,也就是是否为新建状态NEW,如果线程不是新建状态 NEW,则会抛出非法线程状态异常 IllegalThreadStateException。】
public class ThreadDemo3 {public static void main(String[] args) {//创建线程Thread thread = new MyThread(); //NEW新建状态//开启线程thread.run(); //RUNABLE运行状态thread.run();thread.run();thread.start();thread.start();thread.start();} }class MyThread extends Thread {@Overridepublic void run() {Thread thread = Thread.currentThread();System.out.println(thread.getName());} }
写法②(简化):匿名方式创建子对象
public class ThreadDemo6 {public static void main(String[] args) {//创建线程并初始化Thread thread = new Thread() {@Overridepublic void run() {Thread t = Thread.currentThread();System.out.println("任务执行:" + t.getName());}};//执行线程thread.start();}
}

写法和↓类似:
List<String> list = new ArrayList<String>() {{add("ddd");
}};
继承Thread新建线程的缺点:Java 是单继承,继承了 Thread 就不能继承其他类了;然⽽ Java 可以实现多个接⼝,于是有了下⼀种⽅式。
2.方式二:实现Runnable接口(3种写法)
写法③(常规):
/*** 实现Runnable接口新建线程*/
public class ThreadDemo4 {public static void main(String[] args) {// Runnable不是Thread的子类,所以不能用之前的方式直接new一个MyThread2()// 而Thread类可以接收一个Runnable接口作为它的入参//创建RunnableMyThread2 myThread2 = new MyThread2();//创建一个线程Thread thread = new Thread(myThread2);//启动线程thread.start();}
}class MyThread2 implements Runnable {@Overridepublic void run() {//具体的业务代码Thread thread = Thread.currentThread(); //得到当前线程System.out.println("线程执行:" + thread.getName());}
}
写法④(变种):匿名Runnable方式(匿名内部类)
/*** Runnable匿名内部类来创建*/
public class ThreadDemo5 {public static void main(String[] args) {//匿名内部类Thread thread = new Thread(new Runnable() {@Overridepublic void run() {//业务代码Thread t = Thread.currentThread();System.out.println("执行任务:" + t.getName());}});//启动线程thread.start();}
}

写法⑤(变种):使用Lambda匿名Runable方式(更简单)
/*** 使用 lambda 来创建 Runnable*/
public class ThreadDemo7 {public static void main(String[] args) {//创建线程Thread thread = new Thread(() -> {//具体业务Thread t = Thread.currentThread();System.out.println("任务执行:" + t.getName());});//启动线程thread.start();}
}

进入Lambda表达式查看源码:

Lambda表达式是对于Runnable这个FunctionalInterface的一个实例化。
注:以上简单&变种支持JDK1.8+版本。
以上5种写法的共同问题:都没有返回值,当线程执行完成之后,主线程没法拿到新线程的执行结果。
3.方式三:实现Callable接口(带返回值可为任意类型)(2种写法)
写法⑥(常规):Callable + FutureTask(一个容器,用来接收线程执行的返回值)
Runnable(JDK1.0)比Callable(JDK1.5)诞生得早,后来当需要拿到线程的返回值时(使用频率低),为了不增加学习成本,改动原有Thread写法,新创建了FutureTask来接收线程执行的返回值。
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;/*** 实现Callable新建线程*/
public class ThreadDemo8 {public static void main(String[] args) throws ExecutionException, InterruptedException {//创建Callable实例MyCallable myCallable = new MyCallable();//用于接收Callable结果的对象FutureTask<Integer> futureTask = new FutureTask<>(myCallable);//创建新线程Thread thread = new Thread(futureTask); //Thread线程只能接收2种类型的参数,要么是Runnable,要么是FutureTask,不能直接接收一个Callable对象//启动线程thread.start();//接收新线程执行的结果int result = futureTask.get();System.out.println(Thread.currentThread().getName() + "——新线程返回的结果为:" + result);}
}/*** Callable<V> 泛型里面可以是任意数据类型*/
class MyCallable implements Callable<Integer> {@Overridepublic Integer call() throws Exception {//生成随机数的范围是0-9int randomNum = new Random().nextInt(10);System.out.println(Thread.currentThread().getName() + "——随机数:" + randomNum);return randomNum;}
}

写法⑦(简单):匿名Callable
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class ThreadDemo9 {public static void main(String[] args) throws ExecutionException, InterruptedException {FutureTask<String> futureTask = new FutureTask<>(new Callable<String>() {@Overridepublic String call() throws Exception {//新线程执行的业务代码String[] arrs = new String[]{"Java", "MySQL","Thread"};//随机返回一个字符串String result = arrs[new Random().nextInt(3)];System.out.println(Thread.currentThread().getName() + "——字符串:" + result);return result;}});//创建新线程Thread thread = new Thread(futureTask);//启动线程thread.start();String result = futureTask.get();System.out.println(Thread.currentThread().getName() + "——新线程的返回值:" + result);}
}

- 如果是 JDK 1.8 以上版本(含1.8),在不需要获得线程执⾏结果的情况下,推荐使⽤写法②匿名方式创建子对象或写法⑤Lambda ⽅式来创建线程,因为简洁。
- 如果想要获取线程执⾏结果,推荐使用写法⑦ FutureTask + Callable 的⽅式来实现。
相关文章:
JavaWeb3-线程的3种创建方式7种写法
目录 1.方式一:继承Thread(2种写法) 写法①(常规): a.使用jconsole观察线程 b.启动线程——start方法 PS:(常见面试题)start 方法与 run 方法的区别: 写…...
驱动调试手段
文章目录 前言一、通过sysfs调试LCD查看电源:查看 pwm 信息查看管脚信息总结前言 本文记录在驱动中常用的调试手段 提示:以下是本篇文章正文内容,下面案例可供参考 一、通过sysfs 系统起来之后可以读取 sysfs 一些信息,来协助调试 示例: 调试LCD 输入如下命令 cat /…...
[RK3568 Android12] 音频及路由
1:概述(耳机 ,hdmiin ,板载喇叭) 在开发板上面,系统注册了三个音频输出通道,如下: [ 2.280612] ALSA device list: [ 2.280622] #0: rockchip,rk809-codec [ 2.280630] #1: ROCKCHIP,SPDIF [ 2.280638] #2: rockchip,hdmi console:/proc/asound # cat pcm …...
C++——C++11 第一篇
目录 统一的列表初始化 {}初始化 decltype 编辑 nullptr STL中一些变化 右值引用和移动语义 左值引用和右值引用 总结 左值引用优缺点 右值引用(将亡值) 拷贝赋值和移动赋值 万能引用|完美转发 移动构造和移动赋值注意…...
Spring Data JPA 中 CrudRepository 和 JpaRepository 的区别
1 问题描述Spring Data JPA 中,CrudRepository 和 JpaRepository 有何区别?当我在网上找例子的时候,发现它们可以互相替换使用。它们有什么不同呢?为什么你习惯用其中的一个而不是另一个呢?2 CrudRepository 和 JpaRep…...
推荐几款好用的数据库管理工具
本文主要介绍几款常用的数据库管理软件(客户端),包括开源/免费的、商用收费的,其中有一些是专用于 MySQL 数据库的,例如 MySQL Workbench、phpMyAdmin,有一些是支持多种 SQL、NoSQL 数据库的,例…...
DPDK — 性能优化手段
目录 文章目录 目录硬件布局层面的优化操作系统层面的优化Linux 操作系统版本应用程序层面的优化Cache 优化内存对齐内存预取SIMD 报文批处理DDIO使用高级 CPU 指令集硬件布局层面的优化 DPDK 在硬件布局层面的优化,主要体现在以下几个方面: CPU 频率的高低:CPU 频率越高,…...
Fedora Linux未来五年规划
Fedora 委员会一直致力于起草战略计划,以帮助 Fedora Linux 更好地发展。近日 Fedora 委员会公布了一份 “《未来五年的 Fedora Linux 》” 战略计划草案,这份草案里面包含了他们的雄心壮志:每周将 Fedora 的活跃贡献者人数增加一倍。 Fedora…...
【C++之容器篇】map和set常见函数接口的使用与剖析
目录前言一、set1. 简介2. 成员类型3. 构造函数(1) set()(2)set(InputIterator first,InputIterator last)(3)使用4. 拷贝构造函数和赋值运算符重载5. empty()6. size()7. insert()(1)pair<iterator,bool> insert(const K& key)(2)iterator insert(iterator pos,cons…...
虚拟DOM是什么
参考文章做的总结,如有不足之处请指正! 在讲虚拟dom之前,先讲讲,为什么前端操作dom会导致页面性能降低? 先说几个概念 有助于后面的理解 什么是 JavaScript 引擎? JavaScript引擎是一个专门处理JavaScript脚…...
进程通信方式
无名管道( pipe ): 管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。高级管道(popen): 将另一个程序当做一个新的进程在当前程序进…...
强化学习基础知识
强化学习是一种机器学习方法,通过agent与environment的互动,学习适当的action policy以取得更大的奖励reward。本篇博客介绍强化学习的基础知识,与两类强化学习模型。 目录强化学习的基础设定policy based 强化学习的目标3个注意事项实际训练…...
LeetCode230218_148、654. 最大二叉树
给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点,其值为 nums 中的最大值。 递归地在最大值 左边 的 子数组前缀上 构建左子树。 递归地在最大值 右边 的 子数组后缀上 构建右子树。 返回 nums 构建的 最大二叉树…...
WordPress 是什么?.com 和 .org 的 WordPress 有什么差异?
本篇文章会介绍这次WordPress 5.8核心版本所带来的其中一项新功能:内存块小工具(Widget)此次更新把小工具编辑设定的页面也改成用「内存块编辑」的概念,就跟内置的「古腾堡」编辑器一样,把所有元件都内存块化ÿ…...
java8新特性【2023】
Lambda表达式 新的一套语法规则 是一个匿名函数 Testpublic void test1(){Runnable r1 new Runnable(){Overridepublic void run() {System.out.println("线程A");}};r1.run();System.out.println("");Runnable r2 () -> System.out.println("…...
刷题记录:牛客NC51101Lost Cows
传送门:牛客 题目描述: (2≤N≤8,000) cows have unique brands in the range 1..N. In a spectacular display of poor judgment, they visited the neighborhood watering hole and drank a few too many beers before dinner. When it was time to line up for their ev…...
华为OD机试 - 不等式 | 备考思路,刷题要点,答疑 【新解法】
最近更新的博客 华为OD机试 - 寻找路径 | 备考思路,刷题要点,答疑 【新解法】华为OD机试 - 最小叶子节点 | 备考思路,刷题要点,答疑 【新解法】华为OD机试 - 对称美学 | 备考思路,刷题要点,答疑 【新解法】华为OD机试 - 最近的点 | 备考思路,刷题要点,答疑 【新解法】华…...
GuLi商城-SpringCloud-OpenFeign测试远程调用
1. Feign 简介 Feign 是一个声明式的 HTTP 客户端,它的目的就是让远程调用更加简单。Feign 提供了HTTP请 求的模板,通过编写简单的接口和插入注解,就可以定义好 HTTP 请求的参数、格式、地址等信 息。Feign 整合了 Ribbon(负载…...
阿里云_山东鼎信短信的使用(云市场)
目录山东鼎信API工具类随机验证码工具类进行测试Pom依赖(可以先导入依赖)创建controllerSmsServiceSmsServiceImplswagger测试(也可以使用postman)山东鼎信API工具类 山东鼎信短信官网 找到java的Api,复制下来 适当改了一下,为了调用(类名SmsUtils) p…...
基于虚拟机机的代码保护技术
虚拟机保护技术是基于x86汇编系统的可执行代码转换为字节码指令系统的代码,以达到保护原有指令不被轻易逆向和篡改的目的。 字节码(Byte-code)是一种包含执行程序,由一序列 op 代码/数据对组成的 ,是一种中间码。字节是…...
避坑指南:如何在torch 2.4.0 + CUDA 12.1环境下成功安装llamafactory及其依赖
深度避坑:PyTorch 2.4.0与CUDA 12.1环境下的Llamafactory全栈部署实战 当开发者尝试在PyTorch 2.4.0和CUDA 12.1环境下部署Llamafactory时,往往会陷入依赖地狱——从Torch版本误装到vllm模块缺失,每个环节都可能成为耗时数小时的深坑。本文将…...
从Shadertoy到Cesium:那些GLSL移植时没人告诉你的分辨率陷阱
GLSL跨平台移植中的分辨率适配陷阱与实战解决方案 当我们将Shadertoy上令人惊艳的GLSL效果移植到Cesium等三维引擎时,往往会遇到一个看似简单却影响深远的问题——分辨率适配。这个问题不仅关乎视觉效果还原度,更直接影响着色器在不同设备上的表现一致性…...
Step3-VL-10B部署案例:金融APP界面自动化测试,覆盖85%人工回归用例
Step3-VL-10B部署案例:金融APP界面自动化测试,覆盖85%人工回归用例 1. 项目背景与痛点 金融APP的每一次版本更新,都伴随着一场紧张的回归测试。测试团队需要反复验证登录、转账、理财购买、账单查询等几十个核心功能,确保新代码…...
SaaS级AI员工系统源码商用版,多租户+计费系统+API分销,一套源码搞定
温馨提示:文末有资源获取方式最近“龙虾AI”的热度居高不下,到处都在讨论如何“养龙虾”。但观察下来发现,这类应用对普通用户而言技术门槛还是偏高,部署、配置、调试都需要专人跟进,最终往往沦为摆设。源码获取方式在…...
开源动作捕捉新纪元:FreeMoCap低成本解决方案全解析
开源动作捕捉新纪元:FreeMoCap低成本解决方案全解析 【免费下载链接】freemocap Free Motion Capture for Everyone 💀✨ 项目地址: https://gitcode.com/GitHub_Trending/fr/freemocap 问题:动作捕捉技术的高门槛困境 在数字内容创作…...
求一个V站邀请码
有没有大佬可以给个邀请码~~~~~~~~~~~~~~~~~~...
比较好的金线包封胶制造商推荐几家
嘿,朋友们!在半导体封装领域,金线包封胶就像是芯片的“贴身保镖”,保护着纤细的金线,让芯片能够稳定工作。今天咱们就来聊聊比较好的金线包封胶制造商,看看哪家更值得你选择。一、东莞市汉思新材料科技有限…...
APISIX Dashboard实战:从零配置JWT认证网关(含Node.js后端对接)
APISIX Dashboard实战:从零构建JWT认证网关与Node.js后端深度集成 引言:为什么选择APISIX作为API网关? 在现代微服务架构中,API网关扮演着流量调度和安全防护的双重角色。APISIX作为云原生API网关的佼佼者,凭借其动态…...
如何快速上手uesave-rs:虚幻引擎存档编辑的终极指南
如何快速上手uesave-rs:虚幻引擎存档编辑的终极指南 【免费下载链接】uesave 项目地址: https://gitcode.com/gh_mirrors/ue/uesave 还在为无法修改心爱游戏的存档而烦恼吗?想要自定义游戏体验却不知从何下手?uesave-rs这款强大的Rus…...
别再纠结了!用SpringBoot实战告诉你,图片上传选FastDFS还是MinIO(附完整代码)
SpringBoot实战:FastDFS与MinIO文件存储方案深度对比与选型指南 在当今数据驱动的互联网应用中,文件存储系统如同数字世界的基础设施,支撑着从用户头像到高清视频的各种数据存取需求。作为Java开发者,当我们面对"选择困难症&…...







