进程概念(PCB、进程创建、进程状态等)

news2024/9/24 9:25:01

进程是一个运行的程序,是所有计算机的基础。这个过程与计算机代码不一样,尽管它们非常相似。程序通常被认为是 “被动的” 实体,而进程则是 “主动的” 实体。硬件状态、RAM、CPU和其它属性都是进程持有的属性。下面我们就来了解更多关于进程的知识。

文章题目:

  • 什么是进程?
  • 进程控制块 - PCB(Process Control Block)
  • 如何查看进程
  • 进程相关概念
  • 获取进程标示符
  • 创建进程 - fork
  • OS进程状态
  • 僵尸进程 - zombie
  • 孤儿进程 - orphan
  • 进程优先级
  • 查看系统进程
  • PRI and NI
  • 更改进程优先级

什么是进程?

进程本质上就是运行的软件、任何进程的执行都必须按照特定的顺序进行。进程是指帮助表示必须在任何系统中实现的基本工作单元的实体。🎯

课内概念:程序的一个执行实例,正在执行的程序等。
内核观点:担当分配系统资源(CPU时间,内存)的实体。

进程的组成:
在这里插入图片描述

🎯在电脑开机开始运行时,就已经有很多进程就绪,当我们打开网页进行浏览或者打开QQ,这些都是进程。在系统中有许多的进程,而在我们运行程序时,都需要将其加载到内存中,面对着众多的进程,操作系统应该如何来进行进程的管理呢?因此操作系统为了更好的管理进程,将每一个进程描述起来,这就是描述进程 - PCB。

进程控制块 - PCB(Process Control Block)

🧩每个进程都有一个进程控制块,进程信息就被放在进程控制块的数据结构中,这是一个由操作系统管理的数据结构。

🧩课文中将其称为 PCB(Process Control Block),而在 Linux 操作系统下的 PCB 是:task_struct。

🧩task_struct 是 Linux 内核的一种数据结构,它会被装载到 RAM(内存) 里且包含着进程的信息。

一个进程的进程控制块(PCB)是这样的:

在这里插入图片描述
每一个进程都有自己对应的 PCB 来进行标识,也被称为进程的上下文。

使用命令 ps aux 可查看当前计算机中存在的进程:
在这里插入图片描述

操作系统对这些进程进行管理时:先描述,再组织。操作系统不是直接对进程进行管理的,而是当一个进程启动时,操作系统先将其进行描述,然后将其描述的进程信息放入进程控制块的数据结构中管理起来,实际上,操作系统对进程的管理是对进程描述信息的管理(即对 PCB 进行管理)。

操作系统将计算机中运行的每一个进程都使用 PCB 进行了描述,然后将这些 PCB 增加到双链表中进行管理起来:
在这里插入图片描述
这样以来,操作系统需要对每一个进程进行相关操作时,只需要在链表中找到其对应的 PCB,就可找到进程对其进程操作了。PCB 和 数据结构 对进程的描述和组织使操作系统更便于管理进程,使得操作系统对进程的控制科学、有效。

关于 PCB:

  • 每个进程的 PCB 都存储在主存储器中。
  • 每个进程只有一个与之相关的 PCB。
  • 所有进程的 PCB 都列在一个链表中。

task_struct 内容分类:

  • 标示符:描述进程的唯一标示符,用来区别其它进程。
  • 状态:任务状态、退出代码、退出信号等。
  • 优先级:相对于其它进程的优先级。
  • 程序计数器:程序中即将被执行的下一条指令的地址。
  • 内存指针:包括程序代码和进程相关数据的指针,还有和其它进行共享的内存块的指针。
  • 上下文数据:进程执行时处理器的寄存器中的数据。
  • I/O状态信息:包括显示的 I/O 请求,分配给进程的 I/O 设备和被进程使用的文件列表。
  • 记账信息:可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
  • other。

如何查看进程

通过 /proc 查看系统文件中的进程信息。首先进入根目录,然后进入名为 proc 的目录,里面包含了许多进程信息,例如下面我们进入1号进程查看其信息。

在这里插入图片描述
使用 ps ajx可查看当前所有的进程,配合 grep 命令使用我们可以查看到我们所需要进程信息
在这里插入图片描述

进程相关概念

竞争性:系统进程数目众多,而 CPU 资源是有限的,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级。

