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

C# 关于多线程同步不同实现方式

栏目总目录


AutoResetEvent

class MainClass
{// the array of consumer threadsprivate static List<Thread> consumers = new List<Thread> ();// the task queueprivate static Queue<Action> tasks = new Queue<Action>();// the synchronisation object for locking the task queueprivate static readonly object queueLock = new object();// this wait handle notifies consumers of a new taskprivate static EventWaitHandle newTaskAvailable = new AutoResetEvent (false);// the synchronisation object for locking the console colorprivate static readonly object consoleLock = new object();// enqueue a new taskprivate static void EnqueueTask (Action task){lock (queueLock){tasks.Enqueue (task);}newTaskAvailable.Set();}// thread work method for consumersprivate static void DoWork(ConsoleColor color){while (true){// get a new taskAction task = null;lock (queueLock) {if (tasks.Count > 0){task = tasks.Dequeue ();}}if (task != null){// set console to this task's colorlock (consoleLock){Console.ForegroundColor = color;}// execute tasktask ();}else// queue is empty - wait for a new tasknewTaskAvailable.WaitOne();}}public static void Main (string[] args){// set up 3 consumersconsumers.Add(new Thread ( () => { DoWork(ConsoleColor.Red); }));consumers.Add(new Thread ( () => { DoWork(ConsoleColor.Green); }));consumers.Add(new Thread ( () => { DoWork(ConsoleColor.Blue); }));// start all consumersconsumers.ForEach ( (t) => { t.Start (); });while (true){// add a new taskRandom r = new Random();EnqueueTask ( () => {// the task is to write a random number to the consoleint number = r.Next (10);Console.Write (number);});// random sleep to simulate workloadThread.Sleep (r.Next (1000)); }}
}

这段代码实现了一个简单的生产者-消费者模型,其中有一个生产者(在Main方法中模拟)和多个消费者(在这个例子中是三个线程,每个线程代表一个消费者)。这个模型通过共享的任务队列来同步生产者和消费者之间的工作。

代码功能概述:

  1. 任务队列:使用Queue<Action>来存储待执行的任务(在这里,任务被定义为无参数的Action委托)。

  2. 生产者:在Main方法中,通过无限循环不断生成新的任务(打印一个随机数到控制台),并将这些任务添加到任务队列中。生产者每生成一个任务后,会随机等待一段时间(模拟工作负载)。

  3. 消费者:有三个消费者线程,每个线程都执行相同的DoWork方法,但传入不同的控制台颜色参数。消费者线程从任务队列中取出任务并执行(即调用任务委托),同时在执行任务前将控制台颜色设置为自己的颜色。如果任务队列为空,消费者线程将等待(通过newTaskAvailable.WaitOne()),直到生产者通知它们有新的任务可用。

  4. 同步机制

    • 使用queueLock对象来同步对任务队列的访问,确保在添加或移除任务时不会发生数据竞争。
    • 使用newTaskAvailableAutoResetEvent)来通知消费者有新的任务可用。当生产者将任务放入队列后,它会设置这个事件,从而唤醒一个等待的消费者线程。
    • 使用consoleLock对象来同步对控制台颜色的设置,防止多个消费者线程同时更改控制台颜色。

代码执行流程:

  1. 初始化:在Main方法中,创建并启动三个消费者线程,每个线程都执行DoWork方法,但传入不同的控制台颜色参数。

  2. 生产者循环Main方法进入一个无限循环,不断生成新的任务(打印随机数到控制台),并将这些任务添加到任务队列中。每生成一个任务后,生产者会随机等待一段时间。

  3. 消费者工作:每个消费者线程都进入一个无限循环,尝试从任务队列中取出任务。如果队列不为空,它们将设置控制台颜色为自己的颜色,执行任务(打印随机数),然后再次尝试从队列中取出任务。如果队列为空,它们将等待newTaskAvailable事件被设置,这通常发生在生产者将新任务添加到队列后。

  4. 持续运行:这个过程将持续进行,因为生产者和消费者都运行在无限循环中。在实际应用中,您可能需要添加某种退出机制来优雅地停止程序。

ManualResetEvent

