Java多线程:常见的线程的创建方法及Thread类详解
目录
一.并发编程相关概念
线程与进程
多线程
Java中线程的状态
二.线程的创建方法
方法一:继承Thread类
方法二:实现Runnable接口
其他方法
三.Thread类详解
Thread常见构造方法
Thread常见属性
Thread常见方法
start() 与 run()
sleep() 与 yield()
join()
inerrupt()
一.并发编程相关概念
线程与进程
线程是程序的执行流程的最小单元。一个进程(程序的执行实例)可以由一个或多个线程组成,每个线程都有自己的执行路径和执行状态。线程可以并发执行,即多个线程可以同时在不同的处理器核心或计算机上运行,从而提高程序的运行效率。
线程与进程的区别在于,进程是操作系统对一个正在运行的程序的抽象,而线程是进程内部的一个执行单位。一个进程可以有多个线程,这些线程共享进程的资源,如内存空间、文件描述符等。线程之间可以通过共享内存的方式进行通信,相比于进程间通信(如管道、消息队列)的开销更小。
多线程
对于多线程,我们可以举出这样的一个例子来帮助我们理解
一家公司要去银行办理业务,既要进行财务转账,又要进行福利发放,还得进行缴纳社保。 如果只有张三一个会计就会忙不过来,耗费的时间特别长。为了让业务更快的办理好,张三又找 来两位同事李四、王五一起来帮助他,三个人分别负责一个事情,分别申请一个号码进行排队, 自此就有了三个执行流共同完成任务,但本质上他们都是为了办理一家公司的业务。 此时,我们就把这种情况称为多线程,将一个大任务分解成不同小任务,交给不同执行流就分别 排队执行。
对于这样的业务场景,张三、李四和王五各自都相对于一个线程,多个线程之间相互配合才促使了整体业务流程的顺利进行,由此可见多线程对于任务处理的高效。其中由于李四、王五都是张三叫来的,所以张三一般被称为主线程(Main Thread),李四和王五则为其他线程。
Java中线程的状态
Java中线程的状态有以下几种:
1. 新建(New):线程被创建但还没有开始执行。
2. 就绪(Runnable):线程被调度并准备开始执行,但还没有获取CPU执行权。
3. 运行(Running):线程正在执行任务。
4. 阻塞(Blocked):当线程执行到某个阻塞操作时,如等待IO操作完成或等待某个锁的释放时,线程会进入阻塞状态。
5. 等待(Waiting):线程执行了Object类的wait()方法,或者Thread类的join()方法时,线程会进入等待状态。
6. 超时等待(Timed Waiting):线程执行了Thread类的sleep()方法或等待超时后,线程会进入超时等待状态。
7. 终止(Terminated):线程执行完任务后或者出现异常终止时,线程进入终止状态。
二.线程的创建方法
线程是操作系统中的概念,操作系统内核实现了线程这样的机制,并且对用户层提供了一些 API 供用户使用(例如 Linux 的 pthread 库)
而Java标准库中 Thread 类,便可以视为是对操作系统提供的 API 进行了进一步的抽象和封装,作为Java程序员就可以利用Thread 类来实现并发编程。
并发编程是指在计算机系统中,多个独立的任务同时进行,每个任务由一个或多个线程执行,并且这些线程可能在同一时刻同时运行。并发编程可以提高系统的执行效率和资源利用率。在并发编程中,多个线程可以同时进行不同的操作,比如读写数据、计算、网络通信等,它们可以同时执行,不需要等待其他线程的完成。常见的并发编程模型有多线程、异步编程、并行计算等。
说了这么多,归根结底还得落实到代码上,我们常见的创建线程的方式有俩种。
方法一:继承Thread类
- 创建一个继承自Thread类的子类。
- 在子类中重写run()方法,定义线程的执行逻辑。
- 在主线程中创建子类对象,并调用start()方法启动线程。
public class MyThread extends Thread {public void run() {// 线程执行逻辑}public static void main(String[] args) {MyThread thread = new MyThread();thread.start();}
}
方法二:实现Runnable接口
- 创建一个实现了Runnable接口的类,并实现接口中的run()方法,定义线程的执行逻辑。
- 在主线程中创建Runnable实例,并将其作为参数传递给Thread类的构造方法。
- 调用Thread对象的start()方法启动线程。
public class MyRunnable implements Runnable {public void run() {// 线程执行逻辑}public static void main(String[] args) {MyRunnable runnable = new MyRunnable();Thread thread = new Thread(runnable);thread.start();}
}
无论是继承Thread类还是实现Runnable接口,都可以创建多个线程并同时运行,以实现并发执行的效果。
其他方法
除此之外,使用匿名内部类或lambda表达式可以更快速的创建线程
匿名内部类创建Thread 子类对象
// 使用匿名类创建 Thread 子类对象
Thread t1 = new Thread() {@Overridepublic void run() {System.out.println("使用匿名类创建 Thread 子类对象");}
};
匿名内部类创建 Runnable 子类对象
// 使用匿名类创建 Runnable 子类对象
Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("使用匿名类创建 Runnable 子类对象");}
});
lambda 表达式创建Runnable 子类对象
// 使用 lambda 表达式创建 Runnable 子类对象
Thread t3 = new Thread(() -> System.out.println("使用匿名类创建 Thread 子类对象"));
Thread t4 = new Thread(() -> {System.out.println("使用匿名类创建 Thread 子类对象");
});
三.Thread类详解
不管是上述创建线程中的哪一种方法,归根结底都是由 Thread 类延申开来的,Thread 类是 JVM 用来管理线程的一个类,换句话说,每个线程都有一个唯一的 Thread 对象与之关联。而 Thread 类的对象就是用来描述一个线程执行流的,JVM 会将这些 Thread 对象组织起来,用于线程调度,线程管理。
Thread常见构造方法
方法 | 说明 |
Thread() | 创建线程对象 |
Thread(Runnable target) | 使用Runnable对象创建线程对象 |
Thread(String name) | 创建线程对象,并命名 |
Thread(Runnable target, String name) | 使用Runnable对象创建线程对象,并命名 |
Thread(ThreadGroup group, Runnable target) | 线程可以被用来分组管理,分好的组即为线程组 |
Thread常见属性
属性 | 获取方法 |
ID | getId() |
名称 | getName() |
状态 | getState() |
优先级 | getPriority() |
是否后台线程 | isDaemon() |
是否存活 | isAlive() |
是否被中断 | isInterrupted() |
其中 ID 是线程的唯一标识,不同线程不会重复,优先级高的线程理论上来说更容易被调度到,是否存活,简单的理解的话就是 run 方法是否运行结束了
Thread常见方法
start() 与 run()
- start()方法是Thread类中的一个方法,用于启动一个新的线程。当调用start()方法时,系统会创建一个新的线程,并在新的线程中执行run()方法的内容。start()方法会在新的线程中执行一些准备工作,然后调用run()方法。
- run()方法是实现了Runnable接口的类中的一个方法。在启动一个线程后,系统会自动调用该线程对象的run()方法。run()方法中包含了线程的主体代码,即线程要执行的任务。
前文中我们已经了解了如何通过重写 run 方法创建一个线程对象,但线程对象被创建出来并不意味着线程就开始运行了。重写 run 方法是提供给线程要做的事情的指令清单,线程对象可以认为是把李四、王五叫过来了,而调用start() 方法,就是喊一声:“行动起来!”,线程才真正独立去执行。
public class MyThread extends Thread {public void run() {// 线程执行逻辑}public static void main(String[] args) {MyThread thread = new MyThread();thread.start();}
}
就拿上面这段代码来说,我们能不能不管start方法直接调用线程的run方法呢?
其实是可以调用run方法的,但是直接调用run方法只会在当前线程中运行run方法的代码,不会启动新的线程去执行run方法。
而调用start方法则会启动一个新的线程,然后在新的线程中执行run方法的代码。所以,如果只调用run方法而不调用start方法,则不会创建新的线程,无法实现多线程的并发执行。
也就是说,我们可以这样做,但是这样做的话就不会实现多线程,始终我们都只能在一个线程中运行。因此在实际开发中,并不建议这样做。
还有一点需要注意的是,对于start方法,我们只能调用一次,不能重复调用,不然会报非法线程状态异常,因为在调用start方法后,线程就已经处于Runnable状态,对于已经是Runnable状态的线程,再让它start为Runnable状态显然是不合理的。
sleep() 与 yield()
在多线程编程中,可以使用sleep和yield方法来控制线程的执行。
- sleep方法:sleep方法是Thread类提供的静态方法,可以使当前线程暂停一段时间,让其他线程有机会执行。调用sleep方法后,线程会进入阻塞状态,不会占用CPU资源。sleep方法的语法是:Thread.sleep(long millis),其中millis参数表示暂停的时间,以毫秒为单位。例如,Thread.sleep(100)表示暂停100毫秒。
- yield方法:yield方法是Thread类提供的静态方法,可以使当前线程让出CPU资源,使其他同优先级的线程有机会执行。调用yield方法后,线程会进入就绪状态,让出CPU资源,但并不是完全放弃CPU资源,可能会立即重新获取CPU资源。yield方法的语法是:Thread.yield()。例如,Thread.yield()表示当前线程让出CPU资源,给其他同优先级的线程执行的机会。
总的来说,sleep方法是让当前线程暂停一段时间,不会占用CPU资源,适合用于控制线程执行的时间间隔。yield方法是让当前线程主动让出CPU资源,给其他同优先级的线程执行的机会,适合用于在多个线程之间平衡负载,提高系统的性能。
join()
join()方法是Thread类的一个方法,它用于等待该线程完成执行。具体而言,当调用一个线程的join()方法时,当前线程会被阻塞,直到该线程执行完成。
join()方法有两个重载版本:
- join():等待被调用线程执行完成。
- join(long millis):等待被调用线程执行完成,但最多等待millis毫秒。
下面是一个例子,演示如何使用join()方法等待线程执行完成:
public class JoinExample {public static void main(String[] args) {Thread thread1 = new Thread(new MyRunnable(), "Thread 1");Thread thread2 = new Thread(new MyRunnable(), "Thread 2");thread1.start();thread2.start();try {thread1.join();thread2.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("All threads have finished execution.");}
}class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + " is executing.");try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " has finished execution.");}
}
在上面的例子中,我们创建了两个线程thread1和thread2,并将它们启动。然后,我们使用join()方法等待这两个线程执行完成。最后,当两个线程都执行完成后,才会打印"All threads have finished execution."。
inerrupt()
在Java中,线程的interrupt()方法用于中断线程。当一个线程调用interrupt()方法时,如果目标线程当前正在执行可中断的操作(如sleep()、join()、wait()等),它将会收到一个InterruptedException异常,从而提前退出。
如果目标线程没有在可中断操作中阻塞,而是在运行中,那么调用interrupt()方法将设置目标线程的中断标志位为true。这样,目标线程可以通过检查自己的中断标志位来自行决定是否中断执行。
下面是一个示例:
public class MyThread extends Thread {public void run() {while (!Thread.currentThread().isInterrupted()) {// 执行一些操作}System.out.println("线程被中断");}public static void main(String[] args) {MyThread thread = new MyThread();thread.start();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}thread.interrupt();}
}
在上述示例中,我们创建了一个继承自Thread类的自定义线程MyThread。在run() 方法中,我们使用了一个循环来模拟线程的执行操作。每次循环都会检查中断标志位,如果为true则退出循环并输出"线程被中断"。在前文的Thread类常见属性也说过了使用 isInterrupted() 方法就可以获取当前线程的中断标志位。
备注:和 isInterrupted() 相似的还有一个方法叫做 interrupt() 二者都能判断线程是否被打断,但是不同的点在于前者只是做出判断,并不会手动修改这个标记;而后者会在判断后手动清除打断标记,也就是置为false。
在main方法中,我们创建了一个MyThread对象并启动线程。然后通过调用Thread.sleep() 方法来让主线程睡眠1秒,最后调用thread.interrupt() 方法中断线程。当调用interrupt() 方法时,MyThread线程在下一个循环迭代时会检查到中断标志位为true,从而退出了循环并输出"线程被中断"。
本次的分享就到此为止了,希望我的分享能给您带来帮助,创作不易也欢迎大家三连支持,你们的点赞就是博主更新最大的动力!
如有不同意见,欢迎评论区积极讨论交流,让我们一起学习进步!
有相关问题也可以私信博主,评论区和私信都会认真查看的,我们下次再见
相关文章:

Java多线程:常见的线程的创建方法及Thread类详解
目录 一.并发编程相关概念 线程与进程 多线程 Java中线程的状态 二.线程的创建方法 方法一:继承Thread类 方法二:实现Runnable接口 其他方法 三.Thread类详解 Thread常见构造方法 Thread常见属性 Thread常见方法 start() 与 run() sleep(…...

一招搞定生产管理
劳动力成本上升,原材料价格上涨,企业生产成本逐年增加,市场竞争越来越激烈,传统的中小制造企业面临着巨大的挑战。 企业的数字化转型如今成为炙手可热的高频词语,越来越多的中小制造企业已经开始上云,实践SaaS模式的生产管理系统…...

学习CSS3,实现红色心形loading特效
试想一下,如果你的网站在加载过程中,loading图由一个老旧的菊花转动图片,变为一个红色的心形loading特效,那该有多炫酷啊。 目录 实现思路 初始化HTML部分 延迟动画是重点 设定动画效果 完整源代码 最后 实现思路 每个…...

深度学习之基于Matlab神经网络的活体人脸和视频人脸识别系统
欢迎大家点赞、收藏、关注、评论啦 ,由于篇幅有限,只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景 人脸识别技术作为生物识别技术的一种,近年来得到了广泛的关注和应用。与传统的身份认证方…...

充电桩测试:负载箱的重要性
随着电动汽车的普及,充电桩的需求也在不断增加。为了保证充电桩的安全、稳定和高效运行,对其进行严格的测试是必不可少的。在充电桩测试过程中,负载箱作为一种重要的测试设备,对于评估充电桩的性能和可靠性具有重要意义。 负载箱可…...
贪心算法、Dijkstra和A*类路径搜索算法
系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 TODO:写完再整理 文章目录 系列文章目录前言系列文章目录前言1.贪心算法、Dijkstra和A*类路径搜索算法(1)greedy best frist search贪心算法(仅仅考虑启发式代价)1.核心思想2.构造启发式猜…...

Debian是什么?有哪些常用命令
目录 一、Debian是什么? 二、Debian常用命令 三、Debian和CentOS的区别 四、Debian和CentOS的优缺点 五、Debian和CentOS的运用场景 一、Debian是什么? Debian是一种流行的开源Linux操作系统。 Debian是一个以Linux内核为基础的操…...

万兴PDF专家 PDFelement Pro v10.3.8 破姐版!
🧑💻万兴PDF专家 PDFelement Pro v10.3.8 破姐版 (https://docs.qq.com/sheet/DRVVxTHJ3RXJFVHVr)...
Ubuntu22.04 私钥登录
1. 背景 以前一直使用秘钥登录Linux,最近新装了一台Ubuntu 22.04,照旧部署公钥,使用私钥登录,结果SecureCRT 登录没有问题,使用Xshell登录一直报“所选的用户密钥未在远程主机上注册,请再试一次”。然后各种试&#x…...

Java_JVM_JVMs
JVM 官方文档说明文档目录 官方文档 JVM Specification 说明 以Java SE 17为标准 文档目录 2:JVM 结构 class文件数据类型 基本数据类型引用数据类型 运行时数据区 栈帧 其他内容 对象的表示浮点数运算特殊方法 初始化方法【实例、类】多态方法 3ÿ…...

Linux系统编程之基本指令
零、Linux发展史 1、诞生 1991年10月5日,赫尔辛基大学的一名研究生Linus Benedict Torvalds在一个Usenet新闻组 (comp.os.minix)中宣布他编制出了一种类似UNIX的小操作系统,叫Linux。新的操作系统是受到另一个UNIX的小操作系统—…...

[1702]java旅游资源网上填报系统Myeclipse开发mysql数据库web结构java编程计算机网页项目
一、源码特点 java旅游资源网上填报系统是一套完善的java web信息管理系统,对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发,数据库为Mysql…...
【Flask 系统教程 3】请求与响应
Flask 是一个灵活而强大的 Web 框架,而请求与响应则是构建 Web 应用的核心组成部分。在本文中,我们将探讨 Flask 中请求与响应的各种用法,包括不同的请求方法、重定向、响应对象、获取查询参数以及文件上传等。 请求 在 Flask 中࿰…...

jsp校园商城派送系统Myeclipse开发mysql数据库web结构java编程计算机网页项目
一、源码特点 JSP 校园商城派送系统 是一套完善的web设计系统,对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统采用serlvetdaobean mvc 模式,系统主要采用B/S模式 开发。开发环境为TOMCAT7.0,Myeclipse8.…...

【Linux】System V 共享内存
文章目录 1. 共享内存示意图2. 共享内存数据结构3. 共享内存函数shmgetshmatshmdtshmctl 4. 实例代码测试共享内存5. 共享内存相关命令6. System V 消息队列(了解)7. System V 信号量(了解) 共享内存区是最快的 IPC 形式。一旦这样…...

拼多多标准推广怎么玩
拼多多标准推广的玩法主要包括以下方面: 拼多多推广可以使用3an推客。3an推客(CPS模式)给商家提供的营销工具,由商家自主设置佣金比例,激励推广者去帮助商家推广商品链接,按最终有效交易金额支付佣金&…...

HFSS学习-day2-T形波导的优化设计
入门实例–T形波导的内场分析和优化设计 HFSS--此实例优化设计 优化设计要求1. 定义输出变量Power31、Power21、和Power11,表示Port3、Port2、Port1的输出功率2.参数扫描分析添加扫描变量和输出变量进行一个小设置添加输出变量进行扫描分析 3. 优化设计,…...

贪吃蛇小游戏(c语言)
1.效果展示 屏幕录制 2024-04-28 205129 2.基本功能 • 贪吃蛇地图绘制 • 蛇吃食物的功能 (上、下、左、右方键控制蛇的动作) • 蛇撞墙死亡 • 蛇撞自身死亡 • 计算得分 • 蛇身加速、减速 • 暂停游戏 3.技术要点 C语言函数、枚举、结构…...

多商户Docker Supervisor进程管理器部署
Dockerfile 根目录下没有Dockerfile的可以复制下面的命令 # 使用基础镜像 FROM leekay0218/crmeb-mer## 复制代码 ## 在本地调试注释掉,使用映射把文件映射进去 #ADD ./ /var/www# 设置工作目录 WORKDIR /var/www# 设置时区为上海 ENV TZAsia/Shanghai RUN ln -sn…...

Vue--》从零开始打造交互体验一流的电商平台(一)
今天开始使用 vue3 ts 搭建一个电商项目平台,因为文章会将项目的每处代码的书写都会讲解到,所以本项目会分成好几篇文章进行讲解,我会在最后一篇文章中会将项目代码开源到我的github上,大家可以自行去进行下载运行,希…...

网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

边缘计算医疗风险自查APP开发方案
核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...
CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝
目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为:一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...
git: early EOF
macOS报错: Initialized empty Git repository in /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/.git/ remote: Enumerating objects: 2691797, done. remote: Counting objects: 100% (1760/1760), done. remote: Compressing objects: 100% (636/636…...

stm32wle5 lpuart DMA数据不接收
配置波特率9600时,需要使用外部低速晶振...

沙箱虚拟化技术虚拟机容器之间的关系详解
问题 沙箱、虚拟化、容器三者分开一一介绍的话我知道他们各自都是什么东西,但是如果把三者放在一起,它们之间到底什么关系?又有什么联系呢?我不是很明白!!! 就比如说: 沙箱&#…...

鸿蒙Navigation路由导航-基本使用介绍
1. Navigation介绍 Navigation组件是路由导航的根视图容器,一般作为Page页面的根容器使用,其内部默认包含了标题栏、内容区和工具栏,其中内容区默认首页显示导航内容(Navigation的子组件)或非首页显示(Nav…...