多线程讲解(三)

线程池排队机制 线程池的排队机制是并发编程中的一个重要部分,它决定了当线程池中的线程都在忙碌时,新提交的任务应该如何处理。在Java中,线程池通常通过包下的类实现,其排队机制主要依赖于任务队列(workQueue)的配置。 阅读详情

目录标题

一 线程同步(多个线程操作一个资源) 重点难点

在这里插入图片描述

现实生活中 排队的名字 在代码中叫做队列

在这里插入图片描述

处理多线程问题时 多个线程访问同一个对象这种情况叫做并发
这个时候我们就需要线程同步 线程同步其实就是一种等待机制(排队)

在这里插入图片描述

队列的话 类似于 食堂大妈给同学打饭必须要排队才能安全快速的进行
锁机制的话 就类似于 大家一起上厕所 一个人进去厕所后 会锁上门 否则的话 后面的人就会进去造成不应该的矛盾和麻烦
所以为了提高安全性 形成的条件就是 队列加锁

二 什么是线程同步

在这里插入图片描述

synchronized 线程同步



为了保证线程的安全性 当一个线程获得对象的排它锁,独占资源 其他线程必须等待 使用完后才能释放锁即可
但是这么保证线程固然安全 但也缺少了性能问题
出现了以下的问题:
1 一个线程 持有锁会导致其他所有需要此锁的线程来消耗时间挂起
所以锁的存在影响到了效率 降低了性能
2 在多线程的竞争下 加锁 释放锁 会导致比较多的上下文切换和调度延时 引起性能问题
3 如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置 引起性能问题(例如一个大号的同学先进入厕所 一个小号的同学在外面等了半个小时 造成性能倒置 应该是小号先进入大号在进入)
所以 安全性提高了 但是性能会降低
性能提高了 安全性会降低!!!重点




练习一

不安全买票
不安全的买票案例
//可以看出线程不安全 有人拿到了负数的票数 比如黄牛党拿到了第-1票




为什么会拿到负的票数
线程不会排队 当剩下最后一张票时 它们同时去抢 出现了负数的结果



//定义售卖票数停止方式
boolean flag=true;



