多线程基础说明【基础篇】

目录

🌭1.相关概念 

🍿2.创建和启动线程 

🥞3.线程安全

🧈4.死锁

🥓5.线程通信的方法


1.相关概念

1.1程序

为完成特定任务,用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象。

1.2进程

  • 程序的一次执行过程,或是正在内存中运行的应用程序。
  • 每个进程都有一个独立的内存空间。
  • 程序是静态的,进程是动态的。
  • 进程是操作系统调度和分配资源的最小单位。

1.3线程

  • 进程可进一步细化为线程,是程序内部的一条执行路径。
  • 一个进程中至少有一个线程。
  • 一个进程同一时间若 并行 执行多个线程,就是支持多线程的。
  • 线程作为 CPU调度和执行的最小单位。

1.4并行

  • 指两个或多个事件在 同一时刻 发生(同时发生)。
  • 指在同一时刻,有多条指令 在多个CPU 上 同时 执行。

比如:多个人同时做不同的事。

1.5并发 

  • 指两个或多个事件在同一个时间段内发生。
  • 即在一段时间内,有多条指令在单个CPU上快速轮换、交替执行,使得在宏观上目有名个进程同时执行的效果

2.创建和启动线程 

Java语言的JvM允许程序运行多个线程,使用java.lang.Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例

2.1继承Thread类

  • 1.创建一个类,继承Thread
  • 2.重写Thread类的run()方法,将此线程要执行的操作,声明在此方法中
  • 3.创建当前Thread的子类的对象
  • 4.通过对象调用start(), start():1.启动线程,2.调用当前线程的run()方法
public class MyTest {public static void main(String[] args) {//3.创建当前Thread的子类的对象PrintNumber p1 = new PrintNumber();//4.调用start()方法p1.start();//main()所在线程执行的操作for (int i=0;i<=100;i++){if (i%2==0){System.out.println(Thread.currentThread().getName()+":"+i);}}}}//1.创建子类,继承Thread
class PrintNumber extends Thread {//2.重写run()方法@Overridepublic void run() {for (int i = 0; i <= 100; i++) {if (i % 2 == 0) {System.out.println(Thread.currentThread().getName()+":"+i);}}}
}
  • 不能使用p1.run()替换p1.start()的调用 
  • 不能让已经执行start()的线程,再次执行start(),否则报错,应重新创建对象再调用start()

 2.2实现Runnable接口

  • 1.创建一个类,实现Runnable接口
  • 2.实现接口中的run()方法,将此线程要执行的操作,写在run()方法中
  • 3.创建当前实现类的对象
  • 4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的实例
  • 5.Thread类的实例调用start() 
public class RunnableTest {public static void main(String[] args) {//3.创建实现类的对象Number n1 = new Number();//4.将对象传递到Thread的构造器中Thread thread = new Thread(n1);//5.调用start()方法thread.start();}
}//1.创建类,实现Runnable接口
class Number implements Runnable {//2.实现run()方法,并将要执行的操作,写在run()方法中@Overridepublic void run() {for (int i = 0; i <= 100; i++) {if (i % 2 == 0) {System.out.println(Thread.currentThread().getName() +"-偶数:"+i);}}}
}

也可以使用匿名实现RUnnable接口,

new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i <= 100; i++) {if (i % 2 == 0) {System.out.println(Thread.currentThread().getName() + "-偶数:" + i);}}}}).start();

使用Runnable的好处:

  • 1.实现的方式,避免类的单继承的局限性
  • 2.更适合处理共享数据的问题
  • 3.实现了代码和数据的分类

2.3常用方法

  • 1.start():1.启动线程 2.调用线程的run()方法
  • 2.run():将线程要执行的操作,写在run()方法中 
  • 3.currentThread():获取当前代码执行所对应的线程
  • 4.sleep():静态方法,睡眠指定毫秒数
  • 5.yield():静态方法,释放cpu的执行权
  • 6.jion():在线程A中通过线程B调用jion(),线程A进入阻塞状态直到线程B执行完成。
  • 7.isAlive():判断当前线程是否存活 
  •  2.4.线程的生命周期