独立性:多个进程运行,需要独享各种资源,多进程运行期间互不干扰。

并行:多个进程在多个 CPU 下分别,同时进行运行,这称之为并行。

并发:多个进程在一个 CPU 下采用进程切换的方式,在一段时间内,让多个进程得以推进,称之为并发。

获取进程标示符

进程id(PID) - getpid()
父进程id(PPID) - getppid()

在这里插入图片描述

下面通过一个简单的程序来查看以下进程的 PID 和 PPID。当程序重新运行时,进程的 PID 会变化,但是 PPID 是一样的。通过具体查看,发现 PPID 所对应的进程是 bash。在操作系统执行指令时,为了防止因为程序的崩溃而影响到系统,因此,shell 并不会亲自执行指令,而是派生出子进程去执行指令。所以每个进程的 PPID 都是一样的。

在这里插入图片描述

创建进程 - fork

fork 系统调用用于创建一个新的进程,称为子进程,它与进行 fork() 调用的进程并发运行。在创建了新的进程之后,两个进程都将执行 fork() 系统调用之后的下一条指令,子进程使用和父进程相同的程序计数器、相同的 CPU 寄存器,相同的打开文件。下面就来简单的认识一个 fork() 系统调用。

在这里插入图片描述
fork() 不接受参数,返回一个整数值,下面为 fork() 返回的不同值:

负数:子进程创建失败
0:返回到新创建的子进程
正数:返回给父进程或者调用它的地方,取值为新创建的子进程的进程 ID

如下所示,使用 fork() 创建子进程:
在这里插入图片描述
从运行结果可以看出打印函数执行了两次,且不是同一个进程。而其中一个进程的 PPID 是另一个进程的 PID ,由此可以说明其中一个进程是当前进程(父进程)的子进程。

当前程序的代码和数据是属于父进程的,那 fork 创建出的子进程的数据和代码在哪呢?

在这里插入图片描述
上图所示,fork() 调用之后的代码运行了两次,由此可以看出,fork 完成之后,父子进程共享 fork 之后的代码,而父子进程的数据各自开辟空间,独有一份(采用写时拷贝)。

fork 之后用 if 进行分流

当一个进程创建一个新进程时,有两种可能的执行出口:

  • 父进程继续与子进程并发执行。
  • 父进程一直等待,知道部分或全部子进程终止。

如下演示 fork 之后使用 if 进行分流:

在这里插入图片描述
在上面的代码中,使用 fork() 创建了一个子进程。fork() 在子进程中返回0,在父进程中返回正整数,而父进程中的正整数正是子进程的 PID 。这里有两个输出,因为父进程和子进程是并发运行的。而先执行父进程还是子进程是由操作系统决定的。父进程和子进程执行同一个程序,并不意味着它们完全相同。操作系统为这两个进程分配不同的数据和状态,这些进程的控制流可能不同。

总结:

  • fork 系统调用创建一个新的进程,称为 ”子进程“,该进程与父进程并发运行。
  • 父进程和子进程是通过 fork() 调用的返回值来区分开的。
  • 在语法层面上,fork() 不接受任何的参数,其返回值为 pid_t。
  • 子进程与父进程使用相同的 CPU 寄存器、相同的打开文件和相同的程序计数器。
  • 实际上,我们可以用 fork() 系统调用来创建一些唯一的代码,因为每个子进程都会给出唯一的值。

OS进程状态

正在执行的程序称为进程。在进程执行期间,进程在整个生命周期中会经历不同的状态,这些状态称为进程状态。所有与进程相关的信息都会存储在进程控制块(PCB)中,进程状态也如此。

在这里插入图片描述

Linux 内核源代码对进程状态的定义:

/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};

上述代码描述了进程的许多状态。在不同的操作系统中,进程可能存在不同的状态。进程的状态存储在进程控制块(PCB)中。下面我们来详细了解一个每个进程状态。

运行状态 - R(running)

只要从就绪队列中将 CPU 分配给进程,进程状态就会变成运行态。运行状态并不意味着进程一定在运行,它表明进程要么在运行中,要么在运行队列中。
在这里插入图片描述
如下所示的程序处于运行状态中:

在这里插入图片描述

睡眠状态 - S(sleeping)

