当前位置: 首页 > news >正文

JavaEE初阶-线程3

文章目录

  • 一、线程安全问题-内存可见性
  • 二、等待通知
    • 2.1 wait()方法
    • 2.2 notify()方法


一、线程安全问题-内存可见性

import java.util.Scanner;public class Demo27 {private static int count=0;//下面这段代码会出现内存的可见性问题//将从内存中读取count值的操作称为load 判断操作称为cmp//load和cmp的执行速度差了好几个数量级,在线程2开始执行代码提示输入数字时,线程1的while循环已经执行了很多遍//java编译器会自动给代码进行优化//导致load只是第一次时真正从内存中读取count值,其余都是从cpu的寄存器中读取//然而线程2修改count是在内存中进行修改,线程1根本访问不到count的值//可以在变量前加上volatile关键字来提醒编译器不要优化public static void main(String[] args) {Thread t1=new Thread(()->{while(count==0) {//}System.out.println("t1 执行结束");});Thread t2=new Thread(()->{Scanner scanner=new Scanner(System.in);System.out.println("输入数字:");count=scanner.nextInt();});t1.start();t2.start();}}

以上代码建立一个线程t1和线程t2,线程t1中建立一个循环,线程t2控制循环中的条件,按照预期,应该在t2中改变条件之后t1结束,整个程序也应该结束,但事实并非如此。
在这里插入图片描述
输入数字之后线程一仍然没有结束,这是因为count==0这个条件涉及到两个操作load和cmp,先将count的值从内存中载入cpu的寄存器进行比较,在线程二中还未输入数字时,线程一的循环已经执行很多次了,编译器发现这么多次count的值没有变化就会进行优化,只有第一个load会从内存中读count的值,剩余次数都是直接用寄存器中的值,这样既使后来在线程二当中改变了内存中的count的值,因为循环条件的count不从内存中读值因此访问不到修改后的count,线程一就会继续循环,从而程序就结束不了。如果不想让编译器进行优化,可以在count前面加上volatile关键字即可。
另外上述的内存可见性问题加锁,即包含在synchronized内也可以解决,因为加锁是比较重量的,load相对就不算慢了就不会触发优化。在循环内加上sout输出语句也是一个道理,sout相对于load更慢无法触发优化,自然也能解决上述的内存可见性的问题。

在网上查询资料还可以看到以一种JMM(java内存模型)角度来理解该问题的解答:
当t1执行的时候,会从工作内存中读取count而不是从主内存中。
t2修改count会先修改工作内存,再同步到主内存,但由于t1没有重新读主内存,导致t1没有感知到t2的修改。

二、等待通知

2.1 wait()方法

代码示例如下:

public class Demo28 {public static void main(String[] args) throws InterruptedException {Object locker = new Object();System.out.println("等待之前");//wait必须在synchronized内使用,会解锁并且让线程进入阻塞等待状态synchronized (locker) {locker.wait();}System.out.println("等待之后");}
}

wait方法是object类的方法,任何类对象都可以使用,它只能在锁内使用,如果执行wait方法会释放锁并且线程进入阻塞状态waiting。wait也有限时的参数,加上时间,会在限定时间内阻塞之后自动唤醒。
注意:wait和sleep一样可以被interrupt打断并且清空标志位。

2.2 notify()方法

通过notify方法来唤醒wait方法进入阻塞的线程,wait的线程状态从Waiting->Runnable->Blocked。
代码示例如下:

public class Demo29 {public static void main(String[] args) throws InterruptedException {Object locker = new Object();//1.wait和notify必须都在synchronized内//2.一个notify唤醒一个wait() 如果多个线程wait就使用多个notify或者notifyAll 这种唤醒时随机的//3.如果想唤醒指定线程也可以必须一对一写好锁对象//4.notify需要在wait之后Thread t1 = new Thread(() -> {System.out.println("t1 等待之前");synchronized (locker) {try {locker.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("t1 等待之后");});Thread t2 = new Thread(() -> {System.out.println("t2 通知之前");Scanner scanner = new Scanner(System.in);synchronized (locker) {
//控制阻塞,不输入数字t1仍是阻塞scanner.nextInt();locker.notify();}System.out.println("t2 通知之后");});t1.start();t2.start();}}

notify必须也在synchronized之内,并且一个notify只能唤醒对应的一个wait,如果多个线程wait就使用多个notify或者notifyAll,这种唤醒时随机的,唤醒的前提是通过一个对象来调用的wait及notify方法。如果想唤醒指定线程也可以必须一对一写好锁对象。另外notify的使用必须在wait之后,如果在wait之前使用notify不会有任何效果,不过wait就没有办法唤醒了。
使用相应的锁对象进行一对一唤醒代码示例如下:

public class Demo30 {public static void main(String[] args) throws InterruptedException {Object locker = new Object();Object locker1 = new Object();Thread t1 = new Thread(() -> {synchronized (locker) {System.out.println("t1等待之前");try {locker.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("t1等待之后");}});Thread t2 = new Thread(() -> {synchronized (locker1) {System.out.println("t2等待之前");try {locker1.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("t2等待之后");}});Thread t3 = new Thread(() -> {synchronized (locker) {//locker.notifyAll();locker.notify();}synchronized (locker1) {locker1.notify();}});t1.start();t2.start();Thread.sleep(1000);t3.start();}}

相关文章:

JavaEE初阶-线程3

文章目录 一、线程安全问题-内存可见性二、等待通知2.1 wait()方法2.2 notify()方法 一、线程安全问题-内存可见性 import java.util.Scanner;public class Demo27 {private static int count0;//下面这段代码会出现内存的可见性问题//将从内存中读取count值的操作称为load 判…...

C++递归(2)

数塔问题? 题目描述: 有如下所示的数塔,要求从底层走到顶层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少? 输入 输入数据首先包括一个整数整数N(1 输出 从底层走到顶层经过的数字的最大…...

算法训练营第27天|LeetCode 39.组合总和 40.组合总和2 131.分割回文串

LeetCode 39.组合总和 题目链接&#xff1a; LeetCode 39.组合总和 解题思路&#xff1a; 用回溯的方法&#xff0c;&#xff0c;注意这次回溯不是i1&#xff0c;而是i&#xff0c;是因为可用重复选取。 代码&#xff1a; class Solution { public:vector<vector<i…...

【Web】NSSCTF Round#20 Basic 两道0解题的赛后谈

目录 前言 baby-Codeigniter 组合拳&#xff01; 前言 本想着说看看go的gin框架就睡了的&#xff0c;r3师傅提醒说赛题环境已经上了&#xff0c;那不赶紧研究下&#x1f600; 主要来谈谈做题的心路历程 baby-Codeigniter 拿到题目的第一反应应该是&#xff1a;“什么是C…...

memcached缓存数据库简介

memcached是一套分布式的高速缓存系统&#xff0c;由LiveJournal的Brad Fitzpatrick开发&#xff0c;但被许多网站使用。这是一套开放源代码软件&#xff0c;以BSD license授权发布。 memcached缺乏认证以及安全管制&#xff0c;这代表应该将memcached服务器放置在防火墙后。 …...

C# WPF编程-Application类(生命周期、程序集资源、本地化)

C# WPF编程-Application类 应用程序的生命周期创建Application对象应用程序的关闭方式应用程序事件 Application类的任务显示初始界面处理命令行参数访问当前Application对象在窗口之间进行交互 程序集资源添加资源检索资源pack URI内容文件 每个运行中的WPF应用程序都由System…...

fpga_hdmi

HDMI简介: 高清晰度多媒体端接口&#xff0c;通常用来连接一些音视频设备&#xff0c;进行高质量的传输&#xff0c;能够同时传输音频信号和视频信号。而且在传输速度上具有较大的优势。 通过hdmi接口进行数据传输时&#xff0c;不需要切换模块&#xff0c;或者提前设置转换。…...

鸿蒙(HarmonyOS)ArkTs语言基础教程开发准备

本文档适用于HarmonyOS应用开发的初学者。通过构建一个简单的具有页面跳转/返回功能的应用&#xff08;如下图所示&#xff09;&#xff0c;快速了解工程目录的主要文件&#xff0c;熟悉HarmonyOS应用开发流程。 在开始之前&#xff0c;您需要了解有关HarmonyOS应用的一些基本概…...

【C++杂货铺】详解list容器

目录 &#x1f308;前言&#x1f308; &#x1f4c1; 介绍 &#x1f4c1; 使用 &#x1f4c2; 构造 &#x1f4c2; 迭代器iterator &#x1f4c2; capacity &#x1f4c2; modifiers &#x1f4c2; 迭代器失效 &#x1f4c1; 模拟实现 &#x1f4c2; 迭代器的实现 &#x…...

使用filezilla连接Ubuntu22.04虚拟机

获取电脑IP和虚拟机IP ① 在windows下ctrlR再输入cmd&#xff0c;打开指令窗口&#xff0c;输入 ipconfig 虚拟机连接电脑用的是NAT模式&#xff0c;故看VMnet8的IP地址 ② 查看虚拟机IP地址 终端输入 ifconfig 如果没安装&#xff0c;按提示安装net-tools sudo apt install …...

Verilog基础【二】

3.1 Verilog 连续赋值 关键词&#xff1a;assign&#xff0c; 全加器 连续赋值语句是 Verilog 数据流建模的基本语句&#xff0c;用于对 wire 型变量进行赋值。&#xff1a; assign LHS_target RHS_expression &#xff1b;LHS&#xff08;left hand side&#xff09;…...

定时推送任务 Apache HttpClient/okhttp3

定时推送任务 需求 需要定时推送我方的数据到对方那边 方法1 Apache HttpClient 此方法指定推送过去的信息转为utf-8格式的json字符串 Scheduled(initialDelay 1000 * 120, fixedDelay 1000 * 60 * 5) public void diseaseInterface() {String lockKey "lock:dise…...

centos7 安装 mysql

命令记录&#xff0c;未整理&#xff1b; 1. 下载mysql5.7的安装包&#xff0c;上传到linux系统某个目录中 2. 使用tar -xvf 解压 tar包 tar -xvf mysql-5.7.35-1.el7.x86_64.rpm-bundle.tar 3. 使用 rpm -ivh 安装 mysql rpm -ivh mysql-community-common-5.7.35-1.el7.x8…...

src挖掘技巧总结分享

src挖洞技术分享 src推荐刚入门的新手首选公益src如漏洞盒子、补天src&#xff0c;因为漏洞盒子收录范围广&#xff0c;只要是国内的站点都收入&#xff0c;相比其它src平台挖掘难度非常适合新手。后续可以尝试先从一些小的src厂商入手。 首先是熟能生巧&#xff0c;我一开始挖…...

【面试八股总结】传输控制协议TCP(一)

一、什么是TCP协议 TCP是传输控制协议Transmission Control Protocol TCP 是面向连接的、可靠的、基于字节流的传输层通信协议。 面向连接的&#xff1a;每条TCP连接杜只能有两个端点&#xff0c;每一条TCP连接只能是点对点的&#xff08;一对一&#xff09;可靠的&#xff1a…...

【系统架构师】-第13章-层次式架构设计

层次式体系结构设计是将系统组成一个层次结构&#xff0c;每一层 为上层服务 &#xff0c;并作为下层客户。 在一些层次系统中&#xff0c;除了一些精心挑选的输出函数外&#xff0c; 内部的层接口只对相邻的层可见 。 连接件通过决定层间如何交互的协议来定义&#xff0c;拓扑…...

【操作系统】想要更好的学习计算机,操作系统的知识必不可少!!!

操作系统的概念 导言一、日常生活中的操作系统二、计算机系统层次结构三、操作系统的定义3.1 控制和管理计算机资源3.2 组织、调度计算机的工作与资源的分配3.3 给用户和其他软件提供方便接口与环境3.4 总结 四、操作系统的目标和功能4.1 作为管理者4.1.1 处理机管理4.1.2 存储…...

AtCoder Grand Contest 066 B. Decreasing Digit Sums(构造 打表找规律)

题目 给定一个n(n<50)&#xff0c;记f(x)是x各数位的加和&#xff0c;例如f(331)3317 要求输出一个x()&#xff0c;且对于任意i∈[1,n]&#xff0c;均有成立 思路来源 jiangly B站讲解 题解 首先n没啥用&#xff0c;构造一个n50成立的case即可&#xff0c; 给定一个x…...

Hadoop系列总结

一、Hadoop linux基本操作 前提掌握Linux基本操作 参考 Linux基本操作-CSDN博客 1、查看hadoop指定路径下文件大小前6的文件信息 hdfs dfs[hadoop fs] -du -h /path/to/directory|sort -hr|head -n 6...

【第三方登录】Twitter

创建应用 APPID 和 相关回调配置 重新设置api key 和 api secret 设置回调和网址 还有 APP的类型 拿到ClientID 和 Client Secret 源码实现 获取Twitter 的登录地址 public function twitterUrl() {global $db,$request,$comId;require "inc/twitter_client/twitte…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)

2025年能源电力系统与流体力学国际会议&#xff08;EPSFD 2025&#xff09;将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会&#xff0c;EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

剑指offer20_链表中环的入口节点

链表中环的入口节点 给定一个链表&#xff0c;若其中包含环&#xff0c;则输出环的入口节点。 若其中不包含环&#xff0c;则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

华为OD机试-食堂供餐-二分法

import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

跨链模式:多链互操作架构与性能扩展方案

跨链模式&#xff1a;多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈&#xff1a;模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展&#xff08;H2Cross架构&#xff09;&#xff1a; 适配层&#xf…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

Mobile ALOHA全身模仿学习

一、题目 Mobile ALOHA&#xff1a;通过低成本全身远程操作学习双手移动操作 传统模仿学习&#xff08;Imitation Learning&#xff09;缺点&#xff1a;聚焦与桌面操作&#xff0c;缺乏通用任务所需的移动性和灵活性 本论文优点&#xff1a;&#xff08;1&#xff09;在ALOHA…...

HDFS分布式存储 zookeeper

hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架&#xff0c;允许使用简单的变成模型跨计算机对大型集群进行分布式处理&#xff08;1.海量的数据存储 2.海量数据的计算&#xff09;Hadoop核心组件 hdfs&#xff08;分布式文件存储系统&#xff09;&a…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表

##鸿蒙核心技术##运动开发##Sensor Service Kit&#xff08;传感器服务&#xff09;# 前言 在运动类应用中&#xff0c;运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据&#xff0c;如配速、距离、卡路里消耗等&#xff0c;用户可以更清晰…...

安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲

文章目录 前言第一部分&#xff1a;体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分&#xff1a;体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...