3.线程安全

3.1问题

模拟三个窗口卖票,在第一个线程未结束的同时,其他线程参与进来,会出现重复票和错票

3.2解决

必须保证一个线程a在操作共享数据的过程中,其他线必须等待,直到线程a操作结束,其他线程才可以继续操作

3.3线程的同步机制

  • 方式一:同步代码块

synchronized (同步监视器){

      操作共享数据的代码

}

  1. 共享数据:多个线程需要操作的数据。
  2. 同步监视器:俗称 锁  。哪个线程获取了锁,哪个线程就能执行代码块。
  3. 同步监视器可以使用任何一个类的对象充当,当多个线程必须共用同一个同步监视器。
public class WindowTest {public static void main(String[] args) {SaleTicket saleTicket = new SaleTicket();Thread t1 = new Thread(saleTicket);Thread t2 = new Thread(saleTicket);Thread t3 = new Thread(saleTicket);t1.setName("窗口1");t2.setName("窗口2");t3.setName("窗口3");t1.start();t2.start();t3.start();}}class SaleTicket implements Runnable {int ticket = 100;Object object = new Object();@Overridepublic void run() {while (true) {try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}synchronized (object) {if (ticket > 0) {System.out.println(Thread.currentThread().getName() + "售票,票号:" + ticket);ticket--;} else {System.out.println(Thread.currentThread().getName()+"票数不足!");break;}}}}
}
  • 方式二:同步方法
public class WindowTest {public static void main(String[] args) {SaleTicket saleTicket = new SaleTicket();Thread t1 = new Thread(saleTicket);Thread t2 = new Thread(saleTicket);Thread t3 = new Thread(saleTicket);t1.setName("窗口1");t2.setName("窗口2");t3.setName("窗口3");t1.start();t2.start();t3.start();}}class SaleTicket implements Runnable {static int ticket = 100;static Object object = new Object();Boolean isFlag=true;@Overridepublic void run() {while (isFlag) {try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}show();}}public synchronized void show(){ //此时的同步监视器就是this,即代码中的saleTicket,唯一的if (ticket > 0) {System.out.println(Thread.currentThread().getName() + "售票,票号:" + ticket);ticket--;}else {System.out.println(Thread.currentThread().getName()+"票数不足");isFlag=false;}}
}

注:

非静态的同步方法,默认同步监视器是this

静态的同步方法,默认同步监视器是当前类本身

synchronized

好处:解决了线程安全问题

弊端:在操作共享数据时,多线程其实是串行执行的,性能较低 

4.死锁

不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁。

4.1原因

  • 互斥条件
  • 占用且等待
  • 不可抢夺(或不可抢占)
  • 循环等待

4.2解决

  • 针对条件1:互斥条件基本上无法被破坏。因为线程需要通过互斥解决安全问题。
  • 针对条件2:可以考虑一次性申请所有所需的资源,这样就不存在等待的问题。
  • 针对条件3:占用部分资源的线程在进一步申请其他资源时,如果申请不到,就主动释放掉已经占用的资源。
  • 针对条件4:可以将资源改为线性顺序。申请资源时,先申请序号较小的,这样避免循环等待问题。 

5.线程通信的方法

  • wait():线程一旦执行此方法,就进入等待状态。同时,会释放对同步监视器的调用
  • notify():一但执行此方法,就会唤醒wait()的线程中优先级最高的那个线程,如果被wait()唤醒的线程优先级相同,则随即唤醒一个
  • notifyAll():一但执行此方法,就唤醒所有被wait的线程
