当前位置: 首页 > news >正文

JUC并发编程——Java线程(一)

文章目录

  • 1. 线程的创建
    • 1.1 方法1: 直接使用Thread
    • 1.2 方法2:使用Runnable配合Thread
    • 1.3 方法3:FutureTask配合Thread
  • 2. 线程运行
    • 2.1 原理
    • 2.2 常见方法
      • 2.2.1 start与run
      • 2.2.2 sleep与yield
      • 2.2.3 join
      • 2.2.4 interrupt
  • 3. 主线程和守护线程
  • 4. 线程状态
    • 4.1 五种状态
    • 4.2 六种状态


1. 线程的创建

1.1 方法1: 直接使用Thread

Thread t = new Thread(){@Overridepublic void run(){// 要执行的任务}
};
// 启动线程
t.start();

1.2 方法2:使用Runnable配合Thread

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

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

java8以后可以使用lambda精简代码

Runnable r = () -> {log.debug("running");
};
Thread t = new Thread(r, "t2");
t.start();

小结:

  1. 方法1是把线程和任务合并在了一起,方法2是把线程和任务分开了。
  2. 用Runnable更容易把线程池等高级API配合。
  3. 用Runnable让任务类脱离了Thread继承体系,更灵活。

1.3 方法3:FutureTask配合Thread

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

FutureTask<Integer> task = new FutureTask<>(new Callable<Integer>(){@Overridepublic Integer call() throws Exception {log.debug("running");Thread.sleep(1000);return 100;}
});Thread t = new Thread(task);
t.start();log.debug("{}", task.get());

2. 线程运行

2.1 原理

栈与栈帧
JVM由堆、栈、方法区所组成,其中栈内存给线程使用,每个线程启动后哦,虚拟机就会为其分配一块栈内存。

  • 每个栈由多个栈帧(Frame)组成,对应着每次方法调用时所占用的内存。
  • 每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法。

线程上下文切换(Thread Context Switch)
因为以下一些原因导致cpu不再执行当前的线程,转而执行另一个线程的代码

  • 线程cpu时间片用完
  • 垃圾回收
  • 有更高优先级的线程需要运行
  • 线程自己调用了sleep、yield、wait、join、park、sychronized、lock等方法程序

当Context Switch 发生时,需要由操作系统保存当前线程的状态,并恢复另一个线程的状态,Java中对应的概念就是程序计数器,它的作用是记住下一条jvm指令的执行地址,是线程私有的。

  • 状态包括程序计数器、虚拟机栈中每个栈帧的信息,如局部变量、操作数栈、返回地址等。
  • Context Switch频繁发生会影响性能。

多线程

2.2 常见方法

2.2.1 start与run

  • 启动线程必须要调用start(),不然对性能没影响。
  • start()不能多次调用
public class Test4{public static void main(String[] args){Thread t1 = new Thread("t1") {@Overridepublic void run() {log.debug("running....");}};// t1.run();t1.start();}
}

2.2.2 sleep与yield

sleep

  1. 调用sleep会让当前线程从Running进入Timed Waiting状态。
  2. 其它线程可以使用interrupt方法打断正在睡眠的线程,这时sleep方法会抛出InterruptedException。
  3. 睡眠结束后的线程未必立刻得到执行。
  4. 建议用TimeUnit的sleep代替Thread的sleep来获得更好的可读性。

yield

  1. 调用yield会让当前线程从Running进入Runnable状态,然后调度执行其它同优先级的线程。如果这时没有同优先级的线程,那么不能保证让当前线程暂停的效果。
  2. 具体的实现依赖于操作系统的任务调度器。

线程优先级

  • 线程优先级会提示调度器优先调度该线程,但仅仅是一个提示,调度器可以忽略它。
  • 如果cpu比较忙,那么优先级高的线程会获得更多的时间片,但cpu闲时,优先级几乎没作用。

sleep实现
在没有利用cpu来计算时,不要让while(true)空转浪费cpu,这时可以用yield或sleep来让出cpu的使用权给其他程序。

while(true){try{Thread.sleep(50);} catch (InterruptedException e){e.printStackTrace();}
}
  • 可以用wait 或 条件变量达到类似的效果。
  • 不同的是,后两种都需要加锁,并且需要相应的唤醒操作,一般适用于要进行同步的场景。
  • sleep适用于无需锁同步的场景。

2.2.3 join

等待线程运行结束

t1.start();
t1.join();

应用之同步(案例1)
以调用方角度来讲,如果

  • 需要等待结果返回,才能继续运行就是同步
  • 不需要等待结果返回,就能继续运行就是异步

2.2.4 interrupt

打断sleep,wait,join的线程
eg:打断sleep的线程,会清空打断状态。

private static void test1() throws InterruptedException {Thread t1 = new Thread(() ->{sleep(1);}, "t1");t1.start();sleep(0.5);t1.interrupt();log.debug("打断状态:{}", t1.isInterrupted());
}

eg:打断正常运行的线程,不会清空打断状态。

两阶段终止模式
在一个线程T1中如何“优雅”终止T2,即给T2一个善后的机会。

错误思路如下:

  • 使用线程对象stop()方法停止线程
    • stop方法会真正杀死线程,如果这时线程锁住了共享资源,那么当它被杀死后就再也没有机会释放锁,其他线程将永远无法获取锁。
  • 使用System.exit(int)方法停止线程
    • 目的仅是停止一个线程,但这种做法会让整个程序都停止。

在这里插入图片描述

public class Test3{public static void main(String[] args){TwoPhaseTermination tpt = new TwoPhaseTermination();tpt.start();	Thread.sleep(3500);tpt.stop();}
}class TwoPhaseTermination{private Thread monitor;// 启动监控线程public void start(){monitor = new Thread(() -> {while(true){Thread current = Thread.currentThread();if(current.isInterrupted()){log.debug("料理后事");break;}try{Thread.sleep(1000); // 情况1log.debug("执行监控记录"); // 情况2} catch(InterruptedExcetion e){e.printStackTrace();// 重新设置打断标记current.interrupt();}}}); }// 停止监控线程public void stop(){monitor.intterupt();}
}

打断park线程,不会清空打断状态。
如果打断标记已经是true,则park会失效。

不推荐的方法:

  1. stop() 停止线程运行
  2. suspend() 挂起(暂停)线程运行
  3. resume() 恢复线程运行

3. 主线程和守护线程

默认情况下,Java进程需要等待所有线程都运行结束,才会结束。有一种特殊的线程叫做守护线程,只要其它非守护线程运行结束了,即使守护线程的代码没有执行完,也会强行结束。

log.debug("开始运行...");
Thread t1 = new Thread(() -> {log.debug("开始运行...");sleep(2);log.debug("运行结束...");
}, "daemon");
t1.setDaemon(true);
t1.start();sleep(1);
log.debug("运行结束...");

4. 线程状态

4.1 五种状态

这是从操作系统层面来描述的
在这里插入图片描述

  • 初始状态: 仅仅在语言层面创建了线程对象,还未与操作系统线程关联。
  • **可运行状态:**指该线程已经被创建(与操作系统线程关联),可以由CPU调度执行
  • 运行状态: 指获取了CPU时间片运行中的状态。
    • 当CPU时间片用完,会从 运行状态 切换至 可运行状态, 会导致线程的上下文切换
  • 阻塞状态:
    • 如果调用了阻塞API,如BIO读写文件,这时该线程实际不会用到CPU,会导致线程上下文切换,进入阻塞状态
    • 等BIO操作完毕,会由操作系统唤醒阻塞的线程,转换至可运行状态
    • 可运行状态的区别是,对阻塞状态的线程来说只要它们一直不唤醒,调度器就一直不回考虑调度它们。
  • **终止状态:**表示线程已经执行完毕,生命周期已经技术,不会再转换为其它状态。

4.2 六种状态

这是从Java API层面来描述的。
在这里插入图片描述
根据Thread.State 枚举,分为六种状态。

  1. NEW 线程刚被创建,但是还没有调用start()方法。
  2. RUNNABLE当调用了start()方法之后,注意,Java API层面的RUNNABLE状态涵盖了操作系统层面的可运行状态运行状态阻塞状态(由于BIO导致的线程阻塞,在Java里无法区分,仍然认为是可运行)。
  3. BLOCKED、WAITING、TIMED_WAITING都是Java API层面对阻塞状态的细分,后面会在状态转换一节详述。
  4. TERMINATED当线程代码运行结束。

相关文章:

JUC并发编程——Java线程(一)

文章目录 1. 线程的创建1.1 方法1&#xff1a; 直接使用Thread1.2 方法2&#xff1a;使用Runnable配合Thread1.3 方法3&#xff1a;FutureTask配合Thread 2. 线程运行2.1 原理2.2 常见方法2.2.1 start与run2.2.2 sleep与yield2.2.3 join2.2.4 interrupt 3. 主线程和守护线程4. …...

Python入门笔记3

ros小车亚博官网例子延时性基本上跑完了&#xff0c;发现自己一些基础Python语法还不熟悉。 本节学习循环&#xff1a; while\for\break\continue 1. while 循环 while 循环会在条件表达式为真时&#xff0c;重复执行一段代码块&#xff0c;直到条件表达式变为假。 格式&am…...

【SQL教程|07】sql中条件查询where用法示例

SQL WHERE 条件查询教程 在SQL中&#xff0c;WHERE 条件用于在 SELECT 语句后过滤结果集&#xff0c;只返回符合条件的记录。它帮助我们从大量数据中提取所需的信息。以下是使用 WHERE 条件的逐步指南。 1. 基本语法 SELECT [字段] FROM [表] WHERE [条件];SELECT&#xff1a…...

项目实战(13)-双频RFID语音播报阅读器

一. 产品简介&#xff1a; 1、项目背景是在实际应用中需要读取射频标签ID&#xff0c;但是市面上这种标签类型不统一&#xff1b;有的频段是125KHz&#xff0c;高频的是13.56MHz。所以需要一个读卡模块实现这两种卡的识别读取。 2、板子核心处理器是STM32F407&#xff0c;显示…...

基本控制环节的幅频和相频特性

基本控制环节的幅频和相频特性 在控制系统中&#xff0c;不同类型的控制环节具有各自独特的动态特性。为了研究这些环节对信号的影响&#xff0c;通常需要分析其频率响应特性&#xff0c;即幅频特性和相频特性。以下对几种常见的基本控制环节进行逐一分析。 1. 比例环节 比例…...

vue3 ref和reactive的区别

在 Vue 3 中&#xff0c;ref 和 reactive 是两种用于创建响应式数据的 API&#xff0c;但它们的使用场景和实现方式有一些区别。用大白话来说&#xff0c;它们的区别可以这样理解&#xff1a; 1. ref&#xff1a;适合处理简单数据 是什么&#xff1a;ref 是用来包装一个基本类…...

Maven 构建报告与文档生成

Maven 是一种强大的构建工具&#xff0c;它不仅可以帮助我们构建和管理项目&#xff0c;还提供了生成项目报告和文档的功能。通过 Maven 的插件&#xff0c;我们可以自动生成代码文档&#xff08;如 Javadoc&#xff09;&#xff0c;执行测试并生成测试报告&#xff0c;以及其他…...

复制内容到软件内部,软件内部内容不刷新

在Windows 10系统中&#xff0c;遇到复制内容后需要点击任务栏才能刷新软件内容的问题&#xff0c;可能是由于软件自身刷新机制、系统资源管理或显卡驱动等原因导致。以下是逐步解决方案 1. 检查软件设置 开启自动刷新功能&#xff1a;某些软件&#xff08;如文件管理器、IDE、…...

C# 实现完善 Excel 不规则合并单元格数据导入

目录 功能完善 Excel与DataSet的映射关系 运行环境 Excel DCOM 配置 设计实现 组件库引入 方法更新 返回值 参数设计 打开数据源并计算Sheets 拆分合并的单元格 创建DataTable 将单元格数据写入DataTable 删除虚拟列 总结 功能完善 在我的文章 《C#实现Excel…...

C#功能测试

List 内部元素为引用 src[0]为"11" List<Source> src new List<Source>(); src.Add(new Source() { Name "1", Age 1, Description "1" }); src.Add(new Source() { Name "2", Age 2, Description "2"…...

C++17并行化加速STL算法——std::execution

C17 并行化STL算法 文章目录 C17 并行化STL算法概念环境准备工具类 并行算法 - 使用并行算法 - 执行策略总览选择标准详细介绍顺序执行 seq并行化顺序执行 par并行化乱序执行 par_unseq 并行算法 - 异常处理可以不使用并行算法并行算法 - 限制并行算法有哪些原有算法17引入新算…...

从sumsub获取用户图片

已经拿到了imageid 然后从哪个接口可以获取图片文件呢&#xff1f; 根据您的问题,我可以为您提供以下信息: 一旦您获得了imageId,您可以使用以下几个API接口来获取图片文件: 获取文档图片: Get document images GET https://api.sumsub.com/resources/inspections/{inspection…...

DeepSeek + Mermaid编辑器——常规绘图

下面这张图出自&#xff1a;由清华大学出品的 《DeepSeek&#xff1a;从入门到精通》。 作为纯文本生成模型&#xff0c;DeepSeek虽不具备多媒体内容生成接口&#xff0c;但其开放式架构允许通过API接口与图像合成引擎、数据可视化工具等第三方系统进行协同工作&#xff0c;最终…...

ARM64 Trust Firmware [五 ]

本章介绍 ATF 中的 Runtime Service 是如何定义和被调用的。 要了解 SMC&#xff0c;必须从 SMC 指令本身开始&#xff0c;其指令如下图&#xff1a; 指令格式为&#xff1a;SMC #<imm>&#xff0c;从官方文档了解到该指令只能在 EL1 以及更高的异常等级上调用&#xff…...

Excel核心函数VLOOKUP全解析:从入门到精通

一、函数概述 VLOOKUP是Excel中最重要且使用频率最高的查找函数之一&#xff0c;全称为Vertical Lookup&#xff08;垂直查找&#xff09;。该函数主要用于在数据表的首列查找特定值&#xff0c;并返回该行中指定列的对应值。根据微软官方统计&#xff0c;超过80%的Excel用户在…...

KTransformers如何通过内核级优化、多GPU并行策略和稀疏注意力等技术显著加速大语言模型的推理速度?

KTransformers通过内核级优化、多GPU并行策略和稀疏注意力等技术显著加速大语言模型的推理速度&#xff0c;具体体现在以下几个方面&#xff1a; 内核级优化&#xff1a; KTransformers采用了高效的内核级优化技术&#xff0c;包括对Transformer模型中的关键操作进行优化。例如…...

审计级别未启用扩展模式导致查询 DBA_AUDIT_TRAIL 时 SQL_TEXT 列为空

如果查询 DBA_AUDIT_TRAIL 时发现 SQL_TEXT 列为空&#xff0c;但其他字段&#xff08;如 OS_USERNAME、USERNAME、TIMESTAMP 等&#xff09;有数据&#xff0c;可能是由于以下原因之一。以下是可能的原因及解决方法&#xff1a; 1. 审计级别未启用扩展模式 默认情况下&#x…...

微信小程序项目 video 组件失效问题,无法播放本地视频

问题与处理策略 问题描述 <video src"../../assets/video/test-video.mp4" controls style"width: 100%; height: 300px;"></video>在微信小程序项目中&#xff0c;上述 video 组件失效&#xff0c;视频无法加载&#xff0c;无法播放本地视频…...

若依-@Excel新增注解numberFormat

Excel注解中原本的scale会四舍五入小数&#xff0c;导致进度丢失 想要的效果 显示的时候保留两个小数真正的数值是保留之前的数值 还原过程 若以中有一個專門的工具类&#xff0c;用来处理excel的 找到EXCEL导出方法exportExcel()找到writeSheet,写表格的方法找到填充数据的方法…...

网络安全行业有哪些公司

只是简单做一下网络安全公司梳理&#xff0c;不作点评&#xff0c;下列排名不分先后。 一、常见的网络安全公司 1、天融信 天融信&#xff08;002212.SZ&#xff09;创始于1995年&#xff0c;是上市公司中成立最早的网络安全企业&#xff0c;亲历中国网络安全产业的发展历程…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻

在如今就业市场竞争日益激烈的背景下&#xff0c;越来越多的求职者将目光投向了日本及中日双语岗位。但是&#xff0c;一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧&#xff1f;面对生疏的日语交流环境&#xff0c;即便提前恶补了…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器

一.自适应梯度算法Adagrad概述 Adagrad&#xff08;Adaptive Gradient Algorithm&#xff09;是一种自适应学习率的优化算法&#xff0c;由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率&#xff0c;适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖

在前面的练习中&#xff0c;每个页面需要使用ref&#xff0c;onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入&#xff0c;需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

【2025年】解决Burpsuite抓不到https包的问题

环境&#xff1a;windows11 burpsuite:2025.5 在抓取https网站时&#xff0c;burpsuite抓取不到https数据包&#xff0c;只显示&#xff1a; 解决该问题只需如下三个步骤&#xff1a; 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...

爬虫基础学习day2

# 爬虫设计领域 工商&#xff1a;企查查、天眼查短视频&#xff1a;抖音、快手、西瓜 ---> 飞瓜电商&#xff1a;京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空&#xff1a;抓取所有航空公司价格 ---> 去哪儿自媒体&#xff1a;采集自媒体数据进…...

重启Eureka集群中的节点,对已经注册的服务有什么影响

先看答案&#xff0c;如果正确地操作&#xff0c;重启Eureka集群中的节点&#xff0c;对已经注册的服务影响非常小&#xff0c;甚至可以做到无感知。 但如果操作不当&#xff0c;可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...

网站指纹识别

网站指纹识别 网站的最基本组成&#xff1a;服务器&#xff08;操作系统&#xff09;、中间件&#xff08;web容器&#xff09;、脚本语言、数据厍 为什么要了解这些&#xff1f;举个例子&#xff1a;发现了一个文件读取漏洞&#xff0c;我们需要读/etc/passwd&#xff0c;如…...

STM32HAL库USART源代码解析及应用

STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...

ZYNQ学习记录FPGA(一)ZYNQ简介

一、知识准备 1.一些术语,缩写和概念&#xff1a; 1&#xff09;ZYNQ全称&#xff1a;ZYNQ7000 All Pgrammable SoC 2&#xff09;SoC:system on chips(片上系统)&#xff0c;对比集成电路的SoB&#xff08;system on board&#xff09; 3&#xff09;ARM&#xff1a;处理器…...

算法打卡第18天

从中序与后序遍历序列构造二叉树 (力扣106题) 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1: 输入&#xff1a;inorder [9,3,15,20,7…...