意味着该进程正在等待某件事情完成,这里的睡眠状态有时候也可以叫做可中断睡眠(interruptible sleep)。处于此状态的进程随时可以被唤醒和杀掉。

在这里插入图片描述

为什么程序一直在执行,而进程状态确为睡眠状态呢?🎯

在我们使用指令 ps ajx 查看进程状态时,我们查看到的是指令执行时进程所处的状态,而不是随着进程的变化而进行动态变化的状态。CPU 的速度远远大于其它外设的速度,因此 CPU 处理很快,大多数的时间都是在等待其它硬件调配资源,执行程序的时间很短,因此查看到的进程处于 S+ 状态。

处于浅度睡眠的进程,我们可以对其唤醒或者杀掉,例如使用 kill -9 命令将进程杀掉:

在这里插入图片描述

磁盘休眠状态 - D(Disk sleep)

一个进程处于深度睡眠状态,则该进程不会被杀掉。磁盘休眠状态有时候叫做不可中断睡眠状态(uninterruptible sleep),这个状态的进程通常会等待 IO 结束。进程为什么会被置为 uninterruptible sleep 状态呢?当某一进程需要对磁盘进行写入,在对磁盘写入数据期间,该进程就处于深度睡眠状态,不会被操作系统杀掉,该进程需要等待磁盘给出是否写的数据成功的信号。当得到相应的条件时才能响应信号。

停止状态 - T(stopped)

可以通过发送 SIGSTOP 信号开停止进程,这个被暂停的进程可以通过发送 SIGCONT 信号来让进程继续运行。

如下,向进程发送 SIGSTOP 命令,使进程进入暂停状态,发送 SIGCONT 信号进入运行状态:

在这里插入图片描述

在上述程序中,进程开始运行时的状态为 R+ ,而暂停之后继续再次运行时进程状态变为 R。进程状态后面的 + 号表示该进程是一个前台进程,没有加号则表明该进程是一个后台进程。前台进程可以通过 Ctrl + c 或者 kill -9 进行终止。没有 + 号表示该进程是后台进程,只能用 kill -9 指令将其杀死。

死亡状态 - X(dead)

死亡状态只是一个返回状态,不会在任务列表看到这个状态。

僵尸进程 - zombie

僵尸进程也被称为 “死亡进程”。理想情况下,当一个进程执行完成时,他在进程表中的条目应该被删除,但是在僵尸进程情况下,这并不会发生。

🎲僵尸状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程(使用 wait() 系统调用)没有读取到子进程退出的返回信息时就会产生僵尸进程。

🎲僵尸进程会以终止状态保持在进程列表中,并且会一直等待父进程读取退出状态信号。

🎲子进程退出,父进程还在运行,父进程没有读取子进程状态,则子进程进入 Z 状态。

如下我们来演示一下僵尸进程,fork() 创建子进程并在其中打印3次信息后退出,父进程一直循环执行代码不退出。子进程退出之后,父进程依旧运行,因此子进程等待父进程读取自己的退出信息,那么等待时就进入了僵尸状态:

#include <stdio.h>
#include<unistd.h>
#include<sys/types.h>

int main()
{
    pid_t id = fork();
    if(id == 0)
    {
        int count=3;
        while(count)
        {
            printf("I am a child process! PID : %d,PPID : %d,count = %d\n",getpid(),getppid(),count--);
            sleep(1);
        }
        printf("child process quit!\n");
        exit(1);
    }
    else if(id>0) 
    {
        while(1)
        {
            printf("I am a parent process! PID : %d,PPID : %d\n",getpid(),getppid());
            sleep(1);
        }
    }
    else 
    {
        perror("fork false");
        return 1;
    }
    return 0;
}

程序运行后,我们使用监控脚本 while :; do ps axj | head -1 && ps axj | grep process | grep -v grep | grep -v Ssl;echo "---------------------------------";sleep 1;done 来实时查看进程的状态。如下所示,当子进程退出以后,父进程没有退出,子进程就会进入僵尸状态。

在这里插入图片描述

僵尸进程的危害:

  • 操作系统有一个有限大小的进程列表,大量的僵死进程将产生一个完整的进程列表,进程列表慢了意味着操作系统无法在需要时创建新进程。
  • 操作系统中的僵尸进程没有用,因为进程已经死亡,但它的条目占用了内存中的空间。
  • 操作系统中的 PID 是有限的,当所有的 PID 都被僵尸进程耗尽后,就无法创建新的进程了。
  • 一个父进程创建了许多子进程却不回收,就会造成资源的浪费。

