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

多线程(看这一篇就够了,超详细,满满的干货)

多线程

  • 一.认识线程(Thread)
      • 1. 1) 线程是什么
      • 1. 2) 为啥要有线程
      • 1.3) 进程和线程的区别
          • 标题1.4) Java的线程和操作系统线程的关系
  • 二.创建线程
      • 方法1:继承Thread类
      • 方法2:实现Runnable接口
      • 方法3:匿名内部类创建Thread子类对象
      • 标题方法4:匿名内部类创建Runnable子类对象
      • 方法5:lambda表达式创建Runnable子类对象
  • 三.Thread类及其方法
      • 3.1Thread的常见构造方法
      • 3.2Thread的几个常见属性
      • 3.3获取当前线程引用
      • 3.4休眠当前线程
  • 四:线程的状态
      • 4.1线程的所有状态
      • 4.2线程状态和状态转移的意义
      • 4.3观察线程的状态和转移
          • 示例1:
          • 示例2:
  • 五:多线程带来的的风险-线程安全(重点)
      • 5.1线程安全的概念
      • 5.2线程不安全的原因
      • 5.3线程的几大特性
          • 5.3.1:原子性
          • 5.3.2:可见性
          • 5.3.3:指令重排序

在这里插入图片描述

​​在这里插入图片描述
在这里插入图片描述

​​​​​​

一.认识线程(Thread)

1. 1) 线程是什么

⼀个线程就是⼀个 “执行流”. 每个线程之间都可以按照顺序执行自己的代码. 多个线程之间 “同时” 执行着多份代码,main()⼀般被称为主线程(Main Thread)。

1. 2) 为啥要有线程

首先, “并发编程” 成为 “刚需”.

  • 单核 CPU 的发展遇到了瓶颈. 要想提高算力, 就需要多核 CPU. 而并发编程能更充分利用多核 CPU 资源.

  • 有些任务场景需要 “等待 IO”, 为了让等待 IO 的时间能够去做⼀些其他的工作, 也需要用到并发编程. 其次,
    虽然多进程也能实现 并发编程, 但是线程比进程更轻量.

  • 创建线程比创建进程更快.

  • 销毁线程比销毁进程更快.

  • 调度线程比调度进程更快.

最后, 线程虽然比进程轻量, 但是人们还不满足, 于是又有了 “线程池”(ThreadPool) 和 “协程”(Coroutine)
关于线程池我们后面再介绍. 关于协程的话题我们此处暂时不做过多讨论.

1.3) 进程和线程的区别

  • 进程是包含线程的. 每个进程至少有⼀个线程存在,即主线程。
  • 进程和进程之间不共享内存空间. 同⼀个进程的线程之间共享同⼀个内存空间.
  • 进程是系统分配资源的最小单位,线程是系统调度的最小单位。
  • ⼀个进程挂了⼀般不会影响到其他进程. 但是⼀个线程挂了, 可能把同进程内的其他线程⼀起带走(整 个进程崩溃)
标题1.4) Java的线程和操作系统线程的关系

线程是操作系统中的概念. 操作系统内核实现了线程这样的机制, 并且对用户层提供了⼀些API供用户使用(例如Linux的pthread库) 例如:Java标准库Thread的类可以视为是对操作系统提供的API进行了进⼀步的抽象和封装.

二.创建线程

方法1:继承Thread类

继承Thread来创建⼀个线程类,直接使用this就表示当前线程对象的引用

class MyThread extends Thread { @Overridepublic void run() {System.out.println("这⾥是线程运⾏的代码");}
}
public class Test {public static void main(String[] args)  {MyThread t = new MyThread();t.start();}
}

方法2:实现Runnable接口

实现Runnable接口,this表示的是 MyRunnable 的引用.需要使用Thread.currentThread()

class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("这⾥是线程运⾏的代码");}
}
public class Test {public static void main(String[] args)  {Thread t = new Thread(new MyRunnable());t.start();}
}

方法3:匿名内部类创建Thread子类对象

