news 2026/9/11 13:31:24

Java EE初阶--多线程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java EE初阶--多线程

一.为何使用线程?

在过去年代的计算机,大部分采用了并发编程,一个服务器可以服务多个客户端,每给一个客户端服务就会创建一个进程,服务完之后就会销毁进程。一个进程的创建和销毁开销比较大,频繁的创建和销毁严重浪费资源,所以就引入了线程的概念

二.线程和进程的区别

1. 一个进程至少包含一个线程,一个线程即是一段代码指令。

2. 进程和进程不共享空间,线程和进程共享空间

3. 一个进程挂了,不会影响其他进程,一个线程挂了,可能会导致整个进程崩溃

4.进程调度和线程调度调度机制一样,具体实现不一样,如调度周期和调度单位(进程是操作系统分配资源的基本单位,线程是系统调度的基本单位)

5.进程和线程的开销代价不一样

  • 创建一个新进程

    • ✅ 需要创建一个全新的、独立的地址空间(一大块新地皮和新厂房)。

    • ✅ 需要将父进程的代码和数据复制或映射到这个新地址空间中。

    • ✅ 需要创建进程控制块(PCB),这个结构比TCB更复杂。

    • ✅ 需要分配独立的文件描述符表等。

    • 同时,它内部第一个线程的创建成本(TCB、栈等)也同样存在。

    • 总结:进程创建是“从零开始建一个新工厂”,开销巨大。

  • 创建一个新线程

    • ✅ 需要分配一个独立的栈(一小块工作台)。

    • ✅ 需要创建一个线程控制块TCB(一个工牌和日志)。

    • 不需要创建新的地址空间、复制代码数据等。

    • 总结:线程创建是“在现有工厂里增加一条生产线”,开销极小。

三.Java的线程和操作系统之间的关系

线程是操作系统内的概念,操作系统内核实现了该机制,并提供了一些api供用户使用来操控线程

api介绍:又名为应用程序编程接口,就是一个实现一些功能的封装,拿过来就可以用。

Java 标准库中 java.lang(默认导入,不需要手动导入包) 中的Thread类可以视为是对操作系统提供的API进⾏了进⼀步的抽象和封装.

四.线程的创建和使用

五.创建线程的不同形式

六.低耦合高内聚

在程序的过程中都是采用低耦合高内聚的方式写代码

低耦合即降低模块和模块之间的关系,一个模块变化尽量不影响其他模块,不会因一个变化牵动全身

高内聚即一个模块之类把有关联的东西放在一块,到时好找到对应的东西

对比继承Thread类,实现Runnable接口达到了低耦合高内聚的效果,原因是Thread将任务逻辑(run方法)与线程执行机制(Thread类)紧密绑定

七.Thread类的常用方法及其使用

1.构造方法

2.普通方法

2.1 getId()

作用:获取线程ID,不同线程有不同的ID.

2.2 getName()

作用:获取线程的名字

2.3 getPriority()

2.4 isDaemon()和setDaemon()

作用:看是否为后台线程和设置后台线程(得在启动线程前设置)

前台线程:进程会等待所有前台线程都执行完毕后才会终止,我们创造的线程默认为前台线程

后台线程:当前台线程都执行完毕,进程不会等待后台线程执行完毕,会直接结束进程,后台线程会强制终止

使用:

2.5 isAlive()

作用:看线程是否结束

2.6 isInterrupt()、interrupted()、interrupt()

使用其他办法:

使用该方法:

2.7 join()

作用:哪个线程调用这个,并在该线程使用,那该线程得等待调用该方法的线程结束才会执行join()下面的类容

使用原因:如果要控制线程结束的先后顺序,用sleep()方法可能达到效果,但是由于抢占式调度,出现各种可能性,该方法就有时不靠谱,而该方法可以强制控制线程的先后顺序

使用:

2.8 sleep()

作用是休眠,且能控制休眠时间,这些能控制时间的方法,但设置的时间到后不是立即执行,而是要进行一些内部操作才去执行其他指令,所以要比设置的时间长一些

sleep(0): 代表该线程立即放弃cpu资源,让优先级更高的线程吃到cpu资源

2.9 getState()

作用:观察某个线程的状态,根据这个更好的调试代码。

在Thread中的Thread.State是枚举类型,以下为枚举常量

举例:

八.多线程带来的安全问题 --- 线程安全(重点)

举例:

九. 线程安全产生的原因和解决方案

1.线程调度机制为抢占式调度

系统设定,程序员左右不了

2.多个线程同时修改同一个变量

调正代码结构,规避一些线程不安全的代码

3.修改操作不是原子的(如事务中的原子性,一个事务不会执行到一半,而 cpu可能将指令执行到一半就会调到其他指令了)

可以通过加锁来把一些操作打包成原子的

十.synchronized 关键字 - 监视器锁 monitor lock

1.synchronized的特性

1)互斥

