02多线程基础知识

目录

1. 线程与进程

进程(Process)

线程(Thread)

2. 并发和并行

并发(Concurrency)

并行(Parallelism)

3. CPU 调度

定义

类型

调度算法

上下文切换

4.线程间的状态流转

线程的主要状态

注意:

5.创建线程的方法

6.线程安全问题

7.线程间的通信

8.Lock对象的介绍和基本使用

Lock 接口的主要方法

Lock 接口的实现类

9.避免忙等待

使用Condition 对象

使用Timer


1. 线程与进程

进程(Process)
  • 定义:进程是操作系统进行资源分配和调度的基本单位。每个进程都有自己独立的虚拟地址空间、系统资源(如文件句柄、内存等)和一组系统状态信息。

  • 特点:

    • 独立性:每个进程都有自己的独立内存空间,不会直接影响其他进程。

    • 资源分配:进程拥有独立的系统资源,如文件描述符、内存等。

    • 生命周期:进程从创建到终止有一个完整的生命周期,包括创建、就绪、运行、阻塞和终止等状态。

线程(Thread)
  • 定义:线程是进程内的一个执行单元,是操作系统进行调度的基本单位。一个进程可以包含多个线程,这些线程共享进程的资源,但每个线程有自己的栈和程序计数器。

  • 特点:

    • 轻量级:相比于进程,线程的创建和切换开销较小。

    • 资源共享:同一进程内的线程共享进程的内存和其他资源。

    • 并发执行:多个线程可以并发执行,提高程序的响应性和资源利用率。

2. 并发和并行

并发(Concurrency)
  • 定义:并发是指多个任务在同一时间段内交错执行,但不一定同时执行。操作系统通过时间片调度在多个任务之间快速切换,使这些任务看起来像是同时执行的。

  • 特点:

    • 时间片调度:操作系统为每个任务分配一个时间片,在这段时间内任务可以执行。

    • 上下文切换:任务之间通过上下文切换来交替执行。

    • 适用场景:适用于 I/O 密集型任务,如网络请求、文件读写等。

并行(Parallelism)
  • 定义:并行是指多个任务在同一时刻真正同时执行。这通常需要多核处理器的支持,每个核心可以同时执行一个任务。

  • 特点:

    • 多核处理器:并行计算依赖于多核处理器,每个核心可以独立执行任务。

    • 提高计算效率:并行计算可以显著提高计算密集型任务的执行效率。

    • 适用场景:适用于计算密集型任务,如矩阵运算、图像处理等。

3. CPU 调度

定义
  • CPU 调度:CPU 调度是操作系统的核心功能之一,负责在多个进程或线程之间分配 CPU 时间。调度器根据一定的算法选择下一个执行的进程或线程,确保系统的高效运行。

类型
  • 长期调度(Job Scheduler):负责决定哪些进程可以进入内存并准备执行。通常在进程创建时进行。

  • 中期调度(Swapper):负责在内存和磁盘之间交换进程,以释放内存空间。

  • 短期调度(CPU Scheduler):负责在就绪队列中的进程或线程之间分配 CPU 时间。是最常见和最重要的调度类型。

调度算法
  • 先来先服务(First-Come, First-Served, FCFS):按照进程到达的顺序进行调度。

  • 短作业优先(Shortest Job Next, SJN):优先调度预计运行时间最短的进程。

  • 优先级调度(Priority Scheduling):根据进程的优先级进行调度,优先级高的进程优先执行。

  • 轮转法(Round Robin, RR):每个进程或线程分配一个固定的时间片,时间片结束后切换到下一个进程或线程。

  • 多级反馈队列(Multilevel Feedback Queue):结合多种调度策略,根据进程的行为动态调整其优先级和时间片。

上下文切换
  • 定义:上下文切换是指从一个进程或线程切换到另一个进程或线程的过程。包括保存当前进程或线程的状态,加载下一个进程或线程的状态。

  • 开销:上下文切换会消耗 CPU 时间和内存资源,频繁的上下文切换会影响系统的整体性能。

4.线程间的状态流转

线程的主要状态
  • NEW:线程被创建但是未启动

  • RUNNABLE:线程正在运行或者准备运行

  • BLOCKED:线程被阻塞,等待锁进入同步块或方法

  • WAITING:线程无限等待,需要其他线程调用特定方法唤醒

  • TIMED_WAITING:线程有限等待,指定时间过后恢复或被其他线程唤醒

  • TERMINATED:线程终止,执行完毕或者异常停止

