• 线程和线程池


    线程和线程池

    并发和并行

    并发是指在单个CPU核心上,多个线程占用不同的CPU时间片,但由于每个线程占用的CPU时间片非常短(比如10ms),看起来就像是多个线程在共同执行一样,但在微观物理上看其实还是串行执行的。这样的场景称作并发。
    在这里插入图片描述

    并行是指在CPU多个核心上,多个线程是在真正的同时执行。(每个CPU核心也在并发的执行)
    在这里插入图片描述

    多线程的优势

    多线程程序一定就好吗?不一定,要看具体的应用场景:

    IO密集型,运算较少,涉及磁盘或网络、外部设备等IO操作较多,会阻塞等待情况较频繁。
    无论是CPU单核、CPU多核、多CPU,都是比较适合多线程程序的

    CPU密集型,运算多,IO操作少,阻塞情况少。
    CPU单核下,多线程存在上下文切换,是额外的花销,线程越多上下文切换所花费的额外时间也越多,不如一个线程一直进行计算,不适合多线程。
    CPU多核下,多个线程可以并行执行,可以提高CPU利用率。

    线程的消耗

    为了完成任务,创建很多的线程可以吗?线程真的是越多越好?
    线程的创建和销毁都是非常"重"的操作
    线程的创建需要由系统来完成,需要内核的参与,这就涉及到用户空间到内核空间的切换。要给线程分配内核栈、页目录、页表等描述线程的资源和数据结构。创建完成后是要交给用户来使用,需要再切回用户空间。

    线程创建完成后,在用户空间处理执行业务,执行完就需要销毁线程,同样也需要内核的参与。

    操作系统上创建线程和销毁线程都是很"重"的操作,耗时耗性能都比较多,那么在服务执行的过程中,
    如果业务量比较大,实时的去创建线程、执行业务、业务完成后销毁线程,那么会导致系统的实时性能
    降低,业务的处理能力也会降低。

    线程栈本身占用大量内存
    在32位地址空间下,内核给每个进程分配了4G大小的地址空间,用户空间3个G,内核空间1个G,一个进程创建的所有线程共享进程的地址空间。Linux系统下栈的空间大小默认是8M:
    在这里插入图片描述
    3G的空间除去代码段、数据段等,一个进程大概能创建380个线程。
    如果程序一开始就创建了大量的线程,程序的地址空间都被线程栈占了,连变量都定义不了多少,还怎么做业务呢?

    线程的上下文切换要占用大量时间
    线程数量如果过多,就会涉及到线程的调度,线程调度是需要进行上下文切换的,切耗费的是CPU的时间,切换的时候CPU什么都没做,就会降低CPU的利用率。

    大量线程同时等待同一个事件,唤醒时会使系统经常出现锯齿状负载或者瞬间负载量很大导致宕机

    为了减少创建线程和销毁线程的性能和时间耗费,可以在服务进程启动之初,就事先创建好线程池里面的线程,当业务流量到来时需要分配线程,直接从线程池中获取一个空闲线程执行task任务即可,task执行完成后,也不用释放线程,而是把线程归还到线程池中继续给后续的task提供服务。

    fixed模式线程池

    线程池里面的线程个数是固定不变的,一般是ThreadPool创建时根据当前机器的CPU核心数量进行指定。

    cached模式线程池

    线程池里面的线程个数是可动态增长的,根据任务的数量动态的增加线程的数量,但是会设置一个线程数量的阈值(线程过多的坏处上面已经讲过了),任务处理完成,如果动态增长的线程空闲了设定时间还没有处理其它任务,那么关闭线程,保持池中最初数量的线程即可。

    线程池模型:
    在这里插入图片描述

  • 相关阅读:
    vscode远程链接下的python环境配置
    Python 爬虫基础入门知识
    SpringBoot——自定义start场景启动器
    vs2022中使用gridview显示sqlserver中的数据时只显示了列而没有显示表中的数据
    【算法】冒泡排序
    vue3+vite+ts项目初建(仅个人习惯)
    LeetCode【279】完全平方数
    C语言:用函数打印质数
    想要精通算法和SQL的成长之路 - 前缀和的应用
    java文件查看大小,压缩,文件下载工具类
  • 原文地址:https://blog.csdn.net/weixin_43973403/article/details/126311637