synchronized会起到互斥效果,某个线程执⾏到某个对象的synchronized中时,其他线程如果也执⾏ 到同⼀个对象synchronized就会阻塞等待

使用:

2)可重入

十一.死锁

1.一个线程,一把锁,连续加锁俩次

在Java 的synchronized 中构成可重入锁,在C++中会构成死锁

2.两个线程,两个锁,尝试获取对方的锁

3.N个线程,M把锁

举例:哲学家就餐模型

描述:5个哲学家(线程)共有5个筷子(锁)在一个桌子上吃面(想实现的逻辑),哲学家要么思考要么拿到俩个筷子就可以吃面条,吃完面条就放下筷子。如果别人拿到筷子,只能阻塞等待到他放下筷子才有机会拿到筷子

问题:当每个哲学家同时拿到一根筷子,每个哲学家就会拿不到其他人的筷子,就会产生死锁即:

哲学家1拿到 锁1等其他哲学家都拿到自己的锁后尝试获取锁2

哲学家2拿到 锁2等其他哲学家都拿到自己的锁后尝试获取锁3

哲学家3拿到 锁3等其他哲学家都拿到自己的锁后尝试获取锁4

哲学家4拿到 锁4等其他哲学家都拿到自己的锁后尝试获取锁5

哲学家5拿到 锁5等其他哲学家都拿到自己的锁后尝试获取锁1

注意:这里必须是拿到第一个锁之后不释放的前提下去获取对方的锁

十二. 如何避免出现死锁呢?构成死锁的四个必要条件(重点)。

1.锁是互斥的 2.锁是不可剥夺的(锁的基本的性质)

一个线程拿到锁后,其他想获取锁就得阻塞等待,而且不能剥夺该锁

解决方案:自己实现个锁

3.保持和请求

一个线程在已经获取锁1的情况下(不提前释放锁1)获取锁2

解决方案:避免嵌套锁,在释放该线程的锁后才去获取别的锁

4.循环等待

线程A等线程B,线程B等线程C,线程C等线程A.

解决方案:约定加锁的顺序,如哲学家就餐问题:

哲学家1拿到 锁1:持有锁1尝试获取哲学家2的锁2

哲学家2拿到 锁2:持有锁2尝试获取哲学家3的锁3

哲学家3拿到 锁3:持有锁3尝试获取哲学家4的锁4

哲学家4拿到锁4:持有锁4尝试获取哲学家5的锁5

哲学家5 : 尝试拿锁1阻塞等待,最后拿锁5

由于哲学家5没有持有锁5,哲学家4就可以吃到面条,同时释放锁4,哲学家3就可以拿到锁4吃到面条,依次类推,最后哲学家5吃到面条结束。

十三.Java标准库中的线程安全类

线程不安全的类:

• ArrayList • LinkedList • HashMap • TreeMap • HashSet • TreeSet • StringBuilder

线程安全的类:

十四.内存可见性

造成线程安全可见性的原因之一

原因:编译器优化,即在逻辑不变的情况下,提升性能,但在多线程的情况下可能出现失误,导致优化后的逻辑和优化前的逻辑出现误差

解决方案:

注意:volatile解决的是内存可见性的问题,不可以解决原子性问题

十五.java内存模型(Java Memory Model (JMM))

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 13:27:34

Q(V)-特征控制在新能源配电网中的Matlab仿真与实践

1. 项目背景与核心问题在新能源高比例接入的现代配电网中,变流器作为分布式电源与电网的接口设备,其控制策略的稳定性直接影响整个电力系统的安全运行。传统基于P-Q控制的变流器在弱电网条件下容易出现稳定性问题,而Q(V)-特征控制通过引入电压…

作者头像 李华
网站建设 2026/9/11 13:26:47

HTML大屏模板实战指南:从结构解析到生产部署

简介:本资源是一套开箱即用的17个HTML大屏展示模板,面向数据可视化工程师、前端开发人员及政企数字化项目实施人员,解决大数据监控场景下快速构建高视觉表现力、强交互性的全屏数据看板问题。模板覆盖智慧农业、警务监控、车辆管控、压力容器…

作者头像 李华
网站建设 2026/9/11 13:26:10

前端动画性能优化:解决大数据量下的卡顿问题

1. 前端动画卡顿问题解析:当滑出动画遇上大数据量最近在优化一个电商项目时遇到了典型的性能问题:商品列表的滑出动画在数据量超过200条时出现明显卡顿。这种"优雅动画变PPT"的现象其实反映了前端性能优化的核心矛盾——视觉流畅度与数据处理能…

作者头像 李华
网站建设 2026/9/11 13:24:46

Java反射机制原理与性能优化实践

1. Java反射机制深度解析反射是Java语言中最为强大也最为复杂的特性之一,它允许程序在运行时动态地获取类的信息并操作类或对象。这种能力使得Java程序具备了极强的灵活性,但同时也带来了性能开销和安全风险。我们先从一个实际案例开始理解反射的价值&am…

作者头像 李华