多线程3(Thread)

news2025/6/9 13:54:24

wait / notify

线程调度是随机的,但是我们可以使用wait/notify进行规划。

join是控制线程结束顺序,而wait/notify是控制详细的代码块,例如:

线程1执行完一段代码,让线程2继续执行,此时线程2就通过wait进行阻塞,等到线程1执行结束后,再通过notify唤醒线程2。

线程饿死:线程1释放锁资源后,其他线程和线程1要进行竞争锁,但是由于其他线程还要进行唤醒操作,可能会出现线程1一直拿到锁资源,导致其他线程拿不到锁的情况。

wait/notify可以解决线程饿死问题

wait / notify 的使用

wait / notify 是Object类中的方法,而Object又是所有类的“祖宗类”,所以我们可以随便创建一个类进行调用wait / notify。

此时调用wait的线程执行到wait时就会触发阻塞,当别的线程调用notify时,wait线程才会解除阻塞。

wait / notify都要再synchronized中使用(wait方法会释放锁对象,因此要先拿到锁),而且两个锁的锁对象要相同,同时调用wait / notify的对象也要是锁对象,这四个地方要同时满足。

wait()方法

1.wait()方法主要进行的是三件事:

1)释放锁对象

2)使当前代码的线程进行等待(将线程添加到等待队列)。

3)满足某个条件时,将重新尝试获取到这个锁,这样重新获取锁才可以继续synchronized保护的代码。

当wait进行阻塞时,会有两个阶段:  

1)WAITING阻塞,wait进行阻塞。

2)BOLOCK阻塞,这个阻塞是执行完notify后,wait会重新尝试获取锁,但是可能会遇到锁竞争导致阻塞。

2.默认情况下,wait()方法进行的是死等,没有notify就会一直阻塞,但是wait()提供了有参数版本。

3.如果是多个wait一个notify,此时唤醒的就是就是随机的wait,可以使用natifyAll,但是这个随机并不是数学上的随机,而是取决于调度器。

sleep和wait两者的区别

1.wait的设计就是为了唤醒操作,而带参版本是后手;sleep的设计是为了到时间唤醒,虽然可以通过interrupt()提前唤醒,但是会抛出异常。

2.wait会释放锁,所以wait要搭配synchronized使用;sleep可以在锁中使用,也不会释放锁,也可以在锁外使用。

设计模式

设计模式是解决一些固定场景的特定套路。

1.单例模式

单个实例(对象),指在设计类时只单独创建一个实例,将构造方法设为private,这样在new时就会报错。

1)饿汉模式

只进行读操作,线程安全

2)懒汉模式

线程不安全

解决方法:加锁

这里的线程安全问题其实是第一次创建时才有线程安全问题,所以我们要进行判断,当不为空时就不去加锁,因为加锁也要开销,第一层if两个线程都进入,但是加上锁后,一个线程阻塞一个执行,当第二个线程开始后,就会判断不成立,此时就直接返回。

在单线程中判断时往往是不变的,但是多线程就可能会有在判断时有别的线程影响。

2.指令重排序触发的线程安全问题

指令重排序是一种优化机制。

上面懒汉模式new一个对象涉及到很多指令,可以抽象三步:

1.申请内存

2,在内存中进行初始化

3.将内存地址,存到变量应用中

编译器可能会优化成1 3 2.

如果在线程1中进行的是1 3 2 的顺序,此时当进行到3时,线程2判断引用不为空,此时就会返回值,但是此时线程1并没有进行初始化操作,所以由线程2返回的值就是错误的。

因此要将这个变量加上volatile来告诉编译器不要进行这样的优化。

阻塞队列

阻塞队列是一种特殊的队列,也是先进先出。

阻塞队列的规则是:

队列为空,尝试出队列,触发阻塞,直到队列不为空。

队列满了,尝试进队列,触发阻塞,直到队列不满。

阻塞队列可以运用在生产者消费者模型中,生产者消费者之间的速度不同,所以引入阻塞队列进行协调作用。

阻塞队列的优点一:减少资源竞争,提高效率。

优点二:可以更好做到代码块之间解耦合。

优点三:可以降低服务器之间的压力,当前面的服务器压力大时,阻塞队列(消息队列)后面的服务器将不会收到太大压力。

阻塞队列的实现

JAVA标准库中就有现成的阻塞队列的实现BlockingQueue。

一种是基于链表实现的,一种基于数组实现,唯一不同的是数组实现的一定要指定最大长度。

模拟实现阻塞队列

class BlockQueue{
    public String [] arr = null;
    public int head = 0;
    public int tail = 0;
    public int size = 0;
    public Object object = new Object();

    public BlockQueue(int m) {
        arr = new String[m];
    }