僵尸进程清理:

  • 僵尸进程不会被操作系统强制结束。长时间运行的僵尸进程是错误或者资源泄漏的结果。它们在进程表中占用大量的空间,因此,需要避免过多的僵尸进程聚集。
  • 进程变成僵尸进程,它将失去所有内存页、打开的文件句柄、信号量锁等。当进程终止时,操作系统会释放几乎所有系统资源。
  • 可以通过在子进程结束后立即调用等待来防止这种情况,尽快从进程表中清理它。(后续说)

孤儿进程 - orphan

什么是孤儿进程?所谓的孤儿,我们可以用现实生活中的例子来理解。在现实中,孤儿指的是父母的孩子。类似的,在 os 中,正在执行但父进程已经终止的进程称为孤儿进程。

孤儿进程将会获得一个新的父进程。当内核检测到一个进程成为孤儿进程时,会为孤儿进程提供一个新的父进程。在大多数情况下,新的父进程的 PID 是为 1 的 INIT 进程。新的父进程等待孤儿进程完成之后,会要求内核清理孤儿进程的 PCB。这样孤儿进程就被回收掉了。🎯

以下代码模拟孤儿进程,fork 之后,父进程循环打印3次后退出,子进程一直执行,当父进程退出之后,子进程就变成孤儿进程了。将被 PID=1 的进程领养。

#include <stdio.h>
#include<unistd.h>
#include<sys/types.h>

int main()
{
    pid_t id = fork();
    if(id == 0)
    {
        while(1)
        {
            printf("I am a child process! PID : %d,PPID : %d\n",getpid(),getppid());
            sleep(1);
        }
    }
    else if(id>0) 
    {
        int count=3;
        while(count)
        {
            printf("I am a parent process! PID : %d,PPID : %d,count = %d\n",getpid(),getppid(),count--);
            sleep(1);
        }
        printf("parent process quit!\n");
        exit(0);
    }
    else 
    {
        perror("fork false");
        return 1;
    }
    return 0;
}

运行结果如下:当父进程退出之后,子进程的 PPID 变为 1.

在这里插入图片描述
❓太多的孤儿进程对系统有什么危害?

  • 操作系统中的孤儿进程在系统中占用资源。
  • 大量的孤儿进程会使 INIT 进程过载并挂起系统。

进程优先级

在优先调度队列中,每个进程都有一个优先级编号。在 Linux 等系统中,优先级编号的数字越低,则优先级越高。在可用进程中具有较高优先级的进程被给到 CPU。目前存在两种优先级调度算法:抢占式优先级调度、非抢占式优先级调度。

✔️CPU资源分配的先后顺序,就是指进程的优先级(priority)。
✔️优先级高的进程有优先执行的权力。配置进程优先级对多任务环境的 Linux 很有用,可以改善系系统性能。

查看系统进程

在 Linux 或者 Unix 系统中,用 ps -l 命令会输出以下内容:

在这里插入图片描述
以上列出几个重要信息:

  • UID :代表执行者的身份
  • PID :代表这个进程的编号
  • PPID :标记了该进程的父进程,即由那个进程发展衍生而来
  • PRI :代表这个进程可被执行的优先级,其值越小优先级越高
  • NI :该进程的 nice 值

PRI and NI

  • PRI 就是进程的优先级,即被 CPU 执行的先后顺序,PRI 值越小,则进程的优先级越高。
  • NI 就是我们所说的 nice 值,其表示进程可被执行的优先级的修正数值。
  • PRI 值越小越快被执行,加入 nice 值之后,将会使 PRI 变为:PRI(new)= PRI(old)+ nice。
  • 当 nice 值为负值时,那么该程序会将优先级值变小,及其优先级会变高,其越快被执行。
  • 因此,调整进程的优先级,在 Linux 下,是调整进程的 nice 值。
  • nce 值得取值范围是 -20 ~ 19,一个 40 个级别。

更改进程优先级

用 top 命令更改已存在进程的 nice 值:

  • 输入 top 命令
  • 进入 top 后按 “r” -> 输入进程PID -> 输入 nice 值