class MainClass
{// the array of consumer threadsprivate static List<Thread> consumers = new List<Thread> ();// the task queueprivate static Queue<Action> tasks = new Queue<Action>();// the synchronisation object for locking the task queueprivate static readonly object queueLock = new object();// this wait handle notifies consumers of a new taskprivate static EventWaitHandle newTaskAvailable = new AutoResetEvent (false);// this wait handle pauses consumersprivate static EventWaitHandle pauseConsumers = new ManualResetEvent (true);// the synchronisation object for locking the console colorprivate static readonly object consoleLock = new object();// enqueue a new taskprivate static void EnqueueTask (Action task){lock (queueLock){tasks.Enqueue (task);}newTaskAvailable.Set();}// thread work method for consumersprivate static void DoWork(ConsoleColor color){while (true){// check if producer asked us to pausepauseConsumers.WaitOne ();// get a new taskAction task = null;lock (queueLock) {if (tasks.Count > 0){task = tasks.Dequeue ();}}if (task != null){// set console to this task's colorlock (consoleLock){Console.ForegroundColor = color;}// execute tasktask ();}else// queue is empty - wait for a new tasknewTaskAvailable.WaitOne();}}public static void Main (string[] args){// set up 3 consumersconsumers.Add(new Thread ( () => { DoWork(ConsoleColor.Red); }));consumers.Add(new Thread ( () => { DoWork(ConsoleColor.Green); }));consumers.Add(new Thread ( () => { DoWork(ConsoleColor.Blue); }));// start all consumersconsumers.ForEach ( (t) => { t.Start (); });bool consumersPaused = false;while (true){// add a new taskRandom r = new Random();EnqueueTask ( () => {// the task is to write a random number to the consoleint number = r.Next (10);Console.Write (number);});// random sleep to simulate workloadThread.Sleep (r.Next (1000)); // pressing any key pauses/unpauses the consumersif (Console.KeyAvailable){Console.Read ();if (consumersPaused){pauseConsumers.Set ();Console.WriteLine ("Consumers resumed");}else{pauseConsumers.Reset ();Console.WriteLine ("Consumers paused");}consumersPaused = !consumersPaused;}}}
}

这段代码实现了一个带有暂停/恢复功能的生产者-消费者模型,其中包含一个生产者(在Main方法中模拟)和三个消费者线程。这个模型通过共享的任务队列来同步生产者和消费者之间的工作,并且允许用户通过按键操作来暂停或恢复消费者的执行。

代码功能概述:

  1. 任务队列:使用Queue<Action>来存储待执行的任务。

  2. 同步机制

    • queueLock:用于同步对任务队列的访问,确保在添加或移除任务时不会发生数据竞争。
    • newTaskAvailableAutoResetEvent):当生产者将新任务添加到队列时,设置此事件以通知一个等待的消费者线程。
    • pauseConsumersManualResetEvent):允许生产者(或用户)暂停和恢复消费者的执行。
    • consoleLock:用于同步对控制台颜色的设置,防止多个消费者线程同时更改控制台颜色。
  3. 消费者线程:三个消费者线程分别执行DoWork方法,但传入不同的控制台颜色参数。消费者线程无限循环地等待新任务,如果任务队列中有任务,则取出任务并执行,同时设置控制台颜色为自己的颜色。如果任务队列为空,则等待newTaskAvailable事件被设置。此外,消费者还会检查pauseConsumers事件是否被设置,如果被设置,则暂停执行直到被重置。

  4. 生产者:在Main方法中模拟,不断生成新的任务(打印一个随机数到控制台)并添加到任务队列中。每生成一个任务后,生产者会随机等待一段时间(模拟工作负载)。此外,生产者还检查控制台是否有按键输入,如果有,则切换消费者的暂停/恢复状态。

代码执行流程:

  1. 初始化:创建并启动三个消费者线程,每个线程都执行DoWork方法,但传入不同的控制台颜色参数。

  2. 生产者循环Main方法进入一个无限循环,不断生成新的任务(打印随机数到控制台),并将这些任务添加到任务队列中。每生成一个任务后,生产者会随机等待一段时间。同时,生产者检查控制台是否有按键输入,并根据按键切换消费者的暂停/恢复状态。

  3. 消费者工作:每个消费者线程都进入一个无限循环,首先检查pauseConsumers事件是否被设置,如果被设置则等待。然后尝试从任务队列中取出任务,如果队列不为空,则设置控制台颜色并执行任务;如果队列为空,则等待newTaskAvailable事件被设置。

  4. 暂停/恢复:用户可以通过按任意键来切换消费者的暂停/恢复状态。如果消费者当前是暂停状态,则按键将唤醒它们并继续执行;如果消费者当前是运行状态,则按键将使它们暂停执行。