@Override
public void run() {
//买票
while (flag){
try {
buy();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}




//判断是否有票
if (ticketNums<=0){
flag=false;
return;
}



在这里插入图片描述

练习二

两个人不安全的银行取钱案例



//创建一个去取钱的对象
//传入的参数意思为:你在结婚基金中取出50元
//传入的参数意思为:妻子在结婚基金中取出100元
Drawing you = new Drawing(account, 50, “你”);
Drawing her = new Drawing(account, 100, “妻子”);




//银行:模拟取款
//因为银行不涉及多个线程操控一个对象用继承extends即可
//即多个银行让一个人同时取钱不可能实现
//因为此刻的银行不涉及多个线程操控同一个对象(深度理解)
//理解:因为这是一个对象去银行取钱 不涉及多个对象帮助这一个对象去银行取钱
//所以用继承extend更为方便一点 不需要多个线程帮助这一个对象对银行取钱
//参考对比继承Thread类和实现Runnable接口:
//继承Thread类时只有一份资源
//实现Runnable接口时一份资源但多个代理
class Drawing extends Thread{}




//构造器
//在构造器中传入的参数 为 账户 和取多少钱和 哪个对象去取钱
public Drawing(Account account,int drawingMoney,String name){
//复习知识点super
//子类super调用父类的构造方法 必须在构造方法的第一行
//在这里调用的时
super(name);
//重点: 为什么用super(name);调用父类的参数而不用this.name=name;
//this.name=name;//这里可以看到this.name=name;这行代码报错
//为什么呢: 原因 因为Drawing继承了 Thread父类 而父类中的有参构造肯定含有this.name=name;
//name这个参数 所以此刻如果再创建那么就会重复 所以就会出现报错的现象
//解决方法 : 调用super();方法 调用父类的name参数来用
this.account=account;
this.drawingMoney=drawingMoney;
}




//模拟网络延时 sleep 可以放大问题的发生性
//此刻网络延时的目的是:让两个取钱的对象再此刻同时进入银行取钱
//造成出现负数余额的现象
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}




在这里插入图片描述

练习三

线程不安全的集合



//复习 : Array 数组的工具包 java.util.Arrays
//由于数组对象本身没有什么方法可以供我们调用 但API中提供了一个工具类Arrays供我们
//使用 从而可以对数据对象进行一些基本的操作
List list=new ArrayList();
//可以看到通过for循环来创建线程Thread 一共有一万个
for (int i = 0; i < 10000; i++) {
//创建线程
new Thread(()->{
//下行代码 将线程的名字添加到了集合中
//Thread.currentThread().getName() 表示当前代码被哪个线程调用
//比如 Thread-0,Thread-1…
list.add(Thread.currentThread().getName());
}).start();
}




在这里插入图片描述

三 Thread.currentThread().getName() 和 this.getName()的区别

Thread.curentThread().getName() 表示当前的代码被被哪个线程所调用
this.getName() 表示当前线程(当前这个这段代码属于哪个线程里面的)




//isAlive() 方法 测试线程是否处于活动状态



在这里插入图片描述

四 同步方法及同步块

在这里插入图片描述

synchronized同步方法的原理是 控制对“对象”的访问 每一个对象都有一把锁 每一个synchronized方法都必须获得调用该方法的对象的锁才能执行 否则线程就会阻塞


在这里插入图片描述

在这里插入图片描述

练习一改善

在这里插入图片描述

练习二改善

在这里插入图片描述

练习三改善

在这里插入图片描述

五 JUC安全类型的集合

测试JUC安全类型的集合

在这里插入图片描述

六 死锁

在这里插入图片描述

练习一

练习内容
两个女生化妆 都拿着各自对象想要的化妆工具
而都不想进行交换



死锁 :多个线程互相抱着对方需要的资源 然后形成僵持



在这里插入图片描述

练习二改善

这里可以看到一条进程里面想要获得两条资源
显然是不行的


synchronized (lipstick){
//获得口红的锁
System.out.println(this.girlName+“获得口红的锁”);
Thread.sleep(1000);
}
//应该这样理解:代码块外一秒后会释放资源所以这样就解决了
//出现死锁的现象里可以看出 当小明用着口红的时候 口红用完 手里面还拿着口红的的锁 导致其他人不能用
//当小红拿着镜子的时候手里面还拿着 镜子用完 手里还是拿着镜子的锁 导致其他人不能用
//所以对方都拿着对方想要的锁 而不能用 出现了死锁现象
//只要不同时抱着两个锁
//理解为 就是用完口红把锁放下,用完镜子把锁放下,之前是用完了没放下
//将锁拿出来 可以避免出现死锁的现象
//一秒钟后想获得镜子
synchronized (mirror){
System.out.println(this.girlName+“获得镜子的锁”);
}



在这里插入图片描述

七 Lock(锁)

从JDK5.0开始的 提供了更强大的线程同步机制
ReentrantLock 可重入锁

在这里插入图片描述

八 死锁的避免方法

在这里插入图片描述

在这里插入图片描述

练习一

买票的案例
//定义lock锁
private final ReentrantLock lock=new ReentrantLock();

在这里插入图片描述

九 synchronized与Lock的对比

在这里插入图片描述

十 线程协作(生产者消费者模式)

线程通信

在这里插入图片描述

在这里插入图片描述
重点
线程通信的生产者消费者问题中 仅仅有synchronized是远远不够的
因为 synchronized可阻止并发更新同一个共享资源 实现同步
但是synchronized不能用来实现不同线程之间的消息传递(通信)




在这里插入图片描述

重点
这里可以看到 要想解决生产者消费者问题 可以使用wait 方法 notify方法 跟sleep方法不同 sleep方法是抱着锁进入睡眠状态
而wait方法可以释放资源

在这里插入图片描述

在这里插入图片描述

练习一(重点)

解决生产者与消费者的模式
方法一管程法



notify();方法 唤醒一个处于等待状态的线程
wait();方法 如果线程一直等待 直到其他线程通知 与sleep不同会释放锁



在这里插入图片描述

在这里插入图片描述

练习二

解决消费者生产者模式的问题方法二:
信号灯法 标志位解决

在这里插入图片描述

十一 线程池

在这里插入图片描述

在这里插入图片描述

线程池创建
通过ExecutorService线程池接口 来创建一个自定义大小的线程池



如果创建线程是实现的Runnable接口 ze 用execute调用 执行线程
但是execute没有返回值
但是如果创建线程是实现的Callable接口 则用 submit来调用执行线程 而submit有返回值



上面两种方法创建完线程池后最后都分别用shutdown()方法关闭连接池



在这里插入图片描述

总结线程的创建

回顾多线程创建的方法

在这里插入图片描述

C++多线程编程实战:三窗口卖票程序深度解析与并发陷阱 并发编程是现代软件开发的核心技术之一,它允许多个任务同时执行,从而提升程序性能与响应能力。其核心原理在于通过线程管理、同步机制协调多个执行流对共享资源的访问,避免数据竞争与状态不一致。这项技术的价值在于充分利用多核CPU的计算能力,解决高并发场景下的性能瓶颈。在实际应用中,从电商秒杀库存管理到多线程日志系统,再到连接池与任务队列,都需要处理类似“多窗口卖票”的共享资源并发访问问题。本文以经典的C++多线程卖票案例为切入点,深入探讨了**互斥锁(mutex)** 与**条件变量(condition_varia 阅读详情

相关推荐

并发控制的艺术:深度剖析ConcurrentDictionary与ConcurrentQueue,打造高并发应用的必备秘籍

通过上述实战案例,我们见识了和在处理并发数据访问时的高效与便捷。它们利用高级的并发控制机制,如分段锁和乐观并发策略,有效平衡了线程安全与性能之间的矛盾,是构建高性能多线程应用不可或缺的利器。掌握这些并发容器的使用,将为你的多线程编程之旅保驾护航。

java专栏 587

C#多线程开发-使用并发集合

前言大家好,我是阿辉。在C#语言中当需要处理并发的场景时,就需要程序员使用最合理的数据结构。那么哪些数据结构是支持和可以在并行计算中被使用的呢。首先这些数据结构具备可伸缩性,尽可能地避免锁...

dotNET跨平台 787

JAVA多线程 | 实现用户任务排队 | 预估排队时长

实现流程 初始化一定数量的任务处理线程和缓存线程池,用户每次调用接口,开启一个线程处理。 假设初始化5个处理器,代码执行BlockingQueue.take 时候,每次take都会处理器队列就会减少一个,当处理器队列为空时,take就是阻塞线程,当用户处理某某任务完成时候,调用资源释放接口,在处理器队列put 一个处理器对象,原来阻塞的take ,就继续执行。 排队论简介 排队论是研究系统随机聚散现象和随机系统工作工程的数学理论和方法,又称随机服务系统理论,...

洛阳泰山的博客 2054

多线程排队执行

10个线程A一起执行完,再一起执行20个线程B;然后再一起执行10个线程A,再一起执行20个线程B,如此往复50次。 public class CyclickBarrierTest { public static void main(String[] args) { int childSize = 10; int mainSize = 20; int ci...

wender的专栏 2574

Unity游戏开发客户端Unity基础

Unity游戏开发客户端面经 之 Unity 篇

Sea3752的博客 2万+

5G NR 帧结构

本节主要介绍5G NR中的帧结构[38.211-4.3]。5G帧结构(Frame Structure)为时域结构。其设计比其4G LTE更为灵活,这种灵活性使5G能够根据应用需求(如增强移动宽带eMBB,超高可靠低时延通信URLLC)进行调整,同时支持差异化的应用场景,提高了5G的利用效率与响应能力。具体而言,5G帧结构是基于时隙和OFDM符号设计的,且5G网络能够根据服务需求动态调整各时隙持续时长。

夫子喵的博客 5287

多线程讲解系列三

今天我们就来讲讲run()方法与start()方法的区别: 通常情况下,系统通过调用线程类的start()方法来启动一线程,此时该线程处于就绪状态,而非运行状态,也就意味着这个线程可以被jvm来调度执行,在调度过程中,jvm通过调用线程类的run()方法来完成实际的操作,当run()方法结束后,此线程就会终止。 如果直接调用线程类的run()方法,这会被当做一个普通的函数调用,程序中任然只有主...

sdgames的博客 138

Win10系统VS2019+Cmake+qhull_8.0.0环境配置

1 qhull 1.1 简要介绍 qhull是一个强大的计算几何库,可以用于计算高维的convex hull, Delaunay triangulation, Voronoi diagram等。 1.2 依赖库 qhull不依赖其他库。 1.3 源码包下载 qhull源码地址:github:https://github.com/qhull/qhull.git 2 Cmake构建项目 2.1 路径 源代码路径:D:/ThirdParty/qhull/qhull_8.0.0构建项目路径:D:/Thi.

wangchenxue的博客 2495

c/c++: 多线程编程基础讲解(三)

线程会创建了,如何在线程调用函数时,传入参数呢?则应如下所示: #include #include using namespace std; #define NUM_THREADS 5 void* say_hello(void* args) { int i = *((int*)args);//对传入的参数进行强制类型转换,由无类型指针变为整形数指针,然后再读取

懒猫会打盹的专栏 7149

基于VS2012 C#调用bartender自动打印条形码

GitHub:https://github.com/sanjaywu/BarcodePrintTool 一、在引用添加Interop.BarTender.dll 1、在资源解决方案的引用这里,右击选择“添加引用”: 2、按照如下步骤添加Interop.BarTender.dll引用: 3、添加完成 二、使用bartender工具设置打印模板 1、页面大小设置: 2、条码设置: 三、代码...

Sanjay_Wu的博客 5956

AI 模型训练核心方法论:零基础也能落地的 8 个关键阶段

本文是为 AI 零基础学习者打造的模型训练入门指南,以生活化语言拆解核心概念,规避专业术语壁垒。内容先通俗阐释模型训练、监督学习、数据集划分等基础概念,再按问题定义、数据准备、模型选择、环境搭建、训练、评估、调参、部署 8 个阶段,拆解完整训练流程,搭配 PyTorch 代码示例与实战案例,同时提供资源预算、常见问题解决方案及学习路径。指南强调数据的核心重要性,推荐新手优先使用迁移学习和免费 GPU 资源,兼顾理论与实操,帮助学习者快速上手,避开训练误区,独立完成从模型搭建到部署的全流程。

weixin_52741870的博客 469

Linux多线程编程讲解之系列三

互斥锁 尽管在Posix Thread中同样可以使用IPC的信号量机制来实现互斥锁mutex功能,但显然semphore的功能过于强大了,在Posix Thread中定义了另外一套专门用于线程同步的mutex函数。 1. 创建和销毁 有两种方法创建互斥锁,静态方式和动态方式。POSIX定义了一个宏PTHREAD_MUTEX_INITIALIZER来静态初始化互斥锁,方法如下: p

职场里拉开差距的不是知识,而是认知! 668

Android Framework WMS面试题及参考答案

什么是 WindowManagerService(WMS)?它的作用是什么? WindowManagerService(WMS)是 Android 系统中非常重要的一个系统服务。它运行在系统进程(system_server 进程)中。 从本质上来说,WMS 是 Android 窗口管理系统的核心。它负责管理系统中的所有窗口,包括应用程序窗口、系统窗口(如状态栏、导航栏)等。 它的主要作用有很多。首先是窗口的创建和销毁。当一个应用请求创建一个窗口时,WMS 会协调各个模块完成窗口的创建工

大模型大数据攻城狮的专栏 2165

java多线程与线程池技术讲解(三)

线程之间的通信

x_123zai的博客 134

2023华为od机试C卷【启动多任务排序】C++ 实现

一个应用启动时,会有多个初始化任务需要执行,并且任务之间有依赖关系,例如A任务依赖B任务,那么必须在B任务执行完成之后,才能开始执行A任务。现在给出多条任务依赖关系的规则,请输入任务的顺序执行序列,规则采用贪婪策略,即一个任务如果没有依赖的任务,则立刻开始执行,如果同时有多个任务要执行,则根据任务名称字母顺序排序。

MISAYAONE的博客 888

MATLAB与图像处理(一):图像中结构张量的求法(Structure Tensor)

1.结构张量的作用:       能够区分图像中的平坦区域,边缘,角点; 2.图像中的结构张量的定义    1)是一个矩阵;    2)与图像的水平,垂直梯度有关,定义如下: 在MATLAB中,可以用如下语句求解:[Ix,Iy]=gradient(Image); 3)求出结构张量矩阵的行列式,和迹(矩阵对角线之和)   行列式:K=det(E);   迹:  

wenyusuran的专栏 5242

三.多线程JUC篇-3.14 Executor&ExecutorService讲解

1.概述 在Java 5之后,并发编程引入了一堆新的启动、调度和管理线程的API。Executor框架便是Java 5中引入的,其内部使用了线程池机制,它在java.util.cocurrent 包下,通过该框架来控制线程的启动、执行和关闭,可以简化并发编程的操作 Eexecutor作为灵活且强大的异步执行框架,其支持多种不同类型的任务执行策略,提供了一种标准的方法将任务的提交过程和执行过程解耦开发,基于生产者-消费者模式,其提交任务的线程相当于生产者,执行任务的线程相当于消费者,并用Runnabl

中国华的博客 178

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

三.多线程JUC篇-3.18 Future 详细讲解

1.get和interrupt private static void testGet() throws InterruptedException, ExecutionException { ExecutorService executorService = Executors.newCachedThreadPool(); Future<Integer> future = executorService.submit(() -> {

中国华的博客 405

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

多线程基础讲解三: 等待线程 (用面试题理解join等待线程)

面试题: 创建3个线程,t1、t2、t3,让让t1在t2之前执行,t2在t3之前执行。 核心:让其他线程变为等待状态,必须让join方法在其他线程内部调用。 /** * @author: wangqinmin * @date : 2020/7/3 * @description: 仰天大笑出门去,我辈岂是蓬蒿人 */ public class TestJoin { /** * 用一道面试题讲解join * <p> * 创建3个线程...

chuxin_mm的博客 215

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

PYQT5实现多线程的方法

pyqt5处理多线程主要有三种方法: a.使用计时器模块QTimer b.使用多线程模块QThread c.使用事件处理功能 QTimer相当于一个定时器,每当定时器时间溢出后,会执行相关的函数。这个时候程序会从主线程界面跳到QTimer函数中,如果QTimer函数中有延时或者处理时间较长,就会出现界面失去响应,造成界面卡顿的现象。 QThread等于新开一个线程专门处理耗时间的程序,UI主线程显示界面,当子线程处理好数据后通过自定义的信号与槽,将数据交给主线程刷新界面。由于UI主线程一直运行,子线程的延时

GDUT_ZXM的博客 9114

【iOS】多线程基础

多线程的使用是十分重要的知识点,在后面具体项目中与其他第三方库结合的使用也很多,还需要继续学习并加以实践)

2401_86200358的博客 1006

Java多线程学习之三

线程安全 1、关于多线程并发环境下,数据可能会存在安全问题。 2、什么数据在多线程并发的环境下会发生安全问题? 三个条件: 条件一:多线程并发 条件二:有共享数据 条件三:共享数据有修改行为 满足以上三个条件后,就会存在线程安全问题。 3、怎样解决线程安全问题? 线程同步机制 (1)线程排队执行(不能并发),用排队执行解决线程安全问题, 这种机制被称为线程同步机制 (2)线程同步就是线程排队,线程排队了就会牺牲一部分效率,没办法,数据安全第一位,只有数据安全了,我们才可以谈效率。数据不安全,就没有效率的

Mr_Dragon的博客 163

Java多线程锁

同步以及死锁 文章目录同步以及死锁图来同步方法图来死锁图来 一个多线程的程序如果是通过 Runnable 接口实现的,则意味着类中的属性被多个线程共享,那么这样就会造成一种问题,如果这多个线程要操作同一个资源时就有可能出现资源同步问题。 解决方法: synchronized(同步对象){ 需要同步的代码 } class MyThread implements Runnable{ private int ticket = 5 ; // 假设一共有5张票 public voi

nsnydnz的博客 149

java中多线程编程_JAVA多线程编程实例

1.三个售票窗口同时出售20张票程序分析: (1)票数要使用同一个静态值 (2)为保证不会出现卖出同一个票数,要 java 多线程同步锁。 设计思路: (1)创建一个站台类Station,继承 Thread,重写 run方法,在 run 方法里面执行售票操作!售票要使用同步锁:即有一个站台卖这张票时,其他站台要等这张票卖完! (2)创建主方法调用类(一)创建一个站台类,继承 Threadpacka...

weixin_35208293的博客 198
上一篇: 多线程讲解(二)
下一篇: 常用类和内部类总结
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值