如下所示,调整一个进程的优先级:

在这里插入图片描述
在 Linux 操作系统中,初始进程的默认 PRI 为80,NI 默认为0。

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

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

相关文章

活体识别1:近红外(NIR)图像特性

说明 最近在接触活体识别&#xff0c;在网上找到一个介绍近红外光&#xff08;NIR&#xff09;特性的论文&#xff0c;我简单做个笔记。原文的全文在文末参考资料里。 来自&#xff1a;[1]隋孟君,茅耀斌,孙金生.基于近红外图像特征的活体人脸检测[J].自动化与仪器仪表,2021(0…

Win10下使用WSL2

打包 wsl --export Ubuntu-20.04 E:\Ubuntu\ubuntu.tar.gz 注销之前 wsl --unregister Ubuntu-20.04 导入 wsl --import Ubuntu-20.04 E:\Ubuntu\ E:\Ubuntu\ubuntu.tar.gz --version 2 设置默认登陆用户为安装时用户名 ubuntu2004.exe config --default-user dwb 更新清…

vue 预览 word

最近做的项目要求实现预览word, pdf&#xff0c;png等文件功能&#xff0c;pdf以及png都很简单&#xff0c;轻松百度搞定&#xff0c;但是word预览研究了好久&#xff0c;所以特此记录分享。前端实现预览word分为两种&#xff0c;一种是上传前预览&#xff08;也就是前端使用in…

SpringBoot笔记:统一请求参数修改(HttpServletRequest流复制),加解密参数也可参考处理

文章目录需求实现思路实战演练实现过滤器Filter继承 HttpServletRequestWrapper实现 RequestBodyAdvice 统一处理请求参数测试代码测试效果需求 需要进行统一的解密请求 header 头里面的关键字 encryKey &#xff0c;将解密出来的值赋给 provinceId 并传递给后端的每一个请求接…

23年 yolov5车辆识别+行人识别+车牌识别+车速检测代码(python)

行人识别yolov5和v7对比yolo车距yolo车距1代码&#xff1a;yolov5车辆检测代码 已有1503人下载 代码无需更改&#xff0c;直接可以预测&#xff01;&#xff01;&#xff01; 流程&#xff1a; 版本与配置声明 # YOLOv5 requirements # Usage: pip install -r requirements.tx…

C语言--结构体初阶

目录前言结构体类型的声明什么是结构结构的声明结构体变量的定义结构成员的类型结构体变量的初始化结构体的成员访问结构体传参函数调用的参数压栈前言 在前面的C语言学习中&#xff0c;我们学习了形如char&#xff0c;short&#xff0c;int&#xff0c;float等的不同类型的变…

活动星投票臻我风采评选视频投票的功能在线投票程序

“臻我风采评选”网络评选投票_线上小程序的投票方式_视频投票的功能_在线投票程序用户在使用微信投票的时候&#xff0c;需要功能齐全&#xff0c;又快捷方便的投票小程序。而“活动星投票”这款软件使用非常的方便&#xff0c;用户可以随时使用手机微信小程序获得线上投票服务…

即时通讯开发之详解TCP/IP中的IP选路、动态选路

静态 IP 选路 1一个简单的路由表 选路是 IP 层最重要的一个功能之一。前面的部分已经简单的讲过路由器是通过何种规则来根据 IP 数据包的 IP 地址来选择路由。 这里就不重复了。 对于一个给定的路由器,可以打印出五种不同的 flag&#xff1a;  U 表明该路由可用。  G…

Qlik Sense Enterprise Windows版(非集群)——详细安装步骤

Qlik Sense分为客户端(Desktop)和服务器(Server)&#xff0c;本文主要介绍Qlik Sense Server的图形化界面安装操作。 安装方式也分为两种&#xff0c;一种是图形化界面安装&#xff0c;另一种是静默安装。一般只有在特殊报错情况下我们才使用静默安装&#xff0c;静默安装的方…

实现分页查询

实现分页查询一、分页要素与语法二、例&#xff1a;博客系统文章列表页2.1 原始前端代码2.2 实现&#xff1a;查询分页数据验证2.3 实现 “首页” “上一页” “下一页” “末页”前端代码添加得到总页数实现 四个点击效果验证一、分页要素与语法 分页要素&#xff1a; 1&…

