【JavaEE】wait 、notify和单例模式

【JavaEE】wait 、notify 和单例模式

  • 一、引言
  • 一、wait()方法
  • 二、notify()方法
  • 三、notifyAll()方法
  • 四、wait()和sleep()对比
  • 五、单例模式
      • 5.1 饿汉模式
      • 5.2 懒汉模式
      • 5.2 懒汉模式-线程安全(改进)

博客结尾有此篇博客的全部代码!!!

一、引言

假设这里有一个ATM机,然后有人排队取钱,有人排队存钱
在这里插入图片描述
ATM机时进去一个人,门自动关门上锁。
现实生活中,假设第一个人进去取钱,但是恰好此时ATM机里面没有钱,第一个人就出来,刚出来他又觉得ATM机里面有钱了(有押运车来往里放 钱),又进去了,他这样来回反复横跳,一直占着ATM机,不让第二个和第三个人使用!

在操作系统中,这种情况是经常发生的,因为资源的调度是随机的。假设这里有多个线程,系统一直调用某一个线程,让其他线程一直处于阻塞等待,这种情况就叫做线程饿死(线程饥饿)

那么怎么解决这种问题呢?这里就引出了wait()方法!!!

一、wait()方法

  • wait() 方法用于使当前线程等待(挂起)(释放当前锁),让其他线程可以使用这把锁。
    public static void main(String[] args) {Object lock = new Object();Thread t1 = new Thread(() -> {synchronized (lock) {try {System.out.println("wait 之前");lock.wait();System.out.println("wait 之后");} catch (InterruptedException e) {throw new RuntimeException(e);}}});t1.start();}

由于这段代码在执行wait()方法之后就一直等待下去,这里肯定不可能让这段代码一直等待下去。所以就引入一个新的方法唤醒wait()方法------notify()方法。

wait()方法需要注意的:

  1. 必须搭配synchronized()使用,脱离synchronized()就会抛出异常
  2. 其他线程调⽤该等待线程的 interrupted ⽅法, 导致 wait 抛出 InterruptedException 异常
  3. wait()方法也有等待超时

二、notify()方法

这个方法是为了唤醒wait()方法,防止wait()方法一直等待下去!
• ⽅法notify()也要在同步⽅法或同步块中调⽤,该⽅法是⽤来通知那些可能等待该对象的对象锁的其它线程,对其发出通知notify,并使它们重新获取该对象的对象锁。
• 如果有多个线程等待,则有线程调度器随机挑选出⼀个呈 wait 状态的线程。(并没有 “先来后到”)
• 在notify()⽅法后,当前线程不会⻢上释放该对象锁,要等到执行notify()方法的线程将程序执行完,也就是退出同步代码块之后才会释放对象锁。

public class Demo2 {public static void main(String[] args) {Object lock = new Object();Thread t1 = new Thread(() -> {synchronized (lock) {try {System.out.println("wait 之前");lock.wait();System.out.println("wait 之后");} catch (InterruptedException e) {throw new RuntimeException(e);}}});Thread t2 = new Thread(() -> {synchronized (lock) {lock.notify();System.out.println("唤醒wait()方法");}});t1.start();t2.start();}
}

如果这里有多个wait()方法,只有一个notify()方法,这个唤醒是随机的!!!

三、notifyAll()方法

notify⽅法只是唤醒某⼀个等待线程. 使⽤notifyAll⽅法可以⼀次唤醒所有的等待线程.

    public static void main(String[] args) {Object lock1 = new Object();Object lock2 = new Object();Thread t3 = new Thread(() -> {synchronized (lock1) {try {System.out.println("t3 wait()方法之前");lock1.wait();System.out.println("t3 wait()方法之后");} catch (InterruptedException e) {throw new RuntimeException(e);}}});Thread t1 = new Thread(() -> {synchronized (lock1) {try {System.out.println("t1 wait()方法之前");lock1.wait();System.out.println("t1 wait()方法之后");} catch (InterruptedException e) {throw new RuntimeException(e);}}});Thread t2 = new Thread(() -> {synchronized (lock1) {lock1.notifyAll();System.out.println("唤醒wait()方法");}});t3.start();t1.start();t2.start();}
}

wait()、notify()、notifuAll()三种方法都是Object类中的方法!!!

四、wait()和sleep()对比

相同:

  • 都可以让线程放弃一段时间。

不同:

wait:

  • 是Object类中的方法
  • 需要搭配synchronized使用
  • 用于线程间的协作
  • 释放锁,允许其他线程运行
  • 需要在同步块中调用
  • 可以通过 notify() 或超时唤醒

sleep:

  • 是Thread的静态方法
  • 用于简单的延时操作
  • 不释放锁
  • 可以在任何地方调用
  • 只能通过睡眠时间结束或中断唤醒

五、单例模式

