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

Java多线程--线程间的通信

文章目录

  • 一、线程间的通信
    • (1)为什么要处理线程间的通信
    • (2)等待唤醒机制
  • 二、案例
    • (1)案例
      • 1、创建线程
      • 2、解决线程安全问题
      • 3、等待
      • 4、唤醒
      • 5、同步监视器
    • (2)调用wait和notify需注意的细节
  • 三、wait与sleep的区别

一、线程间的通信

(1)为什么要处理线程间的通信

当我们需要多个线程共同完成一件任务,并且我们希望他们有规律的执行,那么多线程之间需要一些通信机制,可以协调它们的工作,以此实现多线程共同操作一份数据。(在同步的基础之上解决通信的问题)

比如:线程A用来生产包子的,线程B用来吃包子的,包子可以理解为同一资源,线程A与线程B处理的动作,一个是生产,一个是消费,此时B线程必须等到A线程完成后才能执行,那么线程A与线程B之间就需要线程通信,即—— 等待唤醒机制。

(2)等待唤醒机制

这是多个线程间的一种协作机制

谈到线程我们经常想到的是线程间的竞争(race),比如去争夺锁,但这并不是故事的全部,线程间也会有协作机制

在一个线程满足某个条件时,就进入等待状态(wait() / wait(time)), 等待其他线程执行完他们的指定代码过后再将其唤醒(notify());

或可以指定wait的时间,等时间到了自动唤醒;

在有多个线程进行等待时,如果需要,可以使用 notifyAll()来唤醒所有的等待线程。wait/notify 就是线程间的一种协作机制。

  1. wait:线程不再活动,不再参与调度,进入 wait set 中,因此不会浪费 CPU 资源,也不会去竞争锁了,这时的线程状态是 WAITING 或 TIMED_WAITING。它还要等着别的线程执行一个特别的动作,也即“通知(notify)”或者等待时间到,在这个对象上等待的线程从wait set 中释放出来,重新进入到调度队列(ready queue)中。
  2. notify:则选取所通知对象的 wait set 中的一个线程释放。
  3. notifyAll:则释放所通知对象的 wait set 上的全部线程。

🗳️注意:

被通知的线程被唤醒后也不一定能立即恢复执行,因为它当初中断的地方是在同步块内,而此刻它已经不持有锁,所以它需要再次尝试去获取锁(很可能面临其它线程的竞争),成功后才能在当初调用 wait 方法之后的地方恢复执行。

总结如下:

  • 如果能获取锁,线程就从 WAITING 状态变成 RUNNABLE(可运行) 状态;
  • 否则,线程就从 WAITING 状态又变成 BLOCKED(等待锁) 状态

二、案例

(1)案例

🌋案例描述:

使用两个线程打印 1-100。线程1, 线程2 交替打印。

🍰分析

1、创建线程

这里使用实现的方式创建线程。

class PrintNumber implements Runnable{//共享100private int number=1;@Overridepublic void run() {}
}

run方法里面写上逻辑代码:

class PrintNumber implements Runnable{//共享100private int number=1;@Overridepublic void run() {//打印数据while(true){if(number<=100){System.out.println(Thread.currentThread().getName()+":"+number);number++;}else{break;}}}
}

main方法中创建两个线程,如下:

public class PrintNumberTest {public static void main(String[] args) {//创建PrintNumber类的实例PrintNumber p=new PrintNumber();Thread t1=new Thread(p,"线程1");Thread t2=new Thread(p,"线程2");t1.start();t2.start();}
}

关于number的问题,需要考虑同步

if中加一个sleep,将问题放大。

目前的代码如下:

public class PrintNumberTest {public static void main(String[] args) {//创建PrintNumber类的实例PrintNumber p=new PrintNumber();Thread t1=new Thread(p,"线程1");Thread t2=new Thread(p,"线程2");t1.start();t2.start();}
}class PrintNumber implements Runnable{//共享100private int number=1;@Overridepublic void run() {//打印数据while(true){if(number<=100){try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+":"+number);number++;}else{break;}}}
}

输出:

image.png

可以看到打印出了错误信息。


2、解决线程安全问题

现在我们使用同步代码块来解决线程安全问题。

将操作number的代码用synchronized包裹起来,就是下面蓝色部分:

image.png

synchronized包裹的时候,不能包裹少了,那样会有安全问题。

若是包裹多了,串行的场景就会更多,导致效率变低。

所以,操作共享数据的代码,不能包裹多,也不能少。

🌱代码

package yuyi04.Communication;/*** ClassName: PrintNumberTest* Package: yuyi04.Communication* Description:*  使用两个线程打印 1-100。线程1, 线程2 交替打印。* @Author 雨翼轻尘* @Create 2024/2/2 0002 14:57*/
public class PrintNumberTest {public static void main(String[] args) {//创建PrintNumber类的实例PrintNumber p=new PrintNumber();Thread t1=new Thread(p,"线程1");Thread t2=new Thread(p,"线程2");t1.start();t2.start();}
}class PrintNumber implements Runnable{//共享100private int number=1;@Overridepublic void run() {//打印数据while(true){synchronized (this) {   //当前this表示PrintNumber的实例,即p,是唯一的if(number<=100){try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+":"+number);number++;}else{break;}}}}
}

🍺输出

image.png

可以看到现在的线程是安全的。


3、等待

紧接着需要考虑下一个问题,需要将两个线程交替打印

🎲如何实现交替?

比如线程1进入同步代码块,然后打印结束,出了同步代码块。

此时线程1需要进入阻塞状态,让线程2进入同步代码块输出执行,才能保证与线程1交替执行。

如何让线程1处于阻塞,这里需要使用一个方法wait(),让它处于等待状态。如下:

image.png

线程一旦执行wait()方法,就进入等待状态(阻塞),同时会释放对同步监视器的调用

wait()方法有一个异常需要处理一下:

image.png

注意,sleep()不会释放同步监视器,这一点需要注意。

有时候面试会问,wait()sleep()有什么区别?

这就是其中一个区别,sleep()不会释放对同步监视器的调用,而wait()会释放对同步监视器的调用。

🌱代码

public class PrintNumberTest {public static void main(String[] args) {//创建PrintNumber类的实例PrintNumber p=new PrintNumber();Thread t1=new Thread(p,"线程1");Thread t2=new Thread(p,"线程2");t1.start();t2.start();}
}class PrintNumber implements Runnable{//共享100private int number=1;@Overridepublic void run() {//打印数据while(true){synchronized (this) {   //当前this表示PrintNumber的实例,即p,是唯一的if(number<=100){try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+":"+number);number++;try {wait(); //线程一旦执行此方法,就进入等待状态(阻塞),同时会释放对同步监视器的调用} catch (InterruptedException e) {e.printStackTrace();}}else{break;}}}}
}

🍺输出

image.png

☕注意

一旦线程1进入同步代码块执行到wait(),就会释放对同步监视器的调用,然后开始等待操作。

线程2就可以拿着同步监视器进入同步代码块了,当线程2执行到wait(),它也开始等待。

所以两个线程都处于等待状态,只能输出两个数字,然后进入了阻塞状态


4、唤醒

🎲如何不一直等待下去呢?

Ctrl+P可以看到wait()方法还有带参的,可以设置等待时间,就是达到时间自动醒来。如下:

image.png

现在我们不使用这个了,因为想让它们交互输出,可以考虑唤醒线程。

线程1进入同步代码块执行到wait(),然后释放同步监视器,线程2进入同步代码块。

所以我们需要在线程2wait()之前把线程1唤醒

可以在这里写上notify(),如下:

image.png

🍰分析一下现在的情况:

线程1进入同步代码块,碰到了notify(),发现没有可以唤醒的线程,就继续往后执行。

然后线程1打印了“1”,接下来执行到wait(),开始等待,并且释放同步监视器。

线程2拿到锁,进入同步代码块,碰到了notify(),发现线程1在等待,就将线程1叫醒,虽然叫醒了,但是没有用,因为已经没有同步资源了。

线程2就拿着锁继续执行,即使sleep也不影响自动睡醒之后继续往后执行(sleep不会导致锁被释放),然后输出“2”。

线程2执行到wait(),就开始等待了,同时也释放同步监视器。

此时线程1是醒着的状态,从被wait()的地方继续往后执行,后边要是有代码的话还需要继续执行,然后拿着锁再次进入同步代码块,然后碰到notify(),将线程2叫醒。

🌱代码

package yuyi04.Communication;/*** ClassName: PrintNumberTest* Package: yuyi04.Communication* Description:*  使用两个线程打印 1-100。线程1, 线程2 交替打印。* @Author 雨翼轻尘* @Create 2024/2/2 0002 14:57*/
public class PrintNumberTest {public static void main(String[] args) {//创建PrintNumber类的实例PrintNumber p=new PrintNumber();Thread t1=new Thread(p,"线程1");Thread t2=new Thread(p,"线程2");t1.start();t2.start();}
}class PrintNumber implements Runnable{//共享100private int number=1;@Overridepublic void run() {//打印数据while(true){synchronized (this) {   //当前this表示PrintNumber的实例,即p,是唯一的notify();if(number<=100){try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+":"+number);number++;try {wait(); //线程一旦执行此方法,就进入等待状态(阻塞),同时会释放对同步监视器的调用} catch (InterruptedException e) {e.printStackTrace();}}else{break;}}}}
}

🍺输出(部分)

image.png

现在看到的就是交互的场景。


5、同步监视器

🗳️关于同步监视器

这里其实省略了this,如下:

image.png

wait同理:

notify();   //this.notify();
wait();		//this.wait();

凡是在方法当中,没有写是谁调用的,如果是非静态方法,那就少了this。

若是静态方法,那就是当前类。

这里的this必须是一样的吗?如下:

image.png

我们先来自己定义一个同步监视器,然后将obj放入:

image.png

🌱代码

public class PrintNumberTest {public static void main(String[] args) {//创建PrintNumber类的实例PrintNumber p=new PrintNumber();Thread t1=new Thread(p,"线程1");Thread t2=new Thread(p,"线程2");t1.start();t2.start();}
}class PrintNumber implements Runnable{//共享100private int number=1;Object obj=new Object();@Overridepublic void run() {//打印数据while(true){synchronized (obj) {   //obj是唯一的,线程安全this.notify();   //notify();if(number<=100){try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+":"+number);number++;try {wait(); //线程一旦执行此方法,就进入等待状态(阻塞),同时会释放对同步监视器的调用} catch (InterruptedException e) {e.printStackTrace();}}else{break;}}}}
}

🍺输出

image.png

会报一个异常IllegalMonitorStateException,这表示当前使用的同步监视器(即obj)和notify()wait()方法的调用者不一致。

所以,它们的调用者,必须是同步监视器。(这里也可以看出,notifywait方法必须要在同步代码块或同步方法中使用,只有这两个结构中才存在同步监视器,Lock里面没有同步监视器)


🚗处理

既然现在的同步监视器是obj,那么就用obj去调用notifywait方法即可。

如下:

image.png

🌱代码

package yuyi04.Communication;/*** ClassName: PrintNumberTest* Package: yuyi04.Communication* Description:*  使用两个线程打印 1-100。线程1, 线程2 交替打印。* @Author 雨翼轻尘* @Create 2024/2/2 0002 14:57*/
public class PrintNumberTest {public static void main(String[] args) {//创建PrintNumber类的实例PrintNumber p=new PrintNumber();Thread t1=new Thread(p,"线程1");Thread t2=new Thread(p,"线程2");t1.start();t2.start();}
}class PrintNumber implements Runnable{//共享100private int number=1;Object obj=new Object();@Overridepublic void run() {//打印数据while(true){synchronized (obj) {   //obj是唯一的,线程安全obj.notify();   //notify();if(number<=100){try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+":"+number);number++;try {obj.wait(); //线程一旦执行此方法,就进入等待状态(阻塞),同时会释放对同步监视器的调用} catch (InterruptedException e) {e.printStackTrace();}}else{break;}}}}
}

🍺输出(部分)

image.png

notifywait方法的调用者必须是“同步监视器”。

(2)调用wait和notify需注意的细节

上述案例涉及到三个方法的使用:

