Java之线程篇四

目录
volatile关键字
volatile保证内存可见性
代码示例
代码示例2-(+volatile)
volatile不保证原子性
synchronized保证内存可见性
wait()和notify()
wait()方法
notify()
理解notify()和notifyAll()
wait和sleep的对比
volatile关键字
volatile保证内存可见性
volatile 修饰的变量, 能够保证 "内存可见性".

代码在写入 volatile 修饰的变量的时候:
改变线程工作内存中volatile变量副本的值
将改变后的副本的值从工作内存刷新到主内存
代码在读取 volatile 修饰的变量的时候:
从主内存中读取volatile变量的最新值到线程的工作内存中
从工作内存中读取volatile变量的副本
加上 volatile , 强制读写内存. 速度是慢了, 但是数据变的更准确了。
代码示例
public class Demo13 {private static int isQuit=0;public static void main(String[] args) {Thread t1=new Thread(()->{while(isQuit==0){}System.out.println("t1 退出");});t1.start();Thread t2=new Thread(()->{System.out.println("请输入 isQuit:");Scanner scanner=new Scanner(System.in);isQuit=scanner.nextInt();});t2.start();}
}
运行结果

通过jconsole观察,会看到线程t1处于RUNNABLE状态。

t1 读的是自己工作内存中的内容 .当 t2 对 flag 变量进行修改 , 此时 t1 感知不到 flag 的变化 .
原因解释:
1) load 读取内存中isQuit的值到寄存器中.
2)通过cmp 指令比较寄存器的值是否是0.决定是否要继续循环.
由于这个循环,循环速度飞快.短时间内,就会进行大量的循环.也就是进行大量的load和cmp 操作.此时,编译器/JVM就发现了,虽然进行了这么多次load,但是 load 出来的结果都一样的.并且, load 操作又非常费时间,一次load花的时间相当于上万次cmp 了.
所以编译器就做了一个大胆的决定~~只是第一次循环的时候才读了内存.后续都不再读内存了,而是直接从寄存器中,取出isQuit的值了.
代码示例2-(+volatile)
public class Demo13 {private static volatile int isQuit=0;public static void main(String[] args) {Thread t1=new Thread(()->{while(isQuit==0){}System.out.println("t1 退出");});t1.start();Thread t2=new Thread(()->{System.out.println("请输入 isQuit:");Scanner scanner=new Scanner(System.in);isQuit=scanner.nextInt();});t2.start();}
}
运行结果

