高级进阶多线程——多任务处理、线程状态(生命周期)、三种创建多线程的方式
Java多线程
Java中的多线程是一个同时执行多个线程的进程。线程是一个轻量级的子进程,是最小的处理单元。多进程和多线程都用于实现多任务处理。
但是,一般使用多线程而不是多进程,这是因为线程使用共享内存区域。它们不分配单独的内存区域以节省内存,并且线程之间的上下文切换比进程花费的时间更少。
Java多线程主要用于游戏,动画等。
优点
(1)它不会阻塞用户,因为线程是独立的,可以同时执行多个操作。
(2)可以一起执行许多操作,因此可以节省时间。
(3)线程是独立的,因此如果在单个线程中发生异常,它不会影响其他线程。
多任务处理
多任务处理是同时执行多个任务的过程。使用多任务来利用CPU,多任务处理可以通过两种方式实现:
基于进程的多任务处理(多进程)
基于线程的多任务处理(多线程)
基于进程的多任务处理(多进程)
- 每个进程在内存中都有一个地址。 换句话说,每个进程分配一个单独的内存区域。
- 进程是重量级的。
- 进程之间的通信成本很高。
- 从一个进程切换到另一个进程需要一些时间来保存和加载寄存器,内存映射,更新列表等。
基于线程的多任务处理(多线程)
- 线程共享相同的地址空间。
- 线程是轻量级的。
- 线程之间的通信成本很低。
注意:一次只执行一个线程。
线程的生命周期(线程状态)
线程可以处于五种状态之一。 根据sun解释,线程生命周期在java中有以下几种状态:初始(NEW) ,运行(RUNNABLE),阻塞(BLOCKED),等待(WAITING),超时等待(TIMED_WAITING)和终止(TERMINATED)。
java中线程的生命周期由JVM控制,java线程状态如下:
- 初始(NEW):新创建了一个线程对象,但还没有调用start()方法。
- 运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。
线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)。 - 阻塞(BLOCKED):表示线程阻塞于锁。
- 等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
- 超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。
- 终止(TERMINATED):表示该线程已经执行完毕。
新建状态:
使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。
就绪状态
当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。
运行状态
如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。
阻塞状态:
如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:
-
等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。
-
同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。
-
其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。
死亡状态
一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。
创建线程
创建一个线程有三种方法:
- 通过扩展
Thread
类。 - 通过实现
Runnable
接口。 - 通过 Callable 和 Future 创建线程。
Thread类Thread
类提供了在线程上创建和执行操作的构造函数和方法。Thread
类扩展了Object
类并实现了Runnable
接口。
常用的Thread类构造函数
Thread()
Thread(String name)
Thread(Runnable r)
Thread(Runnable r,String name)
Thread类的常用方法:
public void run()
: 用于执行线程的操作。public void start()
: 开始执行线程,JVM调用线程上的run()
方法。public void sleep(long miliseconds)
: 使当前正在执行的线程休眠(暂时停止执行)达指定的毫秒数。public void join()
: 等待线程死亡。public void join(long miliseconds)
: 按指定的毫秒数等待线程死亡。public int getPriority()
: 返回线程的优先级。public int setPriority(int priority)
: 更改线程的优先级。public String getName()
: 返回线程的名称。public void setName(String name)
: 更改线程的名称。public int getId()
:返回线程的编号(ID)。public Thread.State getState()
: 返回线程的状态。public boolean isAlive()
: 测试线程是否处于活动状态。public void yield()
: 使当前正在执行的线程对象暂时暂停并允许其他线程执行。public void suspend()
: 用于挂起线程(depricated)。public void resume()
: 用于恢复挂起的线程(depricated)。public void stop()
: 用于停止线程(depricated)。public boolean isDaemon()
: 测试该线程是否为守护进程线程。public void setDaemon(boolean b)
: 将线程标记为守护进程或用户线程。public void interrupt()
: 中断线程。public boolean isInterrupted()
: 测试线程是否被中断。public static boolean interrupted()
: 测试当前线程是否已被中断。
Runnable接口:Runnable
接口应由任何其实例由线程执行类实现。Runnable
接口只有一个run()
方法。
public void run()
: 用于执行线程的操作。
启动线程:
Thread
类的start()
方法用于启动新创建的线程。它执行以下任务:
- 一个新线程启动(使用新的callstack)。
- 线程从
New
状态移动到Runnable
状态。- 当线程有机会执行时,它的目标
run()
方法将运行。
示例
1. 通过扩展Thread类线程示例
package com.yiibai;class Multi extends Thread {public void run() {System.out.println("thread is running...");}public static void main(String args[]) {Multi t1 = new Multi();t1.start();}
}
执行上面示例代码,得到以下结果:
thread is running...
2. 通过实现Runnable接口的线程示例
package com.yiibai;class Multi implements Runnable {public void run() {System.out.println("thread is running...");}public static void main(String args[]) {Multi m1 = new Multi();Thread t1 = new Thread(m1);t1.start();}
}
执行上面示例代码,得到以下结果:
thread is running...
如果没有扩展Thread
类,类对象就不会被视为一个线程对象。所以需要明确地创建Thread
类对象。传递实现Runnable
类的对象,以便类的run()
方法可以执行。
3.通过 Callable 和 Future 创建线程
- 创建 Callable 接口的实现类,并实现 call() 方法,该 call() 方法将作为线程执行体,并且有返回值。
- 创建 Callable 实现类的示例,使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值。
- 使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程。
- 调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值。
public class Zeus implements Callable<Integer> {public static void main(String[] args) { CallableThreadTest ctt = new CallableThreadTest(); FutureTask<Integer> ft = new FutureTask<>(ctt); for(int i = 0;i < 100;i++) { System.out.println(Thread.currentThread().getName()+" 的循环变量i的值"+i); if(i==20) { new Thread(ft,"有返回值的线程").start(); } } try { System.out.println("子线程的返回值:"+ft.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } }@Override public Integer call() throws Exception { int i = 0; for(;i<100;i++) { System.out.println(Thread.currentThread().getName()+" "+i); } return i; }
}
创建线程的三种方式的对比
- 采用实现 Runnable、Callable 接口的方式创建多线程时,线程类只是实现了 Runnable 接口或 Callable 接口,还可以继承其他类。
-
使用继承 Thread 类的方式创建多线程时,编写简单,如果需要访问当前线程,则无需使用 Thread.currentThread() 方法,直接使用 this 即可获得当前线程。
线程的几个主要概念
在多线程编程时,你需要了解以下几个概念:
线程同步
线程间通信
线程死锁
Java线程调度程序
Java的线程调度程序是JVM的一部分,它决定应该运行哪个线程。无法保证线程调度程序将选择运行哪个可运行线程。
一次只能有一个线程在一个进程中运行。线程调度程序主要使用抢占式或时间切片调度来调度线程。
抢占式调度与时间分片的区别
在抢占式调度下,优先级最高的任务一直执行,直到它进入等待或死亡状态或更高优先级的任务出现。 在时间切片下,任务执行预定义的一段时间,然后重新进入就绪任务池。 然后,调度程序根据优先级和其他因素确定接下来应执行的任务。
相关文章:

高级进阶多线程——多任务处理、线程状态(生命周期)、三种创建多线程的方式
Java多线程 Java中的多线程是一个同时执行多个线程的进程。线程是一个轻量级的子进程,是最小的处理单元。多进程和多线程都用于实现多任务处理。 但是,一般使用多线程而不是多进程,这是因为线程使用共享内存区域。它们不分配单独的内存区域…...
【 K8S 】 Pod 进阶
目录 //资源限制官网示例:重启策略 //健康检查:又称为探针(Probe) //资源限制 当定义 Pod 时可以选择性地为每个容器设定所需要的资源数量。 最常见的可设定资源是 CPU 和内存大小,以及其他类型的资源。 当为 Pod 中…...

众和转债,宏微转债,阳谷转债上市价格预测
众和转债 基本信息 转债名称:众和转债,评级:AA,发行规模:13.75亿元。 正股名称:新疆众和,今日收盘价:8.14元,转股价格:8.2元。 当前转股价值 转债面值 / 转股…...

MySQL~事务的四大特性和隔离级别
事务的四大特性 1.原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个…...

JMeter处理接口签名之BeanShell实现MD5加密
项目A需要给项目B提供一个接口,这个接口加密了,现在需要测试这个接口,需要怎么编写脚本呢?实现接口签名的方式有两种:BeanShell实现MD5加密和函数助手实现MD5加密,之前已经分享过了函数助手实现MD5加密&…...
【Golang】一文学完 Golang 基本语法
Golang 下载 安装包链接:https://share.weiyun.com/InsZoHHu IDE 下载:https://www.jetbrains.com/go/ 第一个 golang 程序 package mainimport "fmt"func main() {fmt.Println("hello golang") }每个可执行代码都必须包含 Pack…...

《Java-SE-第三十五章》之方法引用
前言 在你立足处深挖下去,就会有泉水涌出!别管蒙昧者们叫嚷:“下边永远是地狱!” 博客主页:KC老衲爱尼姑的博客主页 博主的github,平常所写代码皆在于此 共勉:talk is cheap, show me the code 作者是爪哇岛的新手,水平很有限&…...

Effective Java笔记(33)优先考虑类型安全的异构容器
泛型最常用于集合,如 Set<E >和 Map<K ,V>,以及单个元素的容器 ,如 ThreadLocal<T>和 AtomicReference<T> 。 在所有这些用法中,它都充当被参数化了的容器 。 这样就限制每个容器…...

释放AI创作潜能:从大模型训练到高产力应用
文章目录 每日一句正能量前言什么是人工智能生成内容(AIGC)人工智能生成内容(AIGC)能做什么为什么要用人工智能生成内容(AIGC)创作成果用Java实现冒泡排序算法学生信息收集系统学生请假管理系统需求分析教务…...

Ajax 笔记(一)—— Ajax 入门
笔记目录 1. Ajax 入门1.1 Ajax 概念1.2 axios 使用1.2.1 URL1.2.2 URL 查询参数1.2.3 小案例-查询地区列表1.2.4 常用请求方法和数据提交1.2.5 错误处理 1.3 HTTP 协议1.3.1 请求报文1.3.2 响应报文 1.4 接口文档1.5 案例1.5.1 用户登录(主要业务)1.5.2…...

Android Studio跳过Haxm打开模拟器
由于公司权限限制无法安装Haxm,这个时候我们可以试试Arm相关的镜像去跳过Haxm运行模拟器。解决方案:安装API27以下的Arm Image. #ifdef __x86_64__if (sarch "arm64" && apiLevel >28) {APANIC("Avds CPU Architecture %s i…...

从一个GPU到多个GPU
在多GPU运行应用程序时,需要正确设计GPU之间的通信,GPU间数据传输的效率取决于GPU是如何连接在一个节点上并跨集群的 在多GPU系统里有两种连接方式 多GPU通过单个节点连接到PCIe总线上 多GPU连接到集群中的网络交换机上 /* * 本示例演示了如何使用 Open…...
小白编写一个Chrome
步骤 1:了解插件的基本结构和功能 首先,向小白解释什么是Chrome插件,它是如何工作的,以及它可以做什么。强调插件可以修改网页内容、添加功能等。 步骤 2:准备工作 安装Chrome浏览器:确保小白的计算机上…...

自然语言处理学习笔记(六)————字典树
目录 1.字典树 (1)为什么引入字典树 (2)字典树定义 (3)字典树的节点实现 (4)字典树的增删改查 DFA(确定有穷自动机) (5)优化 1.…...

WPF实战项目十一(API篇):待办事项功能api接口
1、新建ToDoController.cs继承基础控制器BaseApiController,但是一般业务代码不写在控制器内,业务代码写在Service,先新建统一返回值格式ApiResponse.cs: public class ApiResponse{public ApiResponse(bool status, string mess…...
ffmpeg给视频添加时间水印,准确且不模糊
ffmpeg -i {输入文件路径} -vf{drawtext} {输出文件路径} 针对视频模糊,加上 -b:v {输出视频码率};右键属性,可查看离线视频源码率; 针对离线视频文件加上时间水印,时间跳变不正常,加上-re; 整…...

① vue复习。从安装到使用
vue官网:cn.vuejs.org vue安装 cnpm install -g vue/cli 查看是否安装成功 vue --version 创建一个项目 vue create vue-demo(项目名称) 这个取消掉。空格可选中或者取消。 运行项目: cd 进入到项目下 npm run serve 运行成功后,访问这…...

【Linux】多线程——线程引入 | 线程控制
文章目录 一、Linux多线程1. 线程概念2. 线程创建3. 线程和进程4. 线程的优缺点 二、线程控制1. 线程创建2. 线程终止3. 线程等待4. 线程分离5. 线程局部存储 三、线程封装 一、Linux多线程 一级页表和二级页表都是key/val模型,一级页表的key是第一份的10个比特位&a…...
查询树形目录(内存遍历成树返回)
实体 Data TableName("dtp_sm_servicetype") ApiModel(value "SmServicetype对象", description "服务类型") EqualsAndHashCode(callSuper true) public class SmServicetype extends BaseEntity {ApiModelProperty("服务类型名称&quo…...

Easys Excel的表格导入(读)导出(写)-----java
一,EasyExcel官网: 可以学习一些新知识: EasyExcel官方文档 - 基于Java的Excel处理工具 | Easy Excel 二,为什么要使用easyexcle excel的一些优点和缺点 java解析excel的框架有很多 : poi jxl,存在问题:非常的消耗内存, easyexcel 我们…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...

【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...

MySQL 知识小结(一)
一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库,分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷,但是文件存放起来数据比较冗余,用二进制能够更好管理咱们M…...

Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「storms…...

Rust 开发环境搭建
环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行: rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu 2、Hello World fn main() { println…...
苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会
在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...
Python网页自动化Selenium中文文档
1. 安装 1.1. 安装 Selenium Python bindings 提供了一个简单的API,让你使用Selenium WebDriver来编写功能/校验测试。 通过Selenium Python的API,你可以非常直观的使用Selenium WebDriver的所有功能。 Selenium Python bindings 使用非常简洁方便的A…...

Android写一个捕获全局异常的工具类
项目开发和实际运行过程中难免会遇到异常发生,系统提供了一个可以捕获全局异常的工具Uncaughtexceptionhandler,它是Thread的子类(就是package java.lang;里线程的Thread)。本文将利用它将设备信息、报错信息以及错误的发生时间都…...