设计模式(Design Patterns)是软件工程中用于解决常见问题的可复用的解决方案。它们是经过验证的最佳实践,能够帮助开发者设计出更灵活、可维护和可扩展的代码。

单例模式能保证某个类在程序中只存在唯⼀⼀份实例, ⽽不会创建多个实例。
Thread t1=new Thread();t1就是创建的实例。

单例模式具体的实现方式有很多,最常见的是“饿汉”和“懒汉”两种。

5.1 饿汉模式

类加载的同时,创建实例

class MyDesign{private static MyDesign obj = new MyDesign();private MyDesign(){}public static MyDesign getInstance(){return obj;}
}

5.2 懒汉模式

类加载的时候不创建实例. 第⼀次使⽤的时候才创建实例.

class MyDesignF{private static MyDesignF obj = null;private MyDesignF(){}public static MyDesignF getInstance(){if(obj == null){obj = new MyDesignF();}return obj;}
}

饿汉模式不会出现线程安全问题;懒汉模式会出现线程安全问题!

饿汉模式:没有修改操作,所以不会出现线程安全问题。
懒汉模式:有修改操作,所以线程不安全。

在这里插入图片描述

5.2 懒汉模式-线程安全(改进)

  • 加synchronized
class MyDesignF{private static MyDesignF obj = null;private MyDesignF(){}public  static MyDesignF getInstance(){synchronized (MyDesignF.class){if(obj == null){obj = new MyDesignF();}}return obj;}
}
  • 双重if判断,降低锁竞争的频率
class MyDesignF{private static MyDesignF obj = null;private MyDesignF(){}public  static MyDesignF getInstance(){if(obj == null){synchronized (MyDesignF.class){if(obj == null){obj = new MyDesignF();}}}return obj;}
}
  • 给obj加上volatile
class MyDesignF{private volatile static MyDesignF obj = null;private MyDesignF(){}public  static MyDesignF getInstance(){if(obj == null){synchronized (MyDesignF.class){if(obj == null){obj = new MyDesignF();}}}return obj;}
}