代码示例3-(+sleep)
public class Demo13 {private static int isQuit=0;public static void main(String[] args) {Thread t1=new Thread(()->{while(isQuit==0){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("t1 退出");});t1.start();Thread t2=new Thread(()->{System.out.println("请输入 isQuit:");Scanner scanner=new Scanner(System.in);isQuit=scanner.nextInt();});t2.start();}
}
运行结果

volatile不保证原子性
代码示例
class Counter {volatile public int count = 0;void increase() {count++;}
}public class Demo13 {public static void main(String[] args) throws InterruptedException {final Counter counter = new Counter();Thread t1 = new Thread(() -> {for (int i = 0; i < 50000; i++) {counter.increase();}});Thread t2 = new Thread(() -> {for (int i = 0; i < 50000; i++) {counter.increase();}});t1.start();t2.start();t1.join();t2.join();System.out.println(counter.count);}
}
运行结果

我们会发现,加上volatile以后,依旧不是线程安全的。
synchronized保证内存可见性
代码示例
class Counter {public int flag = 0;
}public class Demo13 {public static void main(String[] args) {Counter counter = new Counter();Thread t1 = new Thread(() -> {while (true) {synchronized (counter) {if (counter.flag != 0) {break;}}}System.out.println("循环结束!");});Thread t2 = new Thread(() -> {Scanner scanner = new Scanner(System.in);System.out.println("输入一个整数:");counter.flag = scanner.nextInt();});t1.start();t2.start();}
}
运行结果

wait()和notify()
wait()方法
wait 做的事情:
使当前执行代码的线程进行等待. (把线程放到等待队列中)
释放当前的锁
满足一定条件时被唤醒, 重新尝试获取这个锁.
wait 要搭配 synchronized 来使用. 脱离 synchronized 使用 wait 会直接抛出异常.
代码示例
public class Demo14 {public static void main(String[] args) throws InterruptedException {Object object = new Object();synchronized (object) {System.out.println("wait 之前");// 把 wait 要放到 synchronized 里面来调用. 保证确实是拿到锁了的.object.wait();System.out.println("wait 之后");}}
}
运行结果

此时object就会一直进行wait,当然我们肯定不想让程序一直等待下去,下面将介绍notify()来唤醒它。
notify()
notify 方法是唤醒等待的线程.
方法notify()也要在同步方法或同步块中调用,该方法是用来通知那些可能等待该对象的对象锁的其它线程,对其发出通知notify,并使它们重新获取该对象的对象锁。
如果有多个线程等待,则有线程调度器随机挑选出一个呈 wait 状态的线程。(并没有 "先来后到"),在notify()方法后,当前线程不会马上释放该对象锁,要等到执行notify()方法的线程将程序执行完,也就是退出同步代码块之后才会释放对象锁。
代码示例
public class Demo15 {public static void main(String[] args) {Object object = new Object();Thread t1 = new Thread(() -> {synchronized (object) {System.out.println("wait 之前");try {object.wait();
// object.wait(5000);//也可以指定等待时间后自动唤醒} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("wait 之后");}});Thread t2 = new Thread(() -> {try {Thread.sleep(3000);} catch (InterruptedException e) {throw new RuntimeException(e);}synchronized (object) {System.out.println("进行通知");object.notify();}});t1.start();t2.start();}
}
运行结果

notifyAll()
class WaitTask implements Runnable {private Object locker;public WaitTask(Object locker) {this.locker = locker;}@Overridepublic void run() {synchronized (locker) {while (true) {try {System.out.println("wait 开始");locker.wait();System.out.println("wait 结束");} catch (InterruptedException e) {e.printStackTrace();}}}}
}
class NotifyTask implements Runnable {private Object locker;public NotifyTask(Object locker) {this.locker = locker;}@Overridepublic void run() {synchronized (locker) {System.out.println("notify 开始");locker.notifyAll();System.out.println("notify 结束");}}
}public class Demo16 {public static void main(String[] args) throws InterruptedException {Object locker = new Object();Thread t1 = new Thread(new WaitTask(locker));Thread t3 = new Thread(new WaitTask(locker));Thread t4 = new Thread(new WaitTask(locker));Thread t2 = new Thread(new NotifyTask(locker));t1.start();t2.start();t3.start();Thread.sleep(5000);t4.start();}
} 运行结果

注意: 虽然是同时唤醒 3 个线程, 但是这 3 个线程需要竞争锁. 所以并不是同时执行, 而仍然是有先有后的执行.
理解notify()和notifyAll()

notifyAll 一下全都唤醒, 需要这些线程重新竞争锁.

wait和sleep的对比
1. wait 需要搭配 synchronized 使用 . sleep 不需要 .2. wait 是 Object 的方法 sleep 是 Thread 的静态方法 .
相关文章:
Java之线程篇四
目录 volatile关键字 volatile保证内存可见性 代码示例 代码示例2-(volatile) volatile不保证原子性 synchronized保证内存可见性 wait()和notify() wait()方法 notify() 理解notify()和notifyAll() wait和sleep的对比 volatile关键字 volati…...
计算机毕业设计之:基于微信小程序的校园流浪猫收养系统
博主介绍: ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台…...
SpringBoot:关于Redis的配置失效(版本问题)
我们使用redis时发现yaml配置中的redis相关配置不生效,后面发现将配置修改甚至删除所有相关redis的配置,springboot依然能使用redis里面默认的db0并且不报错。上网查阅了一些文章,也都没有解决今天分享下,我的处理方法, SpringBo…...
halcon 快速定义字典
定义一个名为params的字典 Params : dict{} 等价于用 create_dict (Params ) 为字典添加键值对,在halcon中箭只能是字符串,值可以是任何类型的obj或者tuple Params.remove_outer_edges : true Params.max_gap : 150 等价于用 set_dict_object (true,…...
Sublime text3怎么关闭提示更新
问题 sublime text 3有新版本后,会不停地在每次启动后弹窗提示更新版本 第一步 软件安装之前,切记是软件安装之前!!!需要在hosts中添加以下内容(屏蔽官网联网检测):hosts的位置一般在C:\Windows\System32\drivers\etc…...
生成式语言模型技术栈
生成式语言模型的最新技术栈正在快速发展,尤其是随着大规模预训练模型(LLMs)和生成式AI的应用不断扩展。以下是当今最前沿的生成式语言模型技术栈,涵盖从模型开发到优化、推理和部署的各个环节。 1. 基础模型开发 基础模型开发包…...
进程分析工具Process Explorer使用
进程分析工具Process Explorer使用 Process Explorer让使用者能了解看不到的在后台执行的处理程序,能显示目前已经载入哪些模块,分别是正在被哪些程序使用着,还可显示这些程序所调用的DLL进程,以及他们所打开的句柄。Process Expl…...
vue 中如何实现鼠标拖动出发滚动条的跟随移动?
使用场景 在做弹窗、表单或 tab 切换需求的时候,有时候因为内容过长会导致出现滚动条,但是只能拖动滚动条时会导致操作不便,我们会希望实现通过拖动内容区实现滚动条的滑动。这样操作就会简单多了。 实现思路 如果要实现鼠标辅助触发滚动条…...
【Java EE】文件IO
Author:MTingle major:人工智能 --------------------------------------- Build your hopes like a tower! 目录 一、文件是什么? 二、针对文件系统操作的API 1.文件路径,文件名,文件是否存在 2. 创建文件 3.删除文件&#…...
使用 React、Material-UI、Spring、MySQL、MyBatis 以及高德 API 模拟实时位置信息
要使用 React、Material-UI、Spring、MySQL、MyBatis 以及高德 API 模拟实时位置信息,你可以按以下步骤来实现: 目录 1. 前端 (React Material-UI) 2. 后端 (Spring Boot MyBatis MySQL) 3. 模拟实时位置数据 4. 前后端联调 1. 前端 (React Mat…...
UniApp一句话经验: px -> rpx动态转换和动态元素区域的获取
px->rpx转换 在多终端条件下,什么devicePixelRatio,upx2px都是不靠谱的,最直接的是这样: const { screenWidth } uni.getSystemInfoSync()const pixelUnit screenWidth / 750 // rpx->px比例基数 动态元素区域获取 多终…...
Python基于flask框架的智能停车场车位系统 数据可视化分析系统fyfc81
目录 技术栈和环境说明解决的思路具体实现截图系统设计python语言django框架介绍flask框架介绍性能/安全/负载方面可行性分析论证python-flask核心代码部分展示python-django核心代码部分展示技术路线操作可行性详细视频演示源码获取 技术栈和环境说明 结合用户的使用需求&…...
海外服务器哪个速度最快且性能稳定
海外服务器的速度与性能稳定性受多种因素影响,包括地理位置、网络架构、基础设施质量以及用户网络路径等。在众多选择中,几个特定地区的服务器因其卓越表现而备受推崇。 首先,美国硅谷(加利福尼亚州)与纽约的服务器以其技术领先、网络连接稳定…...
C/C++通过CLion2024进行Linux远程开发保姆级教学
目前来说,对Linux远程开发支持相对比较好的也就是Clion和VSCode了,这两个其实对于C和C语言开发都很友好,大可不必过于纠结使用那个,至于VS和QtCreator,前者太过重量级了,后者更是不用说,主要用于…...
工程师 - 如何安装Windows 终端
Windows 终端是一款适用于 Windows 的现代命令行应用程序,支持多个终端会话,包括 Command Prompt、PowerShell 和 Windows Subsystem for Linux (WSL)。它具有标签式界面、可定制的设置(如主题和按键绑定)、改进的文本渲染以及对 …...
UniApp 从Vue2升级为Vue3需要注意哪些方面
Vue官方已经发布了Vue3,Vue2不再维护,也在建议大家都迁移到Vue3,所以Vue2终会被淘汰。 那么UniApp 从Vue2升级为Vue3需要注意哪些方面: 1、main.js 下面请看创建应用实例Vue2与Vue3的不同: Vue2的写法:…...
前端面试CSS常见题目
1. CSS 选择器的优先级 (Specificity) 面试官通常会问你如何计算 CSS 选择器的优先级,这对于避免样式冲突、提高代码可维护性很重要。 优先级计算规则: !important 优先级最高。内联样式(例如:<div style"color: red;&…...
408算法题leetcode--第10天
643. 子数组最大平均数 I 643. 子数组最大平均数 I思路:滑动窗口时间:O(n);空间:O(1) class Solution { public:double findMaxAverage(vector<int>& nums, int k) {double ret 0, temp 0;size_t size nums.size()…...
13年计算机考研408-数据结构
解析: 这个降序链表不影响时间复杂度,因为是链表,所以你想要升序就使用头插法,你想要降序就使用尾插法。 然后我们来分析一下最坏的情况是什么样的。 因为m和n都是两个有序的升序序列。 如果刚好m的最大值小于n的最小值࿰…...
跨平台开发新视角:利用Android WebView实现Web内容的原生体验
在移动应用开发领域,跨平台解决方案一直是一个热门话题。开发者们不断寻求能够同时在iOS和Android平台上提供一致用户体验的方法。而Android的WebView组件,作为一个强大的工具,允许开发者在Android应用中嵌入Web内容,为用户提供接…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...
Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...