CountdownEvent

class MainClass
{// the array of consumer threadsprivate static List<Thread> consumers = new List<Thread> ();// the task queueprivate static Queue<Action> tasks = new Queue<Action>();// the synchronisation object for locking the task queueprivate static readonly object queueLock = new object();// this wait handle notifies consumers of a new taskprivate static EventWaitHandle newTaskAvailable = new AutoResetEvent (false);// the wait handle to quit consumersprivate static CountdownEvent quitConsumers = new CountdownEvent (3);// the flag to request that consumers quitprivate static bool quitRequested = false;// the synchronisation object for quitting consumersprivate static readonly object quitLock = new object ();// the synchronisation object for locking the console colorprivate static readonly object consoleLock = new object();// enqueue a new taskprivate static void EnqueueTask (Action task){lock (queueLock){tasks.Enqueue (task);}newTaskAvailable.Set();}// thread work method for consumersprivate static void DoWork(ConsoleColor color){while (true){// check if someone asked us to quitlock (quitLock){if (quitRequested){Console.WriteLine ("Consumer {0} is quitting", color);quitConsumers.Signal ();break;}}// get a new taskAction task = null;lock (queueLock) {if (tasks.Count > 0){task = tasks.Dequeue ();}}if (task != null){// set console to this task's colorlock (consoleLock){Console.ForegroundColor = color;}// execute tasktask ();}else// queue is empty - wait for a new tasknewTaskAvailable.WaitOne(1000);}}public static void Main (string[] args){// set up 3 consumersconsumers.Add(new Thread ( () => { DoWork(ConsoleColor.Red); }));consumers.Add(new Thread ( () => { DoWork(ConsoleColor.Green); }));consumers.Add(new Thread ( () => { DoWork(ConsoleColor.Blue); }));// start all consumersconsumers.ForEach ( (t) => { t.Start (); });int iterations = 0;while (true){// add a new taskRandom r = new Random();EnqueueTask ( () => {// the task is to write a random number to the consoleint number = r.Next (10);Console.Write (number);});// random sleep to simulate workloadThread.Sleep (r.Next (1000)); // quit after 10 iterationsif (iterations++ >= 10){// request consumer quitlock (quitLock){quitRequested = true;}// wait until all consumers have signalledquitConsumers.Wait ();Console.WriteLine ("All consumers have quit");break;}}}
}

这个代码实现了一个带有优雅退出机制的生产者-消费者模型。它创建了三个消费者线程,这些线程从共享的任务队列中取出并执行任务。与之前的代码相比,这个代码添加了以下主要功能和改进:

  1. 优雅退出机制

    • 引入了quitRequested标志和quitLock同步对象,用于控制消费者线程的退出请求。
    • 使用CountdownEventquitConsumers)来等待所有消费者线程都完成退出前的清理工作并发出信号。
    • 当生产者决定退出时,它会将quitRequested标志设置为true,并通过quitConsumers.Wait()等待所有消费者线程都调用quitConsumers.Signal()来确认它们已经准备好退出。
  2. 消费者线程的退出逻辑

    • 每个消费者线程在循环开始时都会检查quitRequested标志。如果设置为true,则消费者将打印一条退出消息,调用quitConsumers.Signal()来通知生产者它已准备好退出,并退出循环。
    • 注意,消费者在退出前会释放控制台颜色的锁(consoleLock),但在这个特定的例子中,由于退出是在没有任务可执行的空闲时间发生的,所以这一步实际上可能是多余的,因为退出时不会再次访问控制台颜色。
  3. 任务队列的轮询

    • 消费者在任务队列为空时会调用newTaskAvailable.WaitOne(1000),这是一个带超时的等待调用。这意味着如果1000毫秒内没有新任务到来,消费者将停止等待并再次检查退出条件。这有助于防止消费者线程在队列为空时永久挂起。
  4. 生产者的迭代次数限制

    • 生产者在一个循环中运行,但只执行有限次数的迭代(在这个例子中是10次)。每次迭代都会向任务队列中添加一个新任务,并在迭代之间随机等待一段时间以模拟工作负载。
    • 当达到迭代次数限制时,生产者会请求消费者退出,并等待所有消费者都准备好退出。
  5. 其他同步机制

    • 代码仍然使用queueLock来同步对任务队列的访问,以防止数据竞争。
    • consoleLock用于同步对控制台颜色的访问,以确保当多个消费者线程尝试同时更改控制台颜色时不会发生冲突。
  6. 代码执行流程

    • 程序初始化三个消费者线程,并将它们启动。
    • 生产者在一个循环中运行,每次迭代都向任务队列中添加一个新任务,并随机等待一段时间。
    • 当达到迭代次数限制时,生产者请求消费者退出,并等待它们确认。
    • 一旦所有消费者都确认退出,生产者将打印一条消息,并退出程序。