Qt音视频开发13-视频解码线程基类的设计

一、前言 这个解码线程基类的设计&#xff0c;是到目前为止个人觉得自己设计的最好的基类之一&#xff0c;当然也不是一开始就知道这样设计&#xff0c;没有个三五年的摸爬滚打以及社会的毒打&#xff0c;是想不到要这样设计的&#xff0c;一方面是要不断提炼各种视频类视频组…

伪逆矩阵 的使用

伪逆矩阵&#xff08;pseudo-inverse&#xff09;_Uglyduckling911的博客-CSDN博客_伪逆矩阵 一、什么是伪逆矩阵 若任意矩阵Am*n,B 为A的广义逆矩阵&#xff0c;若B满足下述条件&#xff08;Moore-penrose条件&#xff09;&#xff1a; &#xff08;1&#xff09;BAB B&am…

4.门面模式,组合模式,享元模式

门面模式 为了保证接口的可复用性&#xff08;或者叫通用性&#xff09;&#xff0c;我们需要将接口尽量设计得细粒度一点&#xff0c;职责单一一点。但是&#xff0c;如果接口的粒度过小&#xff0c;在接口的使用者开发一个业务功能时&#xff0c;就会导致需要调用 n 多细粒度…

【手把手】教你使用JMH和Disruptor - 多线程与高并发工具

JMH JMH全称是Java Microbenchmark Harness&#xff08;Java微基准测试&#xff09;&#xff0c;简单讲其实就是测一个方法的性能好坏。这个测试的框架是2013年发出来的&#xff0c;由JLT的开发人员开发&#xff0c;后来归到了OpenJDK下面&#xff0c;官网地址&#xff1a;htt…

运维实践 | OpenMLDB 跨机房容灾方案

背景 在单集群部署环境下&#xff0c;OpenMLDB 具备集群内节点级别的高可用能力。但若受到机房断电或者自然灾害等不可抗拒因素&#xff0c;则将造成的机房或大部分节点无法正常运转的情况&#xff0c;从而引发该集群状态异常&#xff0c;导致在线服务中断。为此&#xff0c;Op…

悉数美剧《黑客军团》中的黑客工具

本篇文章中主要列举《Mr. Robot》电视剧中主要用到的黑客工具&#xff0c;并对它们所对应的现实中的黑客工具做一简要介绍。Mr. Robot2015年美剧出了一部关于黑客题材的电视剧&#xff0c;相信爱看黑客电视剧、电影的同学们已经看过或者正在追这部神秘的《Mr. Robot》&#xff…

零基础学MySQL(四)-- 数据库最常用的操作【查询基础篇 -- 单表查询】

目录&#x1f4d4;一、最简单的 select 语句1️⃣基本语法2️⃣基本练习3️⃣补充说明(1) 使用表达式对查询的列进行运算(2) 在 select 语句中可使用 as 语句取别名&#x1f4d5;二、使用 where 子句进行过滤查询1️⃣基本语法2️⃣在 where 子句中经常使用的运算符3️⃣基本练…

4道面试题让你了解 ThreadLocal 的那点小秘密

我收集了4个面试中出现频率较高的关于ThreadLocal的问题&#xff1a; 什么是ThreadLocal&#xff1f;什么场景下使用ThreadLocal&#xff1f;ThreadLocal的底层是如何实现的&#xff1f;ThreadLocal在什么情况下会出现内存泄漏&#xff1f;使用ThreadLocal要注意哪些内容&…

工赋开发者社区 | 事件驱动架构要避开的 5 个陷阱

事件驱动架构非常强大&#xff0c;非常适合用在分布式微服务环境中。事件驱动架构提供了解耦的架构、更容易实现的可伸缩性和更高程度的弹性。请求应答&#xff08;客户端和服务器&#xff09;与事件流&#xff08;发布和订阅&#xff09;但是&#xff0c;与请求和应答类型的架…

防范DDOS攻击的最佳方法

Botnets是由多个感染的计算机(称为"bots"或"zombies")组成的网络。这些感染的计算机受到攻击者的控制,可以同时发送大量的数据流量到目标网站,导致DDoS(分布式拒绝服务)攻击。Botnets也可以用于从感染的计算机中获取私人信息,传播病毒和蠕虫,或者执…