    public void put(String newele) throws InterruptedException {
        synchronized (object) {
            while(size >= arr.length) {
                object.wait();
            }
            arr[tail] = newele;
            tail++;
            size++;
            object.notify();
            if (tail >= arr.length) {
                tail = 0;
            }
        }
    }
    public String take() throws InterruptedException {
        synchronized (object) {
            while(size == 0) {
                object.wait();
            }
            String n = arr[head];
            head++;
            size--;
            object.notify();
            if (head >= arr.length) {
                head = 0;
            }
            return n;
        }
    }
}
public class dome12 {
    public static void main(String[] args) {
        BlockQueue n = new BlockQueue(100);
        Thread thread = new Thread(()->{
            int count = 0;
            for (int i = 0; i < 100; i++) {
                try {
                    n.put(" "+count);
                    System.out.println("进入"+count);
                    count++;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread thread1 = new Thread(()->{
            for (int i = 0; i < 100; i++) {
                try {
                    String k = n.take();
                    System.out.println("取出"+k);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        });
        thread1.start();;
        thread.start();
    }

}

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

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

相关文章

附加模块--Qt Shader Tools功能及架构解析

Qt 6.0 引入了全新的 Shader Tools 模块&#xff0c;为着色器管理提供了现代化、跨平台的解决方案。 一、主要功能 核心功能 跨平台着色器编译 支持 GLSL、HLSL 和 MetalSL 着色器语言 可在运行时或构建时进行着色器编译 自动处理不同图形API的着色器变体 SPIR-V 支持 能…

网络编程(计算机网络基础)

思维导图 认识网络 1.网络发展史 ARPnetA(阿帕网)->internet(因特网)->移动互联网->物联网 2.局域网与广域网 局域网 概念&#xff1a;的缩写是LAN&#xff08;local area network&#xff09;&#xff0c;顾名思义&#xff0c;是个本地的网络&#xff0c;只能实现…

在React 中安装和配置 shadcn/ui

1. 创建 React 项目 pnpm create vitelatest .选择模板&#xff1a;React TypeScript安装依赖&#xff1a;pnpm install2. 添加 Tailwind CSS pnpm add -D tailwindcss postcss autoprefixer修改 src/index.css 内容&#xff1a; import "tailwindcss";3. 配置 T…

WINUI——WINUI开发中谨慎使用x:Bind

原因——为什么需要谨慎使用x:Bind&#xff1f; 在实际开发中发现&#xff0c;使用它会导致VM回收不及时&#xff0c;可能导致内存泄漏。 那为何要在项目中使用它呢&#xff1f; 因为&#xff1a;{x&#xff1a;Bind} 标记扩展&#xff08;Windows 10 的新增功能&#xff09;…

MSYS2 环境配置与 Python 项目依赖管理笔记

#工作记录 MSYS2 环境配置 安装和更新 MSYS2 初始安装 下载并安装 MSYS2&#xff1a; 访问 MSYS2 官方网站 并下载安装包。 按照安装向导完成安装。 更新 MSYS2&#xff1a; 打开 MSYS2 终端&#xff08;MSYS2 MINGW64&#xff09;。 更新包数据库和核心系统包&#xff1…

华为云Flexus+DeepSeek征文|华为云一键部署知识库搜索增强版Dify平台,构建智能聊天助手实战指南

目录 前言 1 架构描述 2 资源栈创建流程详解 2.1 选择部署模板 2.2 参数配置内容 2.3 资源栈设置选项 2.4 配置确认与执行方式 3 部署过程与控制台反馈 3.1 实时资源监控 3.2 资源详情与访问路径 3.3 模板与事件管理 4 知识库构建流程 4.1 数据导入操作 4.2 文本…

分形几何在医学可视化中的应用:从理论到Python实战

分形几何在医学可视化中的应用&#xff1a;从理论到Python实战 前言 分形几何作为描述自然界复杂结构的数学工具&#xff0c;正通过其自相似性和分数维度特性&#xff0c;革新医学影像分析领域。本文系统阐述分形几何在医学影像中的创新应用&#xff0c;涵盖从图像预处理、分…

ESP-Brookesia:融合 AI 大模型,全新一代 GUI 开发与管理平台

乐鑫信息科技 (688018.SH) 推出 ESP-Brookesia ——一款专为物联网设备打造、集成 AI 交互能力的 UI 开发与管理框架。 ESP-Brookesia 深度融合 AI 大模型技术&#xff0c;为智能屏显应用赋予语音识别、自然语言对话、拟人化反馈等能力&#xff0c;帮助开发者构建更智能、更具…

【MATLAB去噪算法】基于CEEMD联合小波阈值去噪算法(第三期)

02.去噪算法原理 1.引言 传统EMD方法存在模态混叠问题&#xff0c;即信号成分在不同IMF分量中出现碎片化分布。为改进这一问题&#xff0c;Huang等&#xff08;1999&#xff09;提出间歇性测试算法&#xff0c;但效果有限。Wu和Huang&#xff08;2009&#xff09;发展的集合经…

机器学习实战37-基于情感字典和机器学习的股市舆情分析可视化系统

文章目录 一、项目背景数字时代情感分析情况二、项目流程1.数据采集与预处理2.复合情感分析模型构建3.舆情分析可视化:三、机器学习算法原理1.支持向量机基础2.核函数与高维映射3.情感分类特征融合4.模型训练与优化四、实现代码五、系统特点与优势1.复合情感分析模型2.多维度可…

CAD多面体密堆积3D插件

插件介绍 CAD多面体密堆积3D插件可在AutoCAD内建立三维随机多面体密堆积模型。 插件内置物理动力学模拟算法&#xff0c;通过模拟重力、碰撞等现象&#xff0c;使多面体在虚拟环境中发生自然堆积&#xff0c;进而实现真实的堆积效果。多面体堆积模拟中存在的局部穿模问题可通…

LLMs 系列科普文(5)

在前文中&#xff0c;我们讲述了什么是基础模型&#xff0c;并重点以 LLaMA 3.1 基础模型为例&#xff0c;向大家演示了它可以做什么&#xff0c;有哪些问题或有趣的现象。 在进入新的主题内容之前&#xff0c;我们再次对 基础模型 做一些总结&#xff1a; 这是一个基于 toke…

HarmonyOS开发:显示图片功能详解

目录 前言 Image组件基础 1、Image组件概述 2、加载图片资源 3、存档图类型数据源 &#xff08;1&#xff09;本地资源 &#xff08;2&#xff09;网络资源 &#xff08;3&#xff09;Resource资源 &#xff08;4&#xff09;媒体库file://data/storage &#xff08;…

ORACLE 修改端口号之后无法启动?

Oracle数据库更改端口后出现监听器无法启动的问题确实较为常见&#xff0c;但并非必然发生。这一问题通常源于​​配置错误或环境冲突​​&#xff0c;而非端口修改本身。以下是系统性解决方案&#xff1a; &#x1f50d; ​​一、问题根源分析​​ ​​配置文件语法错误​​ 修…

Excel自动分列开票工具推荐

软件介绍 本文介绍一款基于Excel VBA开发的自动分列开票工具&#xff0c;可高效处理客户对账单并生成符合要求的发票清单。 软件功能概述 该工具能够将客户对账单按照订单号自动拆分为独立文件&#xff0c;并生成可直接导入发票清单系统的标准化格式。 软件特点 这是一款体…

Maven入门(够用)

1、Maven是什么&#xff1f; 这个问题非常不重要&#xff0c;或者说不应该上来就问maven是什么&#xff0c;而是直接学习maven怎么用能干什么&#xff0c;学完之后自然就知道了maven是个什么玩意儿&#xff0c;很多技术都是如此。 2、Maven下载 先准备Java环境&#xff0c;安…

自动化办公集成工具:一站式解决文档处理难题

1. 项目概述 在当今信息化时代,办公自动化已成为提升工作效率的关键。本文将详细介绍一款基于Python和PyQt5开发的「自动化办公集成工具」,该工具集成了多种常用的办公文档处理功能,包括批量格式转换、文本智能替换、表格数据清洗等,旨在为用户提供一站式的办公自动化解决方…

three.js 零基础到入门

three.js 零基础到入门 什么是 three.js为什么使用 three.js使用 Three.js1. 创建场景示例 2.创建相机3. 创建立方体并添加网格地面示例 5. 创建渲染器示例 6. 添加效果(移动/雾/相机跟随物体/背景)自动旋转示例效果 相机自动旋转示例 展示效果 实现由远到近的雾示例展示效果 T…

PublishSubject、ReplaySubject、BehaviorSubject、AsyncSubject的区别

python容易编辑&#xff0c;因此用pyrx代替rxjava3做演示会比较快捷。 pyrx安装命令&#xff1a; pip install rx 一、Subject&#xff08;相当于 RxJava 的 PublishSubject&#xff09; PublishSubject PublishSubject 将对观察者发送订阅后产生的元素&#xff0c;而在订阅前…

在Ubuntu22.04 系统中安装Docker详细教程

1.更新系统软件包 #确保您的系统软件包是最新的。这有助于避免安装过程中可能遇到的问题 sudo apt update sudo apt upgrade -y2.安装必要的依赖 sudo apt install apt-transport-https ca-certificates curl software-properties-common -y3.替换软件源 echo "deb htt…