Java EE之wait和notify

news2024/9/27 9:28:35

一.多线程的执行顺序

由于多个线程执行是抢占式执行,就会导致顺序不同,同时就会导致出现问题,就比如俩个线程同时对同一个变量进行修改,我们难以预知执行顺序。

但在实际开发中,我们希望代码按一定的逻辑顺序执行,希望可以协调多个线程的执行顺序。

之前提到过join,会让调用它的线程进入阻塞等待,但有个缺陷就是,它必须得等那个线程完全执行完才能继续执行。怎么才能随意调度?

可以用到wait和notify方法

二.wait和notify

1.wait和notify可以协调多个线程的执行顺序

wait可以让指定线程进入阻塞等待状态,notify可以唤醒正在wait的线程

2.wait和notify是依赖对象的

wait和notify都是Object类里面的成员方法,它们的调用是依赖对象的

3.wait所做的工作

在了解wait所做的工作之前,我们先看一个wait和notify使用的实例:

我们发现唤醒wait之后,没有进行打印操作,而是抛出了异常,这个异常叫做:IllegalMonitorStatementException非法的监视器状态异常,什么是监视器?其实这里说的是synchronized锁,它也叫做监视器锁。这里我们就可以来了解一下wait所作的工作:

1.释放当前所持有的锁

2.让线程进入阻塞状态,并等待被唤醒。

3.当线程被唤醒时,重新获取到锁

所以说,使用wait的前提是得加锁,同时notify也得加锁,对谁加锁?就是对调用wait和notify的哪个对象进行加锁。

为什么要这样加锁呢?首先对线程1进行加锁,当它不想做任何事情时,就进入阻塞状态,此时它啥也不干,就没必要拿着锁,就释放了,让急需锁的线程2先用,当线程2的任务完成的差不多时,他就可以把锁还给线程1了。所以代码修改如下:

4.notify

唤醒正在等待的线程。当有多个线程都在等待时(前提是这几个等待的线程都在等待同一把锁),notify唤醒时是随即唤醒其中的一个线程而其他线程还在等待。并且,如果notify后面还有代码(在synronized里面),就会先执行完这些代码,再唤醒wait的线程如下例子:

public class Test2 {
    private static Object object=new Object();
    public static void main(String[] args) {
        Thread t1=new Thread(()->{
            synchronized(object) {
                System.out.println("t1kaishi");
                try {
                    object.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t1jieshu");
            }
        });
        Thread t2=new Thread(()->{
            synchronized (object){
                System.out.println("t2kaishi");
                try {
                    object.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t2jieshu");
            }
        });
        Thread t3=new Thread(()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (object){
                try {
                    object.notify();
                    Thread.sleep(1000);
                    System.out.println("t3jieshu");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t1.start();
        t2.start();
        t3.start();
    }
}

首先,t1t2是等待线程,t3是通知线程。t1开始,先得到了锁,然后wait时释放了锁,这时t2拿到了锁,然后wait时释放了锁;之后等1秒过后,t3拿到了锁,然后唤醒等待该锁的线程,但我们发现,最终是t1结束了,但t2没有结束而且程序迟迟没有结束,这说明只有t1被唤醒了,而t2还在wait。而且可以发现,是t3结束先打印的,说明是notify之后会把后面的代码全部执行完才会去唤醒线程,而在调用了notify和t3后续代码执行完期间,t1的状态就是BLOCKED状态,如下:

这是在t3执行了notify之后,t1的状态:Thread-2(也就是t3)持有锁,而Thread-0(t1)已经不是waiting状态了,而是BOLCKED状态,它已经被唤醒,在等锁。

5.notifyAll

notifyAll方法是一次唤醒所有线程。这与notify不同的是,所有线程都可以从WAITING状态转变成其他状态,但是,一i那位它们都想拿同一把锁,所以会出现锁金正,没拿到锁的就得等待持有锁的把锁释放了再去竞争,在等待锁的过程中,这些线程就是BLOCKED状态

public class Test2 {
    private static Object object=new Object();
    public static void main(String[] args) {
        Thread t1=new Thread(()->{
            synchronized(object) {
                System.out.println("t1kaishi");
                try {
                    object.wait();
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t1jieshu");
            }
        });
        Thread t2=new Thread(()->{
            synchronized (object){
                System.out.println("t2kaishi");
                try {
                    object.wait();
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t2jieshu");
            }
        });
        Thread t3=new Thread(()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (object){
                try {
                    object.notifyAll();
                    Thread.sleep(1000);
                    System.out.println("t3jieshu");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t1.start();
        t2.start();
        t3.start();
    }
}

还是上面这个代码,只不过在t1t2被唤醒后又让它们沉睡了1秒,以便观察它们的状态,这一次是notify之后,t2抢到了锁,观察jconsole.exe,发现t1和t2都是BLOCKED,因为先执行了t3锁里面的内容,然后是t2开始执行,此时t1还是BLOCKED,最后t1也拿到了锁。

6.注意

一般我们使用nootify方法,而不是用notifyAll方法,因为notify方法更加可控,而notifyAll方法却会引起竞争,而且会增加cpu的消耗

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

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

相关文章

Visual Basic6.0零基础教学(2)—vb中类的介绍和基本控件的属性

Visual Basic 6.0中类的介绍和基本控件的属性 文章目录 Visual Basic 6.0中类的介绍和基本控件的属性前言一、对象的有关概念1.类2.对象3.对象的三要素4.5. VB程序的执行步骤 二、基本控件属性1.修改控件属性的练习案例 总结 前言 大家好,昨天我们学习了vb的简单介…

elasticsearch 深度分页查询 Search_after(图文教程)

Search_after使用 一. 简介二. 不带PIT的search_after查询2.1 构造数据2.2 search_after分页查询2.2 问题 三. 带PIT的search_after查询3.1 构建第一次查询条件3.2 进行下一页查询3.3 删除PIT 四.参考文章 前言 这是我在这个网站整理的笔记,有错误的地方请指出,关注…

opencv解析系列 - 基于DOM提取大面积植被(如森林)

Note&#xff1a;简单提取&#xff0c;不考虑后处理&#xff08;填充空洞、平滑边界等&#xff09; #include <iostream> #include "opencv2/imgproc.hpp" #include "opencv2/highgui.hpp" #include <opencv2/opencv.hpp> using namespace cv…

Feign远程调用错误

说明&#xff1a;记录一次使用Feign远程调用的错误&#xff0c;错误信息如下&#xff1a; },Server stats: [[Server:192.168.222.1:8082; Zone:UNKNOWN; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 08:…

spring-boot-maven-plugin springboot打包配置问题

目录 一、打包可执行jar 二、打包非可执行jar 三、两种jar对比 springboot项目的pom文件中一般都配置了spring-boot-maven-plugin打包插件。 <!-- 打包插件依赖 --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-b…

论文阅读:Iterative Denoiser and Noise Estimator for Self-Supervised Image Denoising

这篇论文是发表在 2023 ICCV 上的一篇工作&#xff0c;主要介绍利用自监督学习进行降噪的。 Abstract 随着深度学习工具的兴起&#xff0c;越来越多的图像降噪模型对降噪的效果变得更好。然而&#xff0c;这种效果的巨大进步都严重依赖大量的高质量的数据对&#xff0c;这种对…

栈和队列——超详细

一、定义 1.栈的定义&#xff1a; 栈是只允许在一端进行插入或删除的线性表。首先栈是一种线性表&#xff0c;但限定这种线性表只能在某一端进行插入和删除操作。 栈顶&#xff08;Top&#xff09;:线性表允许进行插入删除的那一端&#xff1b;栈底 (Bottom) &#xff1a;固…

vs2022的下载及安装教程(Visual Studio 2022)

vs简介 Visual Studio在团队项目开发中使用非常多且功能强大&#xff0c;支持开发人员编写跨平台的应用程序;Microsoft Visual C 2022正式版(VC2022运行库)&#xff0c;具有程序框架自动生成&#xff0c;灵活方便的类管理&#xff0c;强大的代码编写等功能&#xff0c;可提供编…

开发程序员转金融finance、量化quant的解决方案(含CPA、CFA、CQF等证书要求)

开发程序员转金融finance、量化quant的解决方案&#xff08;含CPA、CFA、CQF等证书要求&#xff09; 文章目录 一、开发程序员转金融 & 量化二、金融行业相关证书&#xff08;CPA、CFA等&#xff09;三、量化分析相关证书&#xff08;CQF等&#xff09;1、量化行业准入门槛…

MES系统是怎么进行数据采集的?

在MES管理系统中&#xff0c;数据采集作为最基础也最为关键的一环&#xff0c;对于实现生产过程的透明化、可控好以及优化生产流程具有重要意义。 mes系统是怎么采集数据的? 一、PLC类数据采集&#xff1a;使用C#或C直接编程访问PLC(不需要花钱买组态软件或第三方软件) 二、…

论文学习——基于注意力预测策略的动态多目标优化合作差分进化论

论文题目&#xff1a;Cooperative Differential Evolution With an Attention-Based Prediction Strategy for Dynamic Multiobjective Optimization 基于注意力预测策略的动态多目标优化合作差分进化论&#xff08;Xiao-Fang Liu , Member, IEEE, Jun Zhang, Fellow, IEEE, a…

多模太与交叉注意力应用

要解决的问题 对同一特征点1从不同角度去拍&#xff0c;在我们拿到这些不同视觉的特征后&#xff0c;就可以知道如何从第一个位置到第二个位置&#xff0c;再到第三个位置 对于传统算法 下面很多点检测都是错 loftr当今解决办法 整体流程 具体步骤 卷积提取特征&#xff0c;…

DevOps本地搭建笔记(个人开发适用)

需求和背景 win11 wsl2 armbian(玩客云矿渣&#xff09;&#xff0c;构建个人cicd流水线&#xff0c;提高迭代效率。 具体步骤 基础设施准备 硬件准备&#xff1a;一台笔记本&#xff0c;用于开发和构建部署&#xff0c;一台服务器&#xff0c;用于日常服务运行。 笔记本…

ArcGIS学习(十四)OD分析

ArcGIS学习(十四)OD分析 1.上海市KFC与麦当劳的空间聚集度分析 本任务给大家带来的内容是网络节点关系分析。网络节点关系分析一般也叫OD分析。“O”指的是起点(ORIGIN),"D”指的是终点(DESTINATION),0D分析即为基于起点到终点的分析。 网络节点关系分析我们经常…

【机器学习300问】31、不平衡数据集如何进行机器学习?

一、什么是不平衡的数据集&#xff1f; &#xff08;1&#xff09;认识不平衡数据 假如你正在管理一个果园&#xff0c;这个果园里主要有两种水果——苹果和樱桃。如果苹果树有1000棵&#xff0c;而樱桃树只有10棵&#xff0c;那么在收集果园的果实时&#xff0c;你会得到大量…

缓存雪崩,穿透,击穿

为什么要设置缓存&#xff1a; 有海量并发的业务场景需要&#xff0c;大量的请求涌入关系型数据库&#xff0c;基于磁盘的IO读取效率低下&#xff0c;常用的mysql数据库不易进行扩展维护&#xff0c;容易造成数据库崩溃&#xff0c;从而相关业务崩溃&#xff0c;系统崩溃。 因此…

【测试】构建质量保证之路:编写测试用例的艺术

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;Linux ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 1. 确定测试目标&#xff1a; 2. 理解需求和规格&#xff1a; 3. 确定测试条件&#xff1a; 4. 编写测试用例&#xff1a; 结…

Linux常用命令之top监测

(/≧▽≦)/~┴┴ 嗨~我叫小奥 ✨✨✨ &#x1f440;&#x1f440;&#x1f440; 个人博客&#xff1a;小奥的博客 &#x1f44d;&#x1f44d;&#x1f44d;&#xff1a;个人CSDN ⭐️⭐️⭐️&#xff1a;传送门 &#x1f379; 本人24应届生一枚&#xff0c;技术和水平有限&am…

CSS 居中对齐 (水平居中 )

水平居中 1.文本居中对齐 内联元素&#xff08;给容器添加样式&#xff09; 限制条件&#xff1a;仅用于内联元素 display:inline 和 display: inline-block; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><…

Canal的入门操作记录

文章目录 1.主从数据库同步原理2.canal使用步骤2.1 开启binlog2.2 配置canalcanal.propertiesinstance.properties区别 3.创建Canal用户4.取信息5.SpringBoot整合 canal其实就是假装自己是从数据库&#xff0c;来监听主数据库的binlog得到数据的变化信息 canal 模拟 MySQL slav…