当前位置: 首页 > 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坐标…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的&#xff0c;根据Excel列的需求预估的工时直接打骨折&#xff0c;不要问我为什么&#xff0c;主要…...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置&#xff0c;使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

vue3 定时器-定义全局方法 vue+ts

1.创建ts文件 路径&#xff1a;src/utils/timer.ts 完整代码&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

什么是EULA和DPA

文章目录 EULA&#xff08;End User License Agreement&#xff09;DPA&#xff08;Data Protection Agreement&#xff09;一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA&#xff08;End User License Agreement&#xff09; 定义&#xff1a; EULA即…...

前端开发面试题总结-JavaScript篇(一)

文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包&#xff08;Closure&#xff09;&#xff1f;闭包有什么应用场景和潜在问题&#xff1f;2.解释 JavaScript 的作用域链&#xff08;Scope Chain&#xff09; 二、原型与继承3.原型链是什么&#xff1f;如何实现继承&a…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战

在现代战争中&#xff0c;电磁频谱已成为继陆、海、空、天之后的 “第五维战场”&#xff0c;雷达作为电磁频谱领域的关键装备&#xff0c;其干扰与抗干扰能力的较量&#xff0c;直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器&#xff0c;凭借数字射…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...