Java【多线程】wait和notify

news2024/11/29 2:44:33

目录

wait / notify


由于线程之间是抢占式执⾏的, 因此线程之间执⾏的先后顺序难以预知.
但是实际开发中有时候我们希望合理的协调多个线程之间的执⾏先后顺序.
wait / notify

等待/通知

协调线程之间的执行逻辑的顺序的

可以让后执行的逻辑等待先执行的逻辑

虽然无法直接干预调度器的调度顺序

但是可以让后执行的逻辑(线程)等待,等待到先执行的逻辑跑完了

通知一下当前线程让他执行

join也是等

jion是等另一个线程彻底执行完,才继续走

wait是等到另一个线程执行notify,才继续走(不需要另一个线程也执行完)

锁的等待是不受控制的

某个线程的代码执行到加锁的逻辑不一定触发等待

不确定其他线程是否是“加锁”状态


当多个线程竞争到一把锁的时候

获取到锁的线程如果释放了,

因为随机调度不确定其他哪个线程拿到锁

操作系统的调度是随机的

其他线程的调度都属于在锁上阻塞等待,是阻塞状态

当前这个释放锁的线程,是就绪状态

这个线程有很大的概论能够再次拿到这个锁

这样的行为称之为“线程饿死”

把每个线程想象成鸟宝宝

cpu就是 鸟妈妈

鸟妈妈喂虫给鸟宝宝吃

一直捞不着cpu去执行就饿死了

当拿到锁的线程发现要执行任务的时候,时机不够成熟就使用wait阻塞等待

wait和notify都是Object的方法

Java中的任意对象都提供了wait和notify

public static void main(String[] args) throws InterruptedException {
  Object object = new Object();
  synchronized (object) {
    System.out.println("等待中");
    object.wait();
    System.out.println("等待结束");
  }
}

Object.wait();第一件事情,就是先释放Object对象对应的锁

能够释放锁的前提是,Object对象应该处于加锁状态才能释放

得先加上锁,才能谈释放

为啥wait要先释放锁呢

wait这个等待,最关键的一点,要先释放锁,给其他线程获取锁的机会

synchronized(object) {//加锁操作
    object.wait();
    //代码进入wait,就会先释放锁,并且阻塞等待
    //如果其他线程做完了必要的工作,调用notify唤醒这个wait线程
    //wait就会解除阻塞,重新获取到锁,继续执行并返回
}
    

要求synchronized的锁对象必须和wait的对象是同一个


scanner.next();等待io进入的阻塞

此处的next就是一个带有阻塞的操作

等待用户在控制台输入

locker.notify();

 这里同样也是需要先拿到锁,再进行notify(属于是java中给出的限制)

wait操作必须要搭配锁来进行,wait会先释放锁

notify操作,原则上来说,不涉及加锁解锁操作

在java中,也强制要求notify搭配synchronized

这4处必须是相同的对象

wait和notify是针对同一个对象,才能生效

这个相同的对象,这两线程沟通的桥梁

如果是两个不同的对象则没有任何相互的影响和作用

必须要确保,notify的执行要在wait之后

先wait后notify才有作用

如果先notify,后wait此时wait无法被唤醒

notify的这个线程也没有副作用(notify一个没有wait的对象,不会报错)

没有副作用指的是,线程自身没有抛出异常/其他报错

如果有多个线程在同一个对象上wait

进行notify的时候是随机唤醒其中的一个线程

一次notify唤醒一个wait


notifyAll一次唤醒所有wait线程

synchronized (locker) {
    locker.notifyAll();
}

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

虽然同时唤醒了t1和t2

由于wait唤醒之后要重新加锁

其中某个线程先加上锁,开始执行

另一个线程因为加锁失败再次阻塞等待

等待先走的线程解锁了,后走的线程才能加上锁继续执行


wait和join类似

也是提供了“死等”版本和“超时时间”版本

locker.wait(1000);

wait引入超时时间之后直观看起来和sleep很像

wait有等待时间

sleep也有等待时间

wait可以使用notify提前唤醒

sleep可以使用interrupt提前唤醒

wait和sleep最主要的区别在于针对锁的操作

1.wait必须要搭配锁,先加锁,才能用wait,sleep不需要

2.如果都是在synchronized内部使用,wait会释放锁,sleep不会释放锁

synchronized(locker){
    Thread.sleep(1000);
}

抱着锁睡

其他线程也是没法获取到这个锁的

Interrupt其实本身的作用是通知线程终止

3.wait是Object的方法sleep是Thread的静态方法

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

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

相关文章

缓存框架JetCache源码解析-缓存定时刷新

作为一个缓存框架,JetCache支持多级缓存,也就是本地缓存和远程缓存,但是不管是使用着两者中的哪一个或者两者都进行使用,缓存的实时性一直都是我们需要考虑的问题,通常我们为了尽可能地保证缓存的实时性,都…

word取消自动单词首字母大写

情况说明:在word输入单词后首字母会自动变成大写 (1)点击菜单栏文件 (2)点击“更多”——>“选项” (3)点击“校对”——>“自动更正选项” (4)取消“句首字母大写…

WPF样式详解:行内样式、模板样式和页面样式的全方位分析

Windows Presentation Foundation (WPF) 是微软推出的一种用于构建桌面应用程序的UI框架。WPF 提供了强大的样式和模板机制,允许开发人员以声明的方式定义和复用UI元素的视觉外观。本文将深入探讨WPF的行内样式、模板样式和页面样式,帮助您在实际开发中更…

大数据linux操作系统

