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

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))

http://www.dtcms.com/a/478583.html

相关文章:

  • 深入理解梯度消失:从DNN到RNN的全面解析与解决方案
  • 南京电子商务网站开发公司石油化工工程建设人才招聘网站
  • 大数据实战:Python+Flask 汽车数据分析可视化系统(爬虫+线性回归预测+推荐 源码+文档)✅
  • 算法8.0
  • 网站左侧导航栏设计一个网站的建设要经过哪几个阶段
  • Java-Linux环境下查看JDK安装路径
  • 嘉立创学习
  • QML学习笔记(三十四)QML的GroupBox、RadioButton
  • AI Agent 的技术架构、产业赋能与治理挑战研究 —— 基于 2024-2025 年技术突破与应用实践的分析
  • 设计美观网站有哪些辽宁网站建设价位
  • vtkFillHolesFilter——3D网格补孔的“一键修复”工具,从原理到避坑
  • 网站建设完整代码深圳开公司流程及费用
  • Vue3为什么选择用Vite?使用指南与优势解析
  • 【STL】set容器(2336.无限集中的最小数字)
  • 第一章 计算机系统概论1
  • Cannot invoke “String.length()“ because “<parameter1>“ is null
  • H5使用环信实现视频或语音通话
  • SMTPman高效稳定的smtp服务器使用指南解析
  • 《Qt应用开发》笔记p3
  • Java-148 深入浅出 MongoDB 聚合操作:$match、$group、$project、$sort 全面解析 Pipeline 实例详解与性能优化
  • Oops 概念
  • 用老域名做新网站 权重怎么传递哈尔滨网站建设公司哪家好
  • Servlet内存马
  • 为什么要使用反射举例
  • python开发生态及学习路线和应用领域都有哪些
  • bk7258 交叉编译libzip-1.11.4
  • 汽车级mosfet的应用场景
  • 手机做ppt的免费模板下载网站深圳自适应网站的公司
  • svn 库 co 下来有白叉
  • Windows安全狗安装教程