public class Test {public static void main(String[] args)  {// 使⽤匿名类创建 Thread ⼦类对象Thread t1 = new Thread() {@Overridepublic void run() {System.out.println("使⽤匿名类创建 Thread ⼦类对象");}};}
}

标题方法4:匿名内部类创建Runnable子类对象

public class Test {public static void main(String[] args)  {// 使⽤匿名类创建 Runnable ⼦类对象Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("使⽤匿名类创建 Runnable ⼦类对象");}});}
}

方法5:lambda表达式创建Runnable子类对象

public class Test {public static void main(String[] args)  {// 使⽤匿名类创建 Runnable ⼦类对象// 使⽤ lambda 表达式创建 Runnable ⼦类对象Thread t3 = new Thread(() -> System.out.println("使⽤匿名类创建 Thread ⼦类对象"));Thread t4 = new Thread(() -> {System.out.println("使⽤匿名类创建 Thread ⼦类对象");});}
}

三.Thread类及其方法

Thread 类是 JVM 用来管理线程的⼀个类,换句话说,每个线程都有⼀个唯⼀的 Thread 对象与之关联。而Thread 类的对象就是用来描述⼀个线程执行流的,JVM 会将这些 Thread 对象组织起来,用于线程调度,线程管理。

3.1Thread的常见构造方法

在这里插入图片描述

Thread t1 = new Thread();
Thread t2 = new Thread(new MyRunnable());
Thread t3 = new Thread("这是我的名字");
Thread t4 = new Thread(new MyRunnable(), "这是我的名字");

3.2Thread的几个常见属性

在这里插入图片描述

  • ID是线程的唯⼀标识,不同线程不会重复

  • 名称是各种调试工具用到

  • 状态表示线程当前所处的⼀个情况,下面我们会进⼀步说明

  • 优先级高的线程理论上来说更容易被调度到

关于后台线程,需要记住⼀点:JVM会在⼀个进程的所有非后台线程结束后,才会结束运行。 是否存活,即简单的理解,为run方法是否运行结束了

public class Test {public static void main(String[] args) {Thread thread = new Thread(() -> {for (int i = 0; i < 10; i++) {try {System.out.println(Thread.currentThread().getName());Thread.sleep(1 * 1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(Thread.currentThread().getName() + ": 我即将死去")});System.out.println(Thread.currentThread().getName() + ": ID: " + thread.getId());System.out.println(Thread.currentThread().getName() + ": 名称: " + thread.getName());System.out.println(Thread.currentThread().getName() + ": 状态: " + thread.getState());System.out.println(Thread.currentThread().getName() + ": 优先级: " + thread.getPriority());System.out.println(Thread.currentThread().getName() + ": 后台线程: " + thread.isDaemon());System.out.println(Thread.currentThread().getName() + ": 活着: " + thread.isAlive());System.out.println(Thread.currentThread().getName() + ": 被中断: " + thread.isInterrupted());thread.start();}
}

3.3获取当前线程引用

在这里插入图片描述

public class ThreadDemo {public static void main(String[] args) {Thread thread = Thread.currentThread();System.out.println(thread.getName());}
}

3.4休眠当前线程

也是我们比较熟悉⼀组方法,有⼀点要记得,因为线程的调度是不可控的,所以,这个方法只能保证
实际休眠时间是大于等于参数设置的休眠时间的。
在这里插入图片描述

public class ThreadDemo {public static void main(String[] args) throws InterruptedException {System.out.println(System.currentTimeMillis());Thread.sleep(3 * 1000);System.out.println(System.currentTimeMillis());}
}

四:线程的状态

4.1线程的所有状态

  • NEW:安排了工作,还未开始行动
  • RUNNABLE:可工作的.又可以分成正在工作中和即将开始工作.
  • BLOCKED:这几个都表示排队等着其他事情
  • WAITING:这几个都表示排队等着其他事情
  • TIMED_WAITING:这几个都表示排队等着其他事情
  • TERMINATED:工作完成了

4.2线程状态和状态转移的意义

在这里插入图片描述

4.3观察线程的状态和转移

示例1:

关注 NEW 、 RUNNABLE 、 TERMINATED 状态的转换

public class ThreadStateTransfer {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {for (int i = 0; i < 1000_0000; i++) {}}, "李四");System.out.println(t.getName() + ": " + t.getState());;t.start();while (t.isAlive()) {System.out.println(t.getName() + ": " + t.getState());;}System.out.println(t.getName() + ": " + t.getState());;}
}
示例2:

关注 WAITING 、 BLOCKED 、 TIMED_WAITING 状态的转换

public static void main(String[] args) {final Object object = new Object();Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {synchronized (object) {while (true) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}}, "t1");t1.start();Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {synchronized (object) {System.out.println("hehe");}}}, "t2");t2.start();}

使用jconsole可以看到t1的状态是TIMED_WAITING,t2的状态是BLOCKED

结论:

  • BLOCKED表示等待获取锁,WAITING和TIMED_WAITING表示等待其他线程发来通知.
  • TIMED_WAITING线程在等待唤醒,但设置了时限;WAITING线程在无限等待唤醒

五:多线程带来的的风险-线程安全(重点)

5.1线程安全的概念

想给出⼀个线程安全的确切定义是复杂的,但我们可以这样认为:如果多线程环境下代码运行的结果是符合我们预期的,即在单线程环境应该的结果,则说这个程序是线程安全的。

5.2线程不安全的原因

线程调度是随机的,这是线程安全问题的罪魁祸首,随机调度使⼀个程序在多线程环境下,执行顺序存在很多的变数.程序猿必须保证在任意执行顺序下,代码都能正常工作.

5.3线程的几大特性

5.3.1:原子性

代码实现时不会受到其它线程的穿插执行,这样就保证了这段代码的原子性了。
有时也把这个现象叫做同步互斥,表示操作是互相排斥的。

5.3.2:可见性

⼀个线程对共享变量值的修改,能够及时地被其他线程看到.

Java内存模型(JMM):Java虚拟机规范中定义了Java内存模型.目的是屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到⼀致的并发效果.
在这里插入图片描述

  • 线程之间的共享变量存在主内存(Main Memory).
  • 每⼀个线程都有自己的"工作内存"(Working Memory)
  • 当线程要读取⼀个共享变量的时候,会先把变量从主内存拷贝到工作内存,再从工作内存读取数据.
  • 当线程要修改⼀个共享变量的时候,也会先修改工作内存中的副本,再同步回主内存,由于每个线程有自己的工作内存,这些工作内存中的内容相当于同⼀个共享变量的"副本".此时修改线程1的工作内存中的值,线程2的工作内存不⼀定会及时变化.
5.3.3:指令重排序

什么是代码重排序
⼀段代码是这样的:
1.去前台取下U盘
2. 去教室写10分钟作业
3. 去前台取下快递 如果是在单线程情况下,JVM、CPU指令集会对其进行优化,比如,按1->3->2的方式执行,也是没问 题,可以少跑⼀次前台。这种叫做指令重排序 编译器对于指令重排序的前提是"保持逻辑不发生变化".这⼀点在单线程环境下比较容易判断,但是 在多线程环境下就没那么容易了,多线程的代码执行复杂程度更高,编译器很难在编译阶段对代码的 执行效果进行预测,因此激进的重排序很容易导致优化后的逻辑和之前不等价. 重排序是⼀个比较复杂的话题,涉及到CPU以及编译器的⼀些底层工作原理,此处不做过多讨论

在这里插入图片描述
如果觉得文章不错,期待你的一键三连哦,你个鼓励是我创作的动力之源,让我们一起加油,顶峰相见*!!!💓 💓 💓*

相关文章:

多线程(看这一篇就够了,超详细,满满的干货)

多线程 一.认识线程&#xff08;Thread&#xff09;1. 1) 线程是什么1. 2) 为啥要有线程1.3) 进程和线程的区别标题1.4) Java的线程和操作系统线程的关系 二.创建线程方法1:继承Thread类方法2:实现Runnable接口方法3:匿名内部类创建Thread子类对象标题方法4:匿名内部类创建Runn…...

爬虫进阶之selenium模拟浏览器

爬虫进阶之selenium模拟浏览器 简介环境配置1、建议先安装conda2、创建虚拟环境并安装对应的包3、下载对应的谷歌驱动以及与驱动对应的浏览器 代码setting.py配置scrapy脚本参考中间件middlewares.py 附录&#xff1a;selenium教程 简介 Selenium是一个用于自动化浏览器操作的…...

props传值

文章目录 props用于父组件向子组件传递数据&#xff0c;从而实现组件之间的通信。 以下是使用props的详细步骤&#xff1a; 父组件中定义 props&#xff1a; 在父组件中&#xff0c;通过在子组件的标签上添加属性来定义要传递的数据。这些属性就是props。 <!-- ParentCompon…...

IaC基础设施即代码:Terraform 使用for_each 创建DNS资源副本

目录 一、实验 1.环境 2.Terraform 使用 for_each 创建资源副本 &#xff08;DNS&#xff09; 一、实验 1.环境 &#xff08;1&#xff09;主机 表1-1 主机 主机系统软件工具备注jia Windows Terraform 1.6.6VS Code、 PowerShell、 Chocolatey 2.Terraform 使用 for_ea…...

dubbo入门案例!!!

入门案例之前我们先介绍一下&#xff1a;zookeeper。 Zookeeper是Apacahe Hadoop的子项目&#xff0c;可以为分布式应用程序协调服务&#xff0c;适合作为Dubbo服务的注册中心&#xff0c;负责服务地址的注册与查找&#xff0c;相当于目录服务&#xff0c;服务提供者和消费者只…...

sm2和aes加解密

引用maven包 <dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk18on</artifactId><version>1.72</version></dependency>2.对报文进行加密后生成签名 {// oristr报文 SECRET_KEY加密密钥String encrypt…...

cv2.findContours报错解决

问题引入 原代码: binary, contours, hierarchy cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) 发生了报错,这是因为我们这里返回了binary, contours, hierarchy三个值 这是opencv2里面的写法,在最新版opencv中只返回2个值 修改 contours, hierarchy c…...

RHEL - 更新升级软件或系统

《OpenShift / RHEL / DevSecOps 汇总目录》 文章目录 小版本软件更新yum update 和 yum upgrade 的区别升级软件和升级系统检查软件包是否可升级指定升级软件使用的发行版本方法1方法2方法3方法4 查看软件升级类型更新升级指定的 RHSA/RHBA/RHEA更新升级指定的 CVE更新升级指定…...

JNPF低代码开发平台总体架构介绍

目录 一、JNPF介绍 二、团队能力 三、技术选型 1.后端技术栈 2.前端技术栈 3.数据库支持 四、JNPF界面示意图 五、开发环境 一、JNPF介绍 JNPF是一款企业级低代码开发平台。基于Springboot、Vue技术&#xff0c;采用微服务、前后端分离架构&#xff0c;基于可视化数据建…...

axios的传参方式

目录 1、data传参 2、使用 params 传递查询参数&#xff1a; 3、使用路径参数传递数据&#xff1a; 在使用 Axios 发送 HTTP 请求时&#xff0c;有三种常见的传参方式&#xff1a;data、params 和路径参数 1、data传参 this.$axios({method: "post",url: "h…...

受电端协议芯片是如何让Type-C接口设备实现快充?

随着科技的不断进步&#xff0c;USB Type-C接口在电子产品中越来越普及。而在这个接口中&#xff0c;Type-c受电端协议芯片起着至关重要的作用。那么&#xff0c;什么是Type-c受电端协议芯片&#xff1f;它又是如何工作的呢&#xff1f;本文将为您揭开Type-c受电端协议芯片的神…...

浪花 - 搜索标签前后端联调

前传&#xff1a;浪花 - 根据标签搜索用户-CSDN博客 目录 一、完善后端搜索标签接口 二、前后端搜索标签接口的对接 1. 使用 Axios 发送请求 2. 解决跨域问题 3. Axios 请求传参序列化 4. 接收后端响应数据 5. 处理后端响应数据格式 6. 搜索结果为空的页面展示 附&am…...

GPU与SSD间的P2P DMA访问机制

基于PCIe&#xff08;Peripheral Component Interconnect Express&#xff09;总线连接CPU、独立GPU和NVMe SSD的系统架构。 在该架构中&#xff0c;PCIe Swicth支持GPU与SSD之间快速的点对点直接内存访问&#xff08;peer-to-peer, p2p DMA&#xff09;。通常情况下&#xff0…...

未来的NAS:连接您的数字生活

未来的NAS&#xff1a;连接您的数字生活 引言 网络附加存储&#xff08;Network Attached Storage&#xff0c;简称NAS&#xff09;是一种通过网络连接的存储设备&#xff0c;用于集中存储和共享数据。传统的NAS设备通常包含一个或多个硬盘驱动器&#xff0c;可以通过局域网连…...

C++ 设计模式之备忘录模式

【声明】本题目来源于卡码网&#xff08;题目页面 (kamacoder.com)&#xff09; 【提示&#xff1a;如果不想看文字介绍&#xff0c;可以直接跳转到C编码部分】 【设计模式大纲】 【简介】 -- 什么是备忘录模式 &#xff08;第17种模式&#xff09; 备忘录模式&#xff08;Meme…...

【项目搭建三】SpringBoot引入redis

添加依赖 本文使用spring data redis访问和操作redis&#xff0c;pom文件中加入以下依赖&#xff1a; <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </depende…...

漫谈广告机制设计 | 听闻RTA要搞二次竞价了?牛啊!

听闻RTA要搞二次竞价了&#xff1f; 读者群里反馈说&#xff0c;某大厂的RTA支持做二次竞价了。笔者听闻后&#xff0c;竖起了大拇指&#xff0c;牛&#xff01; RTA RTA&#xff08;Real Time API), 是一种实时的广告程序接口&#xff0c;用于满足广告主实时个性化的投放需…...

第04章_IDEA的安装与使用(下)(IDEA断点调试,IDEA常用插件)

文章目录 第04章_IDEA的安装与使用&#xff08;下&#xff09;8. 快捷键的使用8.1 常用快捷键8.2 查看快捷键1、已知快捷键操作名&#xff0c;未知快捷键2、已知快捷键&#xff0c;不知道对应的操作名 8.3 自定义快捷键8.4 使用其它平台快捷键 9. IDEA断点调试(Debug)9.1 为什么…...

HBase鉴权设计以及Kerberos鉴权方法

文章目录 1. HBase鉴权方式整理2. Kerboers鉴权架构整理2.1 kerberos的实现架构2.2 相关核心参数整理 3. 客户端的鉴权设计3.1 安全管控权限3.2 安全管控级别3.3 相关操作3.3.1 用户授权3.3.2 回收权限 4. 疑问和思考6. 参考文章 鉴权&#xff0c;分别由鉴和权组成 鉴&#xf…...

【华为GAUSS数据库】IDEA连接GAUSS数据库方法

背景&#xff1a;数据库为华为gauss for opengauss 集中式数据库 IDEA提供了丰富的各类型数据库驱动&#xff0c;但暂未提供Gauss数据库。可以通过以下方法进行连接。 连接后&#xff0c; 可以自动检查xml文件中的sql语句是否准确&#xff0c;表名和字段名是否正确还可以直接在…...

19c补丁后oracle属主变化,导致不能识别磁盘组

补丁后服务器重启&#xff0c;数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后&#xff0c;存在与用户组权限相关的问题。具体表现为&#xff0c;Oracle 实例的运行用户&#xff08;oracle&#xff09;和集…...

业务系统对接大模型的基础方案:架构设计与关键步骤

业务系统对接大模型&#xff1a;架构设计与关键步骤 在当今数字化转型的浪潮中&#xff0c;大语言模型&#xff08;LLM&#xff09;已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中&#xff0c;不仅可以优化用户体验&#xff0c;还能为业务决策提供…...

Ubuntu系统下交叉编译openssl

一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机&#xff1a;Ubuntu 20.04.6 LTSHost&#xff1a;ARM32位交叉编译器&#xff1a;arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

python打卡day49

知识点回顾&#xff1a; 通道注意力模块复习空间注意力模块CBAM的定义 作业&#xff1a;尝试对今天的模型检查参数数目&#xff0c;并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

Angular微前端架构:Module Federation + ngx-build-plus (Webpack)

以下是一个完整的 Angular 微前端示例&#xff0c;其中使用的是 Module Federation 和 npx-build-plus 实现了主应用&#xff08;Shell&#xff09;与子应用&#xff08;Remote&#xff09;的集成。 &#x1f6e0;️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...

论文笔记——相干体技术在裂缝预测中的应用研究

目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术&#xff1a;基于互相关的相干体技术&#xff08;Correlation&#xff09;第二代相干体技术&#xff1a;基于相似的相干体技术&#xff08;Semblance&#xff09;基于多道相似的相干体…...

在Ubuntu24上采用Wine打开SourceInsight

1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行

项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战&#xff0c;克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...

七、数据库的完整性

七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...