第一关:Linux的初体验 答案: cd / ls -a / (里面有空格要注意) 第二关:Linux的常用命令 答案: touch newfile mkdir newdir cp newfile newdir/newfileCpy 第三关:Linux查询命令帮助语句…

我在自动化测试方面犯过的3个大错误

每个人都会犯错误,但不管错误看起来有多糟糕,你都可以恢复过来,更重要的是,从错误中学习。 在软件开发过程的任何领域,从编码到测试,我们都会时不时地犯一些错误。通常,这些错误都很小&#xf…

Linux kernel 堆溢出利用方法

前言 本文还是用一道例题来讲解几种内核堆利用方法,内核堆利用手段比较多,可能会分三期左右写。进行内核堆利用前,可以先了解一下内核堆的基本概念,当然更好去找一些详细的内核堆的基础知识。 概述 Linux kernel 将内存分为 页…

Leetcode 字符串解码

该代码的算法思想可以分为以下几个步骤: 1. 使用栈来处理嵌套结构: 我们需要处理像 k[encoded_string] 这种格式,其中的 encoded_string 可能是嵌套的,即像 3[a2[c]] 这样的输入。因此,我们可以借助 栈(S…

音视频基础知识分享

音视频基础知识分享 RKMedia的各个组件及其交互 首先上图: 考虑到公司业务主要是相机,所以,主要去关注图像数据流,对于音频数据流直接忽略。 图像数据流向: Camera Sensor将光信号转换成电信号(Raw数据&…

【大模型】AI视频课程制作工具开发

1. 需求信息 1.1 需求背景 讲师们在制作视频的过程中,发现录制课程比较麻烦,要保证环境安静,保证录制过程不出错,很容易反复重复录制,为了解决重复录制的工作量,想通过 ai 课程制作工具,来解决…

Rust引用与C++取地址、引用的区别(C++引用、Rust解引用、C++指针)

文章目录 Rust引用与C取地址和引用的比较一、内存安全与管理Rust的内存安全机制C的内存管理 二、引用和取地址Rust的引用C的引用和取地址 三、代码示例比较修改数据的安全性Rust示例C示例 四、结论 Rust引用与C取地址和引用的比较 在程序设计语言的世界里,Rust和C都…

【C++】string类(接口使用详解 下)

我们接着【C】string类(接口使用详解 上)-CSDN博客 继续介绍string的使用。 1.string类对象的修改操作 我们就说一下用的比较多的接口。 1.1 operator 这个接口可以尾插一个字符,或者一个字符串,或者一个对象。 string s1(&qu…

Java—类和对象习题讲解

如果您觉得这篇文章对您有帮助的话 欢迎您一键三连,小编尽全力做到更好 欢迎您分享给更多人哦 目录 习题一: 习题二: 习题三:.import static 能够导入一些静态方法 习题四: 习题五: 习题六&#xff1…

[LeetCode] 415.字符串相加

给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和并同样以字符串形式返回。 你不能使用任何內建的用于处理大整数的库(比如 BigInteger), 也不能直接将输入的字符串转换为整数形式。 示例 1: 输入&#xff…

SHELL脚本之数组介绍

shell数组 一.数组介绍 一段连续的内存空间,根据需要可以存多个数据。 变量定义:从内存中申请一段空间,用来存储数据。 如果同一种类型的数据,每一个数据都定义一个变量,当机器对这些变量进行寻址的时候&#xff0…

【Neo4j】- 轻松入门图数据库

文章目录 前言-场景一、Neo4j概述二、软件安装部署1.软件下载2.软件部署3.软件使用4.语法学习 总结 前言-场景 这里用大家都了解的关系数据与图数据据库对比着说,更加方便大家理解图数据库的作用 图形数据库和关系数据库均存储信息并表示数据之间的关系。但是,关系…

Aspose.PDF功能演示:使用 JavaScript 从 PDF 中提取文本

在数据提取、业务文档自动化和文本挖掘方面,使用 JavaScript 从PDF中提取文本非常有用。它允许开发人员自动执行从 PDF 收集信息的过程,从而显著提高处理大量文档的生产力和效率。在这篇博文中,我们将学习如何使用 JavaScript 从 PDF 中提取文…

功能安全实战系列-软件FEMA分析与组件鉴定

本文框架 前言1. 功能安全分析1.1 Why1.2 What?1.3 How?1.3.1 分析范围确定1.3.2 失效模式分析1.3.3 安全措施制定1.3.4 确认是否满足功能安全目标2. 软件组件鉴定2.1 Why2.2 How?前言 在本系列笔者将结合工作中对功能安全实战部分的开发经验进一步介绍常用,包括Memory(Fl…

stable diffusion 大模型及lora等下载安装使用教程及项目目录说明

首先说明,stable diffusion大模型并非controlNet中使用的模型,这两者有根本的区别,请仔细区分。 国内可下载模型的站点: 哩布哩布 https://liblib.ai 模型分为几类,下载的时候看清楚类型,都会标记在模型…

Python编程探索:从基础语法到循环结构实践(下)

文章目录 前言🍷四、 字符串拼接:连接多个字符串🍸4.1 使用 操作符进行字符串拼接🍸4.2 使用 join() 方法进行字符串拼接🍸4.3 使用 format() 方法进行格式化拼接🍸4.4 使用 f-string(格式化字…

【Linux】进程池

目录 进程池 进程池的概念: 手搓进程池: 1、创建信道和子进程 2、通过channel控制子进程 3、回收管道和子进程 进程池 进程池的概念: 定义一个池子,在里面放上固定数量的进程,有需求来了,就拿一个池中…