Barrier

class MainClass
{// wait handles to rendezvous threads  public static Barrier barrier = new Barrier(3, b => Console.WriteLine("All threads have reached the barrier."));// thread work method  public static void DoWork(){for (int i = 0; i < 5; i++){Console.Write(Thread.CurrentThread.ManagedThreadId + ": " + i + " ");// rendezvous with other threads  barrier.SignalAndWait();}}public static void Main(string[] args){// start three threads  new Thread(DoWork).Start();new Thread(DoWork).Start();new Thread(DoWork).Start();// Keep the main thread alive to prevent the program from exiting before the threads finish  Console.WriteLine("Press Enter to exit...");Console.ReadLine();}
}

代码功能概述:

  1. Barrier 初始化

    • MainClass 中,创建了一个 Barrier 实例 barrier,其构造函数接受两个参数:参与同步的线程数(这里是 3)和一个在每次所有线程都到达屏障时调用的委托(打印一条消息)。
  2. 线程工作方法

    • DoWork 方法是三个线程将执行的方法。每个线程都会进入一个循环,循环 5 次。
    • 在每次循环迭代中,线程都会打印其当前迭代次数和线程 ID,然后调用 barrier.SignalAndWait()
    • SignalAndWait 方法导致当前线程在屏障处等待,直到所有其他参与线程也都调用了 SignalAndWait。一旦所有线程都到达屏障,它们会同时继续执行,并且如果提供了,会执行构造函数中指定的委托(打印一条消息)。
  3. 主线程

    • 主线程启动了三个 DoWork 线程,并等待用户按下 Enter 键以继续执行。这是为了防止主线程在后台线程完成之前退出程序。

运行结果

  • 当所有三个线程都到达 barrier.SignalAndWait() 时,它们会同时停止执行,并等待彼此。
  • 一旦所有线程都到达屏障,它们会同时继续执行,并且控制台会打印出 “All threads have reached the barrier.”。
  • 这个过程会在每次循环迭代时重复,直到每个线程都完成了 5 次迭代。
  • 最后,用户按下 Enter 键后,程序退出。

相关文章:

C# 关于多线程同步不同实现方式