  • wait():线程一旦执行此方法,就进入等待状态。同时,会释放对同步监视器的调用
  • notify():一旦执行此方法,就会唤醒被wait()的线程中优先级最高的那一个线程。(如果被wait()的多个线程的优先级相同,则随机唤醒一个)。被唤醒的线程从当初被wait的位置继续执行。
  • notifyAll():一旦执行此方法,就会唤醒所有被wait的线程

🗳️注意点

  • 此三个方法的使用必须是在同步代码块或同步方法(即synchronized结构)。(超纲:Lock需要配合Condition实现线程间的通信,方式更加灵活)
  • 此三个方法的调用者,必须是同步监视器。否则,会报IllegalMonitorStateException异常。
  • 此三个方法声明在Object类中。(当初说同步监视器的时候,说到“任何一个对象都可以来充当同步监视器”,那么就意味着任何一个对象都应该有能力去调用这几个方法,这几个方法必定是定义在Object类里面的)

image.png


☕调用waitnotify需注意的细节总结

1、wait方法与notify方法必须要由同一个锁对象调用

因为:对应的锁对象可以通过notify唤醒使用同一个锁对象调用的wait方法后的线程。

2、wait方法与notify方法是属于Object类的方法的。

因为:锁对象可以是任意对象,而任意对象的所属类都是继承了Object类的。

3、wait方法与notify方法必须要在同步代码块或者是同步函数中使用。

因为:必须要通过锁对象调用这2个方法。否则会报java.lang.IllegalMonitorStateException异常。

三、wait与sleep的区别

🎲wait()sleep()的区别?(常见面试题)

相同点:一旦执行,都会使得当前线程结束执行状态,进入阻塞状态

不同点