public class AdTest {public static void main(String[] args) {PrintNumbers printNumbers = new PrintNumbers();Thread thread1 = new Thread(printNumbers, "线程1");Thread thread2 = new Thread(printNumbers, "线程2");thread1.start();thread2.start();}}class PrintNumbers implements Runnable {private int number = 1;@Overridepublic void run() {while (true) {synchronized (this) {notify();if (number <= 100) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + ":" + number);number++;try {wait();//线程执行此方法,进入等待状态,同时释放同步监视器的调用} catch (InterruptedException e) {e.printStackTrace();}} else {break;}}}}
}

wait()  VS  sleep()

相同点:一旦执行,当前线程都会阻塞

不同点:声明的位置、使用场景、sleep不会释放同步监视器、阻塞的方式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/703643.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

都2024年了,软件测试面试都问什么?

1、最熟悉的 selenium 操作&#xff1f; 基本上 selenium 提供的一下几大类操作都能够灵活使用&#xff0c;比如说&#xff1a;八大元素定位方式、三大等待方式、用户点击、输入等常见操作、 还有窗口切换、iframe 切换操作&#xff0c;比如说 actionchains 文件上传、JS操作 等…

网站开发--详解Servlet

&#x1f495;"Echo"&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;网站开发–详解Servlet 一.基本介绍 tomcat是Java中开发服务器的重要的一个工具,任何开发的服务器都要部署在tomcat之上,可以说tomcat是所有服务器的底座,为了更好的操作http,to…

golang学习3,golang 项目中配置gin的web框架

1.go 初始化 mod文件 go mod init gin-ranking 2.gin的crm框架 go get -u github.com/gin-gonic/gin 3.go.mod爆红解决

前后端分离Vue+node.js在线学习考试系统gqw7o

与其它应用程序相比&#xff0c;在线学习平台的设计主要面向于学校&#xff0c;旨在为管理员和学生、教师、院系提供一个在线学习平台。学生、教师、院系可以通过系统及时查看公告信息等。 在线学习平台是在Windows操作系统下的应用平台。为防止出现兼容性及稳定性问题&#xf…

B站项目-基于Pytorch的ResNet垃圾图片分类

基于Pytorch的ResNet垃圾图片分类 数据集预处理 画图片的宽高分布散点图 import osimport matplotlib.pyplot as plt import PIL.Image as Imagedef plot_resolution(dataset_root_path):image_size_list []#存放图片尺寸for root, dirs, files in os.walk(dataset_root_pa…

装配制造业的MES系统种的物料齐套技术

装配是制造企业涉及产品生产加工最为普遍的一种模式&#xff0c;包括汽车、电子、电器、电气等行业。经研究表明&#xff0c;装配在整个产品制造总成本中所占比例超过了50%&#xff0c;所占用的总生产时间比例在40%-60%&#xff0c;直接影响着产品质量和成本。装配制造非常强调…

树-王道-复试

树 1.度&#xff1a; 树中孩子节点个数&#xff0c;所有结点的度最大值为 树的度 2.有序树&#xff1a; 逻辑上看&#xff0c;树中结点的各子树从左至右是有次序的&#xff0c;不能互换。 **3.**树的根节点没有前驱&#xff0c;其他节点只有一个前驱 **4.**所有节点可有零个或…

Leetcoder Day23| 回溯part03:组合+分割

语言&#xff1a;Java/Go 39. 组合总和 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的所有不同组合 &#xff0c;并以列表形式返回。你可以按任意顺序返回这些组合。 candidates 中的同一个…

环形光源让图像质量瞬间提升,一探究竟吧!

光源对机器视觉检测系统的性能起着重要作用,精确的光学结构设计可以提高捕获图像的质量,准确地分离目标和背景信息,不充足的光线会使捕捉到的图像无法满足需求&#xff0c;针对不同的检测对象,不同的形状光源应运而生。我们来看看最常用的LED光源之一—环形光源。 环形光源&…

vue3 使用pina

一、Vue 3 项目中集成Pina 状态管理库 要在 Vue 3 项目中使用 Pina&#xff08;Vue 3 状态管理库&#xff09;&#xff0c;您可以按照以下步骤操作&#xff1a; 1. 安装 Pina 库相应的插件&#xff1a; yarn add pinia # 或者使用 npm npm install pinia 2. 在您的 Vue 3 项…

电脑休眠之后唤不醒

现象&#xff1a;午休时间电脑休眠了&#xff0c;醒来之后发现在密码输入界面&#xff0c;但鼠标键盘没反应。按重启键或电源机重新开机&#xff0c;结果开不了机。 原因&#xff1a;1、内存条脏了&#xff0c;导致内存条读取失败 2、休眠的时候硬盘休眠了&#xff0c;导致按…

AngularJS安装版本问题

一、安装 Angular CLI 脚手架安装命令&#xff1a; npm install -g angular/cli 在安装前请确保自己安装NodeJS环境版本为V18及以上&#xff0c;否则会因node版本问题导致项目无法正常运行。 脚手架安装后&#xff0c;已提示了当前node版本必须为18.13.0或大于20.9.0版本&…

git之分支管理

一.理解分支 我们看下面这张图片&#xff1a; 在版本回退⾥&#xff0c;你已经知道&#xff0c;每次提交&#xff0c;Git都把它们串成⼀条时间线&#xff0c;这条时间线就可以理解为是⼀个分⽀。截⽌到⽬前&#xff0c;只有⼀条时间线&#xff0c;在Git⾥&#xff0c;这个分⽀…

2024年 前端JavaScript入门到精通 第四天 笔记

4.1 函数的基本使用以及封装练习 ★ 函数命名规范 4.2 函数的参数以及默认参数 函数的灵魂&#xff01;&#xff01;&#xff01; 4.3 函数封装数组求和案例 4.4 函数返回值return 4.5 函数返回值细节以及上午总结 4.6 函数返回值案例-求最大值和最 4.7 函数复习以及断点进入函…

如何在Linux搭建MinIO服务并实现无公网ip远程访问内网管理界面

文章目录 前言1. Docker 部署MinIO2. 本地访问MinIO3. Linux安装Cpolar4. 配置MinIO公网地址5. 远程访问MinIO管理界面6. 固定MinIO公网地址 前言 MinIO是一个开源的对象存储服务器&#xff0c;可以在各种环境中运行&#xff0c;例如本地、Docker容器、Kubernetes集群等。它兼…

挑战杯 基于机器视觉的12306验证码识别

文章目录 0 简介1 数据收集2 识别过程3 网络构建4 数据读取5 模型训练6 加入Dropout层7 数据增强8 迁移学习9 结果9 最后 0 简介 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于机器视觉的12306验证码识别 该项目较为新颖&#xff0c;适合作为竞赛课题方向…

Inno setup 打包jar包+前端dist+mysql+navicat等应用文件操作

目录 一、 使用exe4j将后端jar包打包成exe应用文件 1.创建一个新的工程 2.选择一个你想要存放的路径 3.进入配置界面 4.选择jar转换exe模式 5.自定义名字和选择输出路径 6.配置初始化 7.配置java环境 8.测试运行结果 二、Inno 打包应用文件exe 1.新建一个工程文件 2…

【hashmap】【将排序之后的字符串作为哈希表的键】【获取 HashMap 中所有值的集合】Leetcode 49 字母异位词分组

【hashmap】【将排序之后的字符串作为哈希表的键】【获取 HashMap 中所有值的集合】Leetcode 49 字母异位词分组 解法1 将排序之后的字符串作为哈希表的键解法2 在解法一的基础上加入了getOrDefault ---------------&#x1f388;&#x1f388;题目链接&#x1f388;&#x1f3…

从零开始手写mmo游戏从框架到爆炸(二十二)— 战斗系统三

导航&#xff1a;从零开始手写mmo游戏从框架到爆炸&#xff08;零&#xff09;—— 导航-CSDN博客 目录 地图设定 战斗引擎 服务端的BattleHandler 客户端的相关handler 战斗场景展示 执行效果 文接上一章。我们把战斗系统demo应用到实际的项目中来。在第十九章&#xf…

AI对话系统app开源

支持对接gpt&#xff0c;阿里云&#xff0c;腾讯云 具体看截图 后端环境&#xff1a;PHP7.4MySQL5.6 软件&#xff1a;uniapp 废话不多说直接上抗揍云链接&#xff1a; https://mny.lanzout.com/iKFRY1o1zusf 部署教程请看源码内的【使用教程】文档 欢迎各位转载该帖/源码