注意:
  • sleep(time)和wait(time)的区别:

    • sleep(time)线程睡眠,睡眠的过程不会释放锁。到时间后自动醒来继续执行。

    • wait(time)线程等待,等待的过程会释放锁,其他线程可以抢,等待过程中被唤醒或者到时间后会进入队列争抢锁。

  • wait()和notify():

    • wait()无限等待,会释放锁,需要其他线程调用notify()或则notifyAll()唤醒,被唤醒后进入队列争抢锁

    • notify()一次只能唤醒一条等待的线程,如果是多条线程等待中,随机唤醒一条等待中的线程。

    • notifyAll()唤醒所有等待中的线程。

    • notify()和notifyAll()都不会影响sleep状态的线程

  • wait()和notify()的共同点

    • 都需要锁对象,所以在同步方法或者块中执行

    • 两个方法的调用必须是同一个锁对象调用:理解为同一个锁对象将多条线程分到了一组中,notify就知道唤醒的是本组(同一个同步方法或块)的等待线程

5.创建线程的方法

线程的创建方法总共可以分为5种。

  • 继承Thread类,通过重写run()方法创建线程

    public class ThreadOne extends Thread {public void run() {System.out.println("Thread One is running");}public static void main(String[] args) {ThreadOne threadOne = new ThreadOne();//调用start方法,开启线程,jvm自动调用run方法threadOne.start();}   
    }

    Thread类中的方法:

    • void start():开启线程,jvm自动调用run()方法

    • void run():设置线程任务。Thread重写Runnable中的run()方法

    • String getName():获取线程名字

    • void setName():给线程设置名字

    • static Thread currentThread():获取当前线程对象

    • static void sleep(long millis):线程睡眠,超时后自动醒来继续执行,参数是毫秒

    • void setpriority(int newPriority):设置线程优先级

    • void join() 插队

    • void yield() 礼让

  • 实现Runnable接口,实现run()方法创建线程

    public class ThreadTwo implements Runnable{@Overridepublic void run() {System.out.println("Thread Two is running");}
    ​public static void main(String[] args) {ThreadTwo threadTwo = new ThreadTwo();/*Thread(Runnable target)*/Thread thread = new Thread(threadTwo);thread.start();}
    }
  • 使用Lambda表达式匿名内部类,简化Runnale的创建

    public class ThreadThree {public static void main(String[] args) {new Thread(new Runnable(){@Overridepublic void run() {System.out.println("Thread Three is running");}},"threadThree").start();}
    }
  • 使用ExecutorService创建和管理线城池,使用线程池创建

    使用 ExecutorService 创建线程池时,newFixedThreadPoolnewCachedThreadPool 是两种常用的工厂方法。然而,这两种线程池在某些情况下可能会因为资源耗尽而导致 OutOfMemoryError(OOM)。

    注意:实际的开发中不要使用ExecutorService创建线程池,要使用new ThreadPoolExecutor的方式。

        public static void main(String[] args) {// 线程池参数int corePoolSize = 5; // 核心线程数int maximumPoolSize = 10; // 最大线程数long keepAliveTime = 60L; // 线程空闲时间TimeUnit unit = TimeUnit.SECONDS; // 时间单位BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(100); // 工作队列ThreadFactory threadFactory = Executors.defaultThreadFactory(); // 线程工厂RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy(); // 拒绝策略
    ​// 创建线程池ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue,threadFactory,handler);
    ​// 提交大量任务省略...
    ​// 关闭线程池executor.shutdown();}
    • newFixedThreadPool使用的是无界队列,当队列中的任务增长速度远大于处理的速度,队列会不断增长,导致内存耗尽。应对思路:设置有限队列存放任务

    • newCachedThreadPool使用的是可缓存的线程池,当任务的提交速度大于处理速度,线程池不断创建新线程,导致内存耗尽。应对思路:设置拒绝策略。

  • 使用FutureTask和Callable创建

    FutureTaskCallable 是用于实现异步计算和返回结果的重要接口和类。

    public class ThreadFive {public static void main(String[] args) {FutureTask<Integer> futureTask = new FutureTask<>(() -> {int sum = 0;for (int i = 0; i < 100; i++) {sum += i;}return sum;});
    ​new Thread(futureTask).start();
    ​try {System.out.println(futureTask.get());} catch (InterruptedException | ExecutionException e) {System.out.println("Error: " + e.getMessage());}}
    }

6.线程安全问题

模拟妈妈摊10个煎饼儿子吃10个煎饼的场景

public static void main(String[] args) {// 妈妈摊10煎饼Thread mother = new Thread(() -> {for (int i = 0; i < 10; i++) {System.out.println("妈妈:摊了一个煎饼!");NUM_PANCAKES++;System.out.println("还剩:" + NUM_PANCAKES + "个煎饼!");}});
​// 儿子吃10煎饼Thread son = new Thread(() -> {for (int i = 10; i > 0; i--) {System.out.println("儿子:吃了一个煎饼!");NUM_PANCAKES--;System.out.println("还剩:" + NUM_PANCAKES + "个煎饼!");}});
​mother.start();son.start();}

结果:

多线程下对同一个共享资源的访问,会导致诸多线程安全问题:

  • 数据竞争

    多个线程访问同一内存位置,至少一个在写,没有合适的同步机制保护数据就会导致未定义的行为。

  • 竞态条件

    多个线程访问和操作共享顺序的操作非原子性(不可中断的操作),那么就会导致不同的顺序不同的结果。

  • 死锁

    线程间互相等待对方的资源。吃饭需要碗和勺子,一个拿碗一个拿勺。

  • 内存可见性

    线程更改了共享变量的值,其他线程没有及时同步更新,读取的还是自己的缓存。

  • 指令重排序

    编译器和处理器可能会重新安排指令的执行顺序,多线程下会影响程序的正确性

7.线程间的通信

在Java中,可以使用wait()notify()方法来实现线程间的同步通信。

用妈妈摊煎饼儿子吃煎饼,模拟线程间通信,同时确保煎饼只能摊一张吃一张的功能。

public class PancakeScenario {// 共享资源:煎饼private static boolean pancakeReady = false;private static int NUM_PANCAKES_SUM = 0;
​private static int NUM_PANCAKES_REST = 0;
​public static void main(String[] args) {// 妈妈:摊煎饼Thread motherThread = new Thread(() -> {while(true) {synchronized(PancakeScenario.class) {// 有煎饼,妈妈就等待while (pancakeReady) {try {PancakeScenario.class.wait();} catch (InterruptedException e) {System.out.println("妈妈:等待失败...");}}System.out.println("妈妈:烤煎饼中...");// 煎饼摊好了,妈妈通知儿子pancakeReady = true;NUM_PANCAKES_REST++;NUM_PANCAKES_SUM++;System.out.println("还剩" + NUM_PANCAKES_REST + "个煎饼");System.out.println("妈妈摊了" + NUM_PANCAKES_SUM + "个煎饼");PancakeScenario.class.notify();}}}, "motherThread");
​// 儿子:吃煎饼Thread childThread = new Thread(() -> {while(true) {synchronized(PancakeScenario.class) {// 没煎饼,儿子就等待while (!pancakeReady) {try {PancakeScenario.class.wait();} catch (InterruptedException e) {System.out.println("儿子:等待失败...");}}System.out.println("儿子:吃煎饼中...");// 煎饼吃完了,儿子通知妈妈pancakeReady = false;NUM_PANCAKES_REST--;System.out.println("还剩" + NUM_PANCAKES_REST + "个煎饼");System.out.println("儿子吃了" + NUM_PANCAKES_SUM + "个煎饼");PancakeScenario.class.notify();}}}, "childThread");
​motherThread.start();childThread.start();}
}

8.Lock对象的介绍和基本使用

在Java中,Lock 接口提供了比内置的 synchronized 关键字更灵活的锁定机制。Lock 接口及其相关类位于 java.util.concurrent.locks 包中,提供了一系列高级功能,如公平锁、非阻塞锁、可中断锁等。

Lock 接口的主要方法
  1. void lock():获取锁。如果锁不可用,当前线程将被阻塞,直到锁可用。

  2. void lockInterruptibly():获取锁,如果锁不可用,当前线程将被阻塞,直到锁可用或被中断。

  3. boolean tryLock():尝试获取锁。如果锁可用,则立即返回 true;如果锁不可用,则立即返回 false

  4. boolean tryLock(long time, TimeUnit unit):尝试获取锁,但在指定的等待时间内如果锁不可用,则返回 false

  5. void unlock():释放锁。

Lock 接口的实现类
  1. ReentrantLock:最常用的 Lock 实现,支持重入。这意味着同一个线程可以多次获取同一个锁,而不会导致死锁。

  2. ReentrantReadWriteLock:读写锁,允许多个读取者同时访问资源,但写入者独占资源。

  3. StampedLock:提供乐观读锁、写锁和读锁,适用于高性能读多写少的场景

用lock改造摊煎饼场景:

public class PancakeScenarioUpgrade {// 共享资源:煎饼private static boolean pancakeReady = false;
​// 锁对象private static final Lock lock = new ReentrantLock();
​public static void main(String[] args) {// 妈妈线程:负责摊煎饼Thread motherThread = new Thread(() -> {while (true) {lock.lock();try {while (pancakeReady) {// 如果已经有煎饼了,妈妈就等待try {lock.unlock();Thread.sleep(1000); // 模拟等待时间} catch (InterruptedException e) {e.printStackTrace();} finally {lock.lock();}}// 摊煎饼pancakeReady = true;System.out.println("妈妈摊了一个煎饼");} finally {lock.unlock();}
​// 模拟摊煎饼的时间try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});
​// 儿子线程:负责吃煎饼Thread sonThread = new Thread(() -> {while (true) {lock.lock();try {while (!pancakeReady) {// 如果没有煎饼,儿子就等待try {lock.unlock();Thread.sleep(1000); // 模拟等待时间} catch (InterruptedException e) {e.printStackTrace();} finally {lock.lock();}}// 吃煎饼pancakeReady = false;System.out.println("儿子吃了煎饼");} finally {lock.unlock();}
​// 模拟吃煎饼的时间try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});
​// 启动线程motherThread.start();sonThread.start();}
}

9.避免忙等待

在改造的场景中,idea有一个提示信息:

// 在循环中使用Thread.sleep()可能会忙等待
Call to 'Thread.sleep()' in a loop, probably busy-waiting

忙等待是指在一个循环中不断检查某个条件,直到该条件满足为止,而在此过程中线程不会放弃 CPU 时间片,也不会进入休眠状态。这种方式通常用于短时间的等待,或者在高实时性要求的场景中。它会导致CPU持续占用和性能损耗。

  • 使用Condition 对象

可以使用Condition 对象,提供了更精确的等待和通知机制,避免 Thread.sleep() 的精度问题。

public class PancakeScenario {
​// 共享资源:煎饼private static boolean pancakeReady = false;
​// 锁对象private static final Lock lock = new ReentrantLock();// 条件对象private static final Condition pancakeReadyCondition = lock.newCondition();
​public static void main(String[] args) {// 妈妈线程:负责摊煎饼Thread motherThread = new Thread(() -> {while (true) {lock.lock();try {while (pancakeReady) {// 如果已经有煎饼了,妈妈就等待pancakeReadyCondition.await();}// 摊煎饼System.out.println("妈妈摊了一个煎饼");pancakeReady = true;// 通知儿子可以吃煎饼了pancakeReadyCondition.signal();} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}
​// 模拟摊煎饼的时间try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});
​// 儿子线程:负责吃煎饼Thread sonThread = new Thread(() -> {while (true) {lock.lock();try {while (!pancakeReady) {// 如果没有煎饼,儿子就等待pancakeReadyCondition.await();}// 吃煎饼System.out.println("儿子吃了煎饼");pancakeReady = false;// 通知妈妈可以摊新的煎饼了pancakeReadyCondition.signal();} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}
​// 模拟吃煎饼的时间try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});
​// 启动线程motherThread.start();sonThread.start();}
}
  • 使用Timer

    还是摊煎饼吧,儿子每隔10秒就跑去看煎饼是否摊好。

    public static void main(String[] args) {Thread son = new Thread(() -> {while (true) {try {//看煎饼好了没checkPancakeStatus();Thread.sleep(1000L * 10);} catch (Exception e) {//print the error loge.printStackTrace();}}});son.start();}

    如果checkPancakeStatus方法抛出了异常就会跳过sleep(),那就没办法休眠,循环持续执行,在这个基础上,如果捕获异常打印了日志,还会导致日志撑爆磁盘。

    还有一个要注意的坑,线程在sleep的过程中并不会释放所持有的锁,这会导致严重的并发问题,甚至是死锁。

    推荐可以使用使用jdk自带的java.util.Timer解决:

        public static void main(String[] args) {Timer timer = new Timer();timer.schedule(new TimerTask(){@Overridepublic void run() {try {//看煎饼好了没checkPancakeStatus();Thread.sleep(1000L * 10);} catch (Exception e) {//print the error loge.printStackTrace();}}}, 1000L * 10, 1000L * 10);}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于SpringBoot+Gpt个人健康管家管理系统【提供源码+答辩PPT+参考文档+项目部署】

作者简介&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流。✌ 主要内容&#xff1a;&#x1f31f;Java项目、Python项目、前端项目、PHP、ASP.NET、人工智能…

Kotlin by lazy和lateinit的使用及区别

在 Kotlin 中&#xff0c;lateinit 和 by lazy 都可以用来延迟初始化变量&#xff0c;但它们有不同的适用场景和使用方式。下面详细介绍它们的用法和区别。 1.lateinit lateinit 关键字用于延迟初始化 可变属性 (var)&#xff0c;主要用于那些在声明时不能立即初始化&#xf…

提高文本处理效率:精通awk命令中的$NF

在AWK编程语言中&#xff0c;$NF是一个特定的变量&#xff0c;用于引用当前处理记录中的最后一个字段值。这里的NF是AWK的一个内置变量&#xff0c;表示当前记录所含字段的数量。通过使用$NF&#xff0c;可以直接获取到与NF数值相对应的那个字段的具体内容。 示例使用 以下文件…

通讯学徒学习日记

本章内容为 长期更新模式&#xff0c;目前入职的第三天&#xff0c;学徒状态。 文章目录 前言开始接水晶头、接光纤水晶头接光纤 PON&#xff08;GPON 、EPON&#xff09;AON 和 PON 的详解AONPON 前言 编程虽然是爱好&#xff0c;但确实也想把这份爱好变成工作。但是对于目前刚…

SpringBoot在线教育系统:集成第三方服务

5系统详细实现 5.1 普通管理员管理 管理员可以对普通管理员账号信息进行添加修改删除操作。具体界面的展示如图5.1所示。 图5.1 普通管理员管理界面 5.2 课程管理员管理 管理员可以对课程管理员进行添加修改删除操作。具体界面如图5.2所示。 图5.2 课程管理员管理界面 5.3 …

【用Java学习数据结构系列】泛型上界与通配符上界

看到这句话的时候证明&#xff1a;此刻你我都在努力 加油陌生人 个人主页&#xff1a;Gu Gu Study 专栏&#xff1a;用Java学习数据结构系列 喜欢的一句话&#xff1a; 常常会回顾努力的自己&#xff0c;所以要为自己的努力留下足迹 喜欢的话可以点个赞谢谢了。 作者&#xff…

backtrader下的轮动策略模板,附年化20.6%的策略源码。

原创内容第700篇&#xff0c;专注量化投资、个人成长与财富自由。 原创日更700天&#xff0c;回首向来萧瑟处&#xff0c;也无风雨也无晴。 但行好事&#xff0c;莫问前程&#xff0c;持续改1%&#xff0c;为社群的同学们提供价值。 今天我们实现backtrader下的轮动策略模板…

B2109 统计数字字符个数

B2109 统计数字字符个数 #include <iostream> using namespace std; # include <string.h> #include <ctype.h> #include <algorithm> int main(){ char str[256]; cin.getline(str,256); //fgets(str,256,stdin); int cnt 0; //for(size_t i 0…

使用AWS Lambda构建无服务器应用程序

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 使用AWS Lambda构建无服务器应用程序 AWS Lambda 简介 创建 AWS 账户 创建 Lambda 函数 配置触发器 编写和测试代码 示例代码&am…

如何在Word的表格中一次性插入多行?

当我们想在Word中的表格中一次性插入多行时&#xff0c;却发现内置的插入功能并没有插入行数选项。 此时我们只需要选择多行&#xff0c;例如&#xff0c;选择5行&#xff0c;以同样的步骤插入&#xff0c; 在下方就新增了5行。 同理&#xff0c;插入其他自定义行数。

【ACM出版,EI稳定检索,九大高校联合举办, IEEE Fellow支持】2024年计算机视觉与艺术研讨会(CVA 2024,11月29-12月1日)

大会官网&#xff1a;www.icadi.net (CVA为ICADI分会&#xff0c;网站沿用主会议&#xff1b;议程、出版将以主会为准&#xff09; 大会时间&#xff1a;2024年11月29-12月1日 大会地点&#xff1a;中国-天津 终轮截稿&#xff1a;2024年11月22号&#xff08;特殊情况联系会…

火山引擎VeDI数据服务平台:在电商场景中,如何解决API编排问题?

01 平台介绍 数据服务平台可以在保证服务高可靠性和高安全性的同时&#xff0c;为各业务线搭建数据服务统一出口&#xff0c;促进数据共享&#xff0c;为数据和应用之间建立了一座“沟通桥梁”。 同时&#xff0c;解决数据理解困难、异构、重复建设、审计运维困难等问题&#x…

网付碰一下支付系统功能分享来了!

随着碰一下支付代理骗局的持续曝光&#xff0c;越来越多的人都开始将目光转向了碰一下支付系统源码部署这一入局方式之上&#xff0c;使得这一项目愈加火爆的同时&#xff0c;也让网付等头部聚合支付公司成为了大家关注的焦点&#xff0c;连带着网付碰一下支付系统有哪些功能这…

ElasticSearch学习篇16_《检索技术核心20讲》进阶篇之空间检索

背景 学习极客实践课程《检索技术核心20讲》https://time.geekbang.org/column/article/215243&#xff0c;文档形式记录笔记。 相关问题&#xff1a; 查询范围固定的需求 直接计算两点之间距离区域二进制编码GeoHash编码 查询范围不固定的需求 GeoHash编码索引结构设计 基于…

SSH详解

一、SSH 引入 在使用 https 协议访问我们的 Gitee 库的时候&#xff0c;如果我们想要克隆一个私有库&#xff0c;或者说想要使用 git push&#xff0c;我们都需要输入账户账号和密码&#xff0c;这样十分繁琐而且很不安全。 虽然我们可以使用 Git for Windows 的 Git Credent…

互联网大厂钟爱的压测工具分享,战绩可查!

双11来了&#xff0c;又到了一些互联网大厂技术团队疯狂&#xff08;~~加班&#xff09;~~备战的紧张时刻。 今天&#xff0c;为大家带来一期“互联网大厂亲测的压测工具分享”&#xff0c;并在结尾附上30天SaaS版免费体验&#xff01; 压力测试相比于监控而言&#xff0c;是…

mac-泛洪

泛洪攻击的类型 TCP SYN Flood&#xff1a; 攻击者向目标服务器发送大量的 TCP SYN 请求&#xff0c;但不完成握手过程。服务器为每个请求分配资源&#xff0c;最终可能耗尽其连接表&#xff0c;导致无法处理正常请求。 UDP Flood&#xff1a; 攻击者向目标发送大量的 UDP 数据…

【数据分享】1901-2023年我国省市县镇四级的逐年最高气温数据(免费获取/Shp/Excel格式)

之前我们分享过1901-2023年1km分辨率逐月最高气温栅格数据和Excel和Shp格式的省市县镇四级逐月最高气温数据&#xff0c;原始的逐月最高气温栅格数据来源于彭守璋学者在国家青藏高原科学数据中心平台上分享的数据&#xff01;基于逐月数据我们采用求年平均值的方法得到逐年最高…

算法笔记:Day-09(初始动态规划)

509. 斐波那契数 斐波那契数 &#xff08;通常用 F(n) 表示&#xff09;形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始&#xff0c;后面的每一项数字都是前面两项数字的和。也就是&#xff1a; F(0) 0&#xff0c;F(1) 1 F(n) F(n - 1) F(n - 2)&#xff0c;其中 …

「Mac畅玩鸿蒙与硬件27」UI互动应用篇4 - 猫与灯的互动应用

本篇将带领你实现一个趣味十足的互动应用&#xff0c;用户点击按钮时猫会在一排灯之间移动&#xff0c;猫所在的位置灯会亮起&#xff08;on&#xff09;&#xff0c;其余灯会熄灭&#xff08;off&#xff09;。应用会根据用户的操作动态更新灯光状态和文本提示当前亮灯的位置&…