  • 声明的位置(定义方法所属的类)
    • wait():声明在Object类中。
    • sleep():声明在Thread类中,静态的。
  • 使用的场景不同(使用范围不同)
    • wait()只能使用在同步代码块或同步方法中
    • sleep()可以在任何需要使用的场景
  • 都在同步结构(同步代码块或同步方法)中使用的时候,是否释放同步监视器的操作不同
    • wait():一旦执行,会释放同步监视器
    • sleep():一旦执行,不会释放同步监视器
  • 结束阻塞的方式(结束等待的方式不同)
    • wait()到达指定时间自动结束阻塞无限等待直到被notify/notifyAll唤醒,结束阻塞。
    • sleep()到达指定时间自动结束阻塞

相关文章:

Java多线程--线程间的通信

文章目录 一、线程间的通信&#xff08;1&#xff09;为什么要处理线程间的通信&#xff08;2&#xff09;等待唤醒机制 二、案例&#xff08;1&#xff09;案例1、创建线程2、解决线程安全问题3、等待4、唤醒5、同步监视器 &#xff08;2&#xff09;调用wait和notify需注意的…...

vue + element 页面滚动计算百分比 + 节流函数

html&#xff1a; <el-progress :percentage"scrollValue"></el-progress> js&#xff1a; data() {return {scrollValue: 0,} }, mounted() {window.addEventListener(scroll, this.handleScroll) // 监听页面滚动 }, beforeDestroy() {window.remov…...

【笔记】React Native实战练习(仿网易云游戏网页移动端)

/** * 如果系统看一遍RN相关官方文档&#xff0c;可能很快就忘记了。一味看文档也很枯燥无味&#xff0c; * 于是大概看了关键文档后&#xff0c;想着直接开发一个Demo出来&#xff0c;边学边写&#xff0c;对往后工作 * 开发衔接上能够更顺。这期间肯定会遇到各种各样的问题&a…...

Android SystemUI 介绍

目录 一、什么是SystemUI 二、SystemUI应用源码 三、学习 SystemUI 的核心组件 四、修改状态与导航栏测试 本篇文章&#xff0c;主要科普的是Android SystemUI &#xff0c; 下一篇文章我们将介绍如何把Android SystemUI 应用转成Android Studio 工程项目。 一、什么是Syst…...

2024美赛数学建模A题思路分析 - 资源可用性和性别比例

1 赛题 问题A&#xff1a;资源可用性和性别比例 虽然一些动物物种存在于通常的雄性或雌性性别之外&#xff0c;但大多数物种实质上是雄性或雌性。虽然许多物种在出生时的性别比例为1&#xff1a;1&#xff0c;但其他物种的性别比例并不均匀。这被称为适应性性别比例的变化。例…...

2024年数学建模美赛C题(预测 Wordle)——思路、程序总结分享

1: 问题描述与要求 《纽约时报》要求您对本文件中的结果进行分析&#xff0c;以回答几个问题。 问题1&#xff1a;报告结果的数量每天都在变化。开发一个模型来解释这种变化&#xff0c;并使用您的模型为2023年3月1日报告的结果数量创建一个预测区间。这个词的任何属性是否会…...

TryHackMe-File Inclusion练习

本文相关的TryHackMe实验房间链接&#xff1a;TryHackMe | Why Subscribe 路径遍历(目录遍历) LocationDescription/etc/issue包含要在登录提示之前打印的消息或系统标识。/etc/profile控制系统范围的默认变量&#xff0c;例如导出&#xff08;Export&#xff09;变量、文件创…...

Leetcode 《面试经典150题》169. 多数元素

题目 给定一个大小为 n 的数组 nums &#xff0c;返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。 你可以假设数组是非空的&#xff0c;并且给定的数组总是存在多数元素。 示例 1&#xff1a; 输入&#xff1a;nums [3,2,3] 输出&#xff1a;3示…...

百度输入法往选字框里强塞广告

关注卢松松&#xff0c;会经常给你分享一些我的经验和观点。 国内几乎100%的输入法都有广告&#xff0c;只是你们没发现而已&#xff01;&#xff01;&#xff01; 百度输入法居然在输入法键盘上推送广告&#xff0c;近日&#xff0c;博主阑夕 表示&#xff0c;V2EX论坛上有…...

分享一个Qt使用的模块间通信类

需求&#xff1a; 不同线程&#xff0c;或者同一线程的不同类之间通信&#xff0c;按照Qt的机制&#xff0c;定义一个信号&#xff0c;一个槽&#xff0c;然后绑定。以两个类A,B为例&#xff0c;A触发一个信号&#xff0c;B执行一个槽&#xff0c;在定义好信号和槽之后&#x…...

工作七年,对消息推送使用的一些经验和总结

前言&#xff1a;不管是APP还是WEB端都离不开消息推送&#xff0c;尤其是APP端&#xff0c;push消息&#xff0c;小信箱消息&#xff1b;WEB端的代办消息等。因在项目中多次使用消息推送且也是很多项目必不可少的组成部分&#xff0c;故此总结下供自己参考。 一、什么是消息推…...

计网——应用层

应用层 应用层协议原理 网络应用的体系结构 客户-服务器&#xff08;C/S&#xff09;体系结构 对等体&#xff08;P2P&#xff09;体系结构 C/S和P2P体系结构的混合体 客户-服务器&#xff08;C/S&#xff09;体系结构 服务器 服务器是一台一直运行的主机&#xff0c;需…...

算法面试八股文『 基础知识篇 』

博客介绍 近期在准备算法面试&#xff0c;网上信息杂乱不规整&#xff0c;出于强迫症就自己整理了算法面试常出现的考题。独乐乐不如众乐乐&#xff0c;与其奖励自己&#xff0c;不如大家一起嗨。以下整理的内容可能有不足之处&#xff0c;欢迎大佬一起讨论。 PS&#xff1a;…...

docker-学习-4

docker学习第四天 docker学习第四天1. 回顾1.1. 容器的网络类型1.2. 容器的本质1.3. 数据的持久化1.4. 看有哪些卷1.5. 看卷的详细信息 2. 如何做多台宿主机里的多个容器之间的数据共享2.1. 概念2.2. 搭NFS服务器实现多个容器之间的数据共享的详细步骤2.3. 如果是多台机器&…...

el-upload子组件上传多张图片(上传为files或base64url)

场景&#xff1a; 在表单页&#xff0c;有图片需要上传&#xff0c;表单的操作行按钮中有上传按钮&#xff0c;点击上传按钮。 弹出el-dialog进行图片的上传&#xff0c;可以上传多张图片。 由于多个表单页都有上传多张图片的操作&#xff0c;因此将上传多图的el-upload定义…...

2024美赛数学建模C题思路源码——网球选手的动量

这题挺有意思,没具体看比赛情况,打过比赛的人应该都知道险胜局(第二局、第五局逆转局)最影响心态的,导致第3、5局输了 模型结果需要证明这样的现象 赛题目的 赛题目的:分析网球球员的表现 问题一.球员在比赛特定时间表现力 问题分析 excel数据:每个时间段有16场比赛,…...

金三银四_程序员怎么写简历_写简历网站

你们在制作简历时,是不是基本只关注两件事:简历模板,还有基本信息的填写。 当你再次坐下来更新你的简历时,可能会发现自己不自觉地选择了那个“看起来最好看的模板”,填写基本信息,却没有深入思考如何使简历更具吸引力。这其实是一个普遍现象:许多求职者仍停留在传统简历…...

echarts条形图添加滚动条

效果展示: 测试数据: taskList:[{majorDeptName:测试,finishCount:54,notFinishCount:21}, {majorDeptName:测试,finishCount:54,notFinishCount:21}, {majorDeptName:测试,finishCount:54,notFinishCount:21}, {majorDeptName:测试,finishCount:54,notFinishCount:21}, {maj…...

Java 使用Soap方式调用WebService接口

pom文件依赖 <dependencies><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.13.0</version></dependency><!-- https://mvnrepository.com/artif…...

2024美赛数学建模所有题目思路分析

美赛思路已更新&#xff0c;关注后可以获取更多思路。并且领取资料 C题思路 首先&#xff0c;我们要理解势头是什么。简单来说&#xff0c;势头是一方在比赛中因一系列事件而获得的动力或优势。在网球中&#xff0c;这可能意味着连续赢得几个球&#xff0c;或是在比赛的某个关…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

高频面试之3Zookeeper

高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个&#xff1f;3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制&#xff08;过半机制&#xff0…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业

6月9日&#xff0c;国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解&#xff0c;“超级…...

cf2117E

原题链接&#xff1a;https://codeforces.com/contest/2117/problem/E 题目背景&#xff1a; 给定两个数组a,b&#xff0c;可以执行多次以下操作&#xff1a;选择 i (1 < i < n - 1)&#xff0c;并设置 或&#xff0c;也可以在执行上述操作前执行一次删除任意 和 。求…...

linux 错误码总结

1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

基于Docker Compose部署Java微服务项目

一. 创建根项目 根项目&#xff08;父项目&#xff09;主要用于依赖管理 一些需要注意的点&#xff1a; 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件&#xff0c;否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)

文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

重启Eureka集群中的节点,对已经注册的服务有什么影响

先看答案&#xff0c;如果正确地操作&#xff0c;重启Eureka集群中的节点&#xff0c;对已经注册的服务影响非常小&#xff0c;甚至可以做到无感知。 但如果操作不当&#xff0c;可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...

Linux离线(zip方式)安装docker

目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1&#xff1a;修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本&#xff1a;CentOS 7 64位 内核版本&#xff1a;3.10.0 相关命令&#xff1a; uname -rcat /etc/os-rele…...