栏目总目录 AutoResetEvent class MainClass {// the array of consumer threadsprivate static List<Thread> consumers new List<Thread> ();// the task queueprivate static Queue<Action> tasks new Queue<Action>();// the synchronisation o…...

【人工智能学习笔记】4_2 深度学习基础之多层感知机

感知机概述 感知机是人工智能最早的模型,是一种有监督的算法,本质上是一个二分类问题,是神经网络和支持向量机的基础缺点:感知机智能解决单纯的线性问题 感知机的过程 多层感知机的层级结构 多层感知机的层级结构主要包括输入层、隐藏层和输出层、可以用于拟合非线性函数。…...

WPS2019如何打出各种横线

WPS2019如何打出各种横线 测试于WPS2019...

Vue获取后端重定向拼接的参数

前言 比如我们要重定向这样一个连接&#xff1a; http://192.168.2.189:8081?nameadmin springboot重定向&#xff1a; Vue获取&#xff1a; getParam(param) {var reg new RegExp("(^|&)" param "([^&]*)(&|$)");var r location.searc…...

vscode spring boot项目编辑yaml不自动提示补全如何解决

文章目录 properties能够自动弹出提示但是YAML文件就不会自动弹出提示ctrl空格不出提示的解决办法 properties能够自动弹出提示 但是YAML文件就不会自动弹出提示 只是不会自动弹出来而已&#xff0c;按ctrl空格即可解决 ctrl空格不出提示的解决办法 如果按ctrl空格没有用 …...

算法练习题19——leetcode141环形链表

题目描述 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置&a…...

基于人类反馈的强化学习概述

文章目录 RLHF 概述人类反馈数据的收集由于对齐标准难以通过形式化的优化目标进行建模,因此研究人员提出了基于人类反馈的强化学习(Reinforcement Learning from Human Feedback, RLHF),引入人类反馈对大语言模型的行为进行指导。我们将首先介绍基于人类反馈的强化学习的整…...

【SIT1463Q】带振铃抑制功能的CAN收发器,替代TJA1463

【SIT1463Q】带振铃抑制功能的CAN收发器&#xff0c;替代TJA1463 SIT1463Q核心亮点&#xff1a; 满足ISO11898-2:2016高速CAN规范的物理层要求和CiA601-4&#xff1a;2019 SIC规范要求。 支持高达8Mbps的数据速率。 更稳定的位时序&#xff0c;比特对称性增强&#xff0c;降低…...

CCF刷题计划——坐标变换(其二)(前缀和)

坐标变换&#xff08;其二&#xff09; 首先我按照一般的逻辑写出来&#xff0c;居然超时了&#xff1f;&#xff1f;&#xff1f; 之后想了想&#xff0c;还是觉得大有可为的&#xff0c;对拉伸前缀积&#xff0c;对旋转前缀和成功解决问题。 80分&#xff1a;超时 #inclu…...

游戏开发简述

《黑神话&#xff1a;悟空》爆红后&#xff0c;游戏开发一时成为热点。作为个人或小公司&#xff0c;能否进入游戏开发领域。从纯技术角度而言&#xff0c;并不是可望不可即&#xff1a; 另&#xff1a;学会了&#xff0c;哪怕自己干不成&#xff0c;招游戏开发的岗位也不少&am…...

最新前端开发VSCode高效实用插件推荐清单

在此进行总结归类工作中用到的比较实用的、有助于提升开发效率的VSCode插件。大家有其他的好插件推荐的也欢迎留言评论区哦&#x1f604; 基础增强 Chinese (Simplified) Language Pack: 提供中文界面。 Code Spell Checker: 检查代码中的拼写错误。 ESLint: 集成 ESLint&…...

分布式调度方案:Elastic-Job

文章目录 一、什么是分布式调度二、Elastic-Job 介绍三、Elastic-Job 实战3.1 环境搭建3.1.1 本地部署3.1.2 服务器部署3.1.3 Zookeeper 管控台界面 3.2 入门案例3.3 SpringBoot 集成 Elastic-Job3.4 任务分片&#xff08;★&#xff09;3.5 Dataflow 类型调度任务 一、什么是分…...

网络安全工程师(白帽子)企业级学习路线

第一阶段&#xff1a;安全基础&#xff08;入门&#xff09; 第二阶段&#xff1a;Web渗透&#xff08;初级网安工程师&#xff09; 第三阶段&#xff1a;进阶部分&#xff08;中级网络安全工程师&#xff09;...

数据结构详细解释

数据结构 1. 线性数据结构 数组&#xff08;Array&#xff09; 定义&#xff1a;数组是一种固定大小的、元素类型相同的线性数据结构。元素在内存中是连续存储的&#xff0c;可以通过索引直接访问。 特点&#xff1a; 支持常数时间的随机访问&#xff08;O(1)&#xff09;。…...

7.1图像平移

目录 实验原理 示例代码&#xff11; 运行结果&#xff11; 示例代码&#xff12; 运行结果&#xff12; 实验原理 OpenCV中&#xff0c;图像平移是一种基本的几何变换&#xff0c;指的是将图像中的每一个像素点沿着水平方向或垂直方向移动一定的距离。图像平移不改变图像…...

海外云手机是否适合运营TikTok?

随着科技的迅猛发展&#xff0c;海外云手机逐渐成为改变工作模式的重要工具。这种基于云端技术的虚拟手机&#xff0c;不仅提供了更加便捷、安全的使用体验&#xff0c;还在电商引流和海外社媒管理等领域展示了其巨大潜力。那么&#xff0c;海外云手机究竟能否有效用于运营TikT…...

IT 行业中常见的专业名称及其含义

API&#xff08;Application Programming Interface&#xff09; API 是应用程序编程接口&#xff0c;定义了不同软件系统之间如何互相通信的规则和方式。开发人员使用 API 将应用程序与外部服务集成&#xff0c;进行数据交换或调用外部功能。 IDE&#xff08;Integrated Deve…...

全球开店,Shopee东南亚入驻指南|用友BIP电商通引领电商出海新潮流

在全球化的浪潮中&#xff0c;东南亚市场以其蓬勃的发展态势成为中国企业出海的首选之地。得益于其语言、物流、仓储、距离及政策的友好性&#xff0c;东南亚市场已成为企业海外拓展的必争之地。作为东南亚领先的电商平台&#xff0c;Shopee以其庞大的用户基础和高度的用户活跃…...

java当中什么是NIO

Java中的NIO&#xff08;Non-blocking I/O&#xff09;即非阻塞I/O&#xff0c;是Java 1.4中引入的一种新的I/O API&#xff0c;用于替代传统的I/O&#xff08;即BIO, Blocking I/O&#xff09;。与传统的阻塞式I/O相比&#xff0c;NIO提供了更高效的I/O操作&#xff0c;特别是…...

【基础】Three.js 自定义几何体和复制几何体

通过自定义顶点数据&#xff0c;可以创建任意的几何体。像threejs的长方体BoxGeometry、球体SphereGeometry等几何体都是基于BufferGeometry类构建的&#xff0c;它表示一个没有任何形状的空几何体。 1. 自定义点模型 通过javascript 类型化数组 Float32Array创建一组xyz坐标…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…...

Web 架构之 CDN 加速原理与落地实践

文章目录 一、思维导图二、正文内容&#xff08;一&#xff09;CDN 基础概念1. 定义2. 组成部分 &#xff08;二&#xff09;CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 &#xff08;三&#xff09;CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 &#xf…...

Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信

文章目录 Linux C语言网络编程详细入门教程&#xff1a;如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket&#xff08;服务端和客户端都要&#xff09;2. 绑定本地地址和端口&#x…...

解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用

在工业制造领域&#xff0c;无损检测&#xff08;NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统&#xff0c;以非接触式光学麦克风技术为核心&#xff0c;打破传统检测瓶颈&#xff0c;为半导体、航空航天、汽车制造等行业提供了高灵敏…...

0x-3-Oracle 23 ai-sqlcl 25.1 集成安装-配置和优化

是不是受够了安装了oracle database之后sqlplus的简陋&#xff0c;无法删除无法上下翻页的苦恼。 可以安装readline和rlwrap插件的话&#xff0c;配置.bahs_profile后也能解决上下翻页这些&#xff0c;但是很多生产环境无法安装rpm包。 oracle提供了sqlcl免费许可&#xff0c…...

【WebSocket】SpringBoot项目中使用WebSocket

1. 导入坐标 如果springboot父工程没有加入websocket的起步依赖&#xff0c;添加它的坐标的时候需要带上版本号。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dep…...

Android写一个捕获全局异常的工具类

项目开发和实际运行过程中难免会遇到异常发生&#xff0c;系统提供了一个可以捕获全局异常的工具Uncaughtexceptionhandler&#xff0c;它是Thread的子类&#xff08;就是package java.lang;里线程的Thread&#xff09;。本文将利用它将设备信息、报错信息以及错误的发生时间都…...

React从基础入门到高级实战:React 实战项目 - 项目五:微前端与模块化架构

React 实战项目&#xff1a;微前端与模块化架构 欢迎来到 React 开发教程专栏 的第 30 篇&#xff01;在前 29 篇文章中&#xff0c;我们从 React 的基础概念逐步深入到高级技巧&#xff0c;涵盖了组件设计、状态管理、路由配置、性能优化和企业级应用等核心内容。这一次&…...

土建施工员考试:建筑施工技术重点知识有哪些?

《管理实务》是土建施工员考试中侧重实操应用与管理能力的科目&#xff0c;核心考查施工组织、质量安全、进度成本等现场管理要点。以下是结合考试大纲与高频考点整理的重点内容&#xff0c;附学习方向和应试技巧&#xff1a; 一、施工组织与进度管理 核心目标&#xff1a; 规…...

负载均衡器》》LVS、Nginx、HAproxy 区别

虚拟主机 先4&#xff0c;后7...