volatile关键字作用:(防止指令重排序
在懒汉模式中,obj = new MyDesignF();也可以分为三步:

  • 分配内存空间。----1
  • 调用构造函数初始化对象。----2
  • 将内存地址赋值给 obj 变量。----3

正常情况下是1-》2-》3,但如果发生指令重排序就会出现1-》3-》2,先将内存地址赋值给obj,但还没有进行初始化对象,此时如果另一个线程访问obj,还未完全初始化的对象,那么此时就出现错误!!!

此篇博客的全部代码!!!

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

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

相关文章

http报文的content-type参数和spring mvc传参问题

很早之前博主聊过HTTP的报文结构以及其中和传参相关的重要参数content-type还有spring mvc,以前的三篇文章: HTTP与HTTPS协议详解:基础与安全机制-CSDN博客 详解Http的Content-Type_content-type application-CSDN博客 如何在Spring Boot中…

‘ts-node‘ 不是内部或外部命令,也不是可运行的程序

新建一个test.ts文件 let message: string = Hello World; console.log(message);如果没有任何配置的前提下,会报错’ts-node’ 不是内部或外部命令,也不是可运行的程序。 此时需要安装一下ts-node。 npm install

《白帽子讲 Web 安全:点击劫持》

目录 摘要: 一、点击劫持概述 二、点击劫持的实现示例:诱导用户收藏指定淘宝商品 案例 构建恶意页面: 设置绝对定位和z - index: 控制透明度: 三、其他相关攻击技术 3.1图片覆盖攻击与 XSIO 3.2拖拽劫持与数据…

基于机器学习的图像分类综述

图像分类是计算机视觉和模式识别领域的核心任务之一,其目标是从输入的图像中自动识别并标注其所属的类别标签。基于机器学习的图像分类技术近年来取得了显著进展,尤其是在深度学习的推动下,性能得到了质的提升,并在多个实际应用中表现出色。 以下是对基于机器学习的图像分…

SQL Server 中行转列

在 SQL Server 数据库中,行转列在实践中是一种非常有用,可以将原本以行形式存储的数据转换为列的形式,以便更好地进行数据分析和报表展示。本文将深入浅出地介绍 SQL Server 中的行转列技术,并以数据表中的时间数据为例进行详细讲…

系统架构设计师—计算机基础篇—系统性能评价

文章目录 性能评价指标主频CPU时钟周期机器周期CPIMIPS 系统性能调整阿姆达尔解决方案性能优化数据库应用系统Web应用系统 性能评估方法评价程序真实程序基准测试程序核心程序小型基准程序合成基准程序 基准测试程序组 评测准确度 性能指标计算机数据库应用系统Web应用系统 性能…

web3.0简介

Web3.0(或简称 Web3)是近年来广泛讨论的一个新型互联网概念,其核心思想在于利用区块链及相关分布式技术,打造一个更加开放、去中心化、透明且以用户为主导的网络生态系统。这意味着在 Web3.0 时代,用户不再只是信息的消…

python第十一课:并发编程 | 多任务交响乐团

🎯 本节目标 理解多线程/多进程/协程的应用场景掌握threading与multiprocessing核心用法学会使用asyncio进行异步编程开发实战项目:高并发爬虫引擎破解GIL锁的性能迷思 1️⃣ 并发编程三剑客 🎻 生活化比喻: 多线程 → 餐厅多个…

微服务架构实践:SpringCloud与Docker容器化部署

## 微服务架构实践:SpringCloud与Docker容器化部署 随着互联网应用的复杂性不断增加,传统的单体应用架构面临着诸多挑战,如难以部署、维护困难、开发效率低下等问题凸显出来。为了解决这些问题,微服务架构应运而生,它通…

SpringBoot实战(三十二)集成 ofdrw,实现 PDF 和 OFD 的转换、SM2 签署OFD

目录 一、OFD 简介 1.1 什么是 OFD?1.2 什么是 版式文档?1.3 为什么要用 OFD 而不是PDF? 二、ofdrw 简介 2.1 定义2.2 Maven 依赖2.3 ofdrw 的 13 个模块 三、PDF/文本/图片 转 OFD(ofdrw-conterver) 3.1 介绍&#xf…

随机树算法 自动驾驶汽车的路径规划 静态障碍物(Matlab)

随着自动驾驶技术的蓬勃发展,安全、高效的路径规划成为核心挑战之一。快速探索随机树(RRT)算法作为一种强大的路径搜索策略,为自动驾驶汽车在复杂环境下绕过静态障碍物规划合理路径提供了有效解决方案。 RRT 算法基于随机采样思想…

Vscode通过Roo Cline接入Deepseek

文章目录 背景第一步、安装插件第二步、申请API key第三步、Vscode中配置第四步、Deepseek对话 背景 在前期介绍【IDEA通过Contince接入Deepseek】步骤和流程,那如何在vscode编译器中使用deepseek,记录下来,方便备查。 第一步、安装插件 在…

C++ 二叉树代码

二叉树代码&#xff0c;见下 #include <iostream> using namespace std;template<typename T> struct TreeNode{T val;TreeNode *left;TreeNode *right;TreeNode():val(0), left(NULL), right(NULL)TreeNode(T x):val(x), left(NULL), right(NULL){} };template&l…

leetcode第17题求电话号码组合

原题出于leetcode第17题https://leetcode.cn/problems/letter-combinations-of-a-phone-number/description/题目如下&#xff1a; 题目稍微有点复杂&#xff0c;初看会感觉特别复杂&#xff0c;首先我们需要理清思路&#xff1a; 最后的结果是字母组合&#xff0c;因此遍历的是…

Deepseek对ChatGPT的冲击?

从测试工程师的视角来看&#xff0c;DeepSeek对ChatGPT的冲击主要体现在**测试场景的垂直化需求与通用模型局限性之间的博弈**。以下从技术适配性、效率优化、风险控制及未来趋势四个维度展开分析&#xff1a; --- ### **一、技术适配性&#xff1a;垂直领域能力决定工具选择…

三十五周学习周报

目录 摘要abstract文献阅读1.1相关知识1.1.1 PSO1.1.2 BI-LSTM1.1.3 BI-GRU 1.2 整体框架1.3 实验分析 总结 摘要 在本周阅读的文献中&#xff0c;作者提出了一种创新的水文时间序列预测模型&#xff0c;其通过将粒子群优化&#xff08;PSO&#xff09;与Bi-LSTM和Bi-GRU相结合…

Git:多人协作

目录 多人协作一 准备工作 开发者1准备工作 开发者2准备工作 协作开发 将内容合并进master 多人协作二 开发者1进行工作 开发者2进行工作 特殊场景 将内容合并进master 之前所学习的Git操作&#xff0c;是为了多人协作开发做铺垫的&#xff0c;因为在公司中&#xf…

登录次数限制

文章目录 一、应用场景与设计目的1. 应用场景2. 设计目的 二、功能设计1. 登录限制规则2. 解锁机制3. 适用维度 三、技术实现1. 数据存储2. 逻辑流程3. 实现代码示例4. 动态锁定时间 四、安全增强与扩展1. 防止用户名枚举2. 加入验证码3. 监控与报警4. 分布式支持 五、设计思考…

计算机毕业设计SpringBoot+Vue.js景区民宿预约系统(源码+文档+PPT+讲解)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

(十 五)趣学设计模式 之 命令模式!

目录 一、 啥是命令模式&#xff1f;二、 为什么要用命令模式&#xff1f;三、 策略模式的实现方式四、 命令模式的优缺点五、 命令模式的应用场景六、 总结 &#x1f31f;我的其他文章也讲解的比较有趣&#x1f601;&#xff0c;如果喜欢博主的讲解方式&#xff0c;可以多多支…