一文带你深入了解线程池


一. 什么是线程池

简单来说,线程池就是提前创建好一批线程,当有任务的时候,从池子中取出一个线程去执行该任务,执行结束后,再把线程放回池子中,以备循环使用。

二. 为什么要使用线程池

  1. 降低资源消耗,线程一个生命周期需要经过创建、调度、销毁过程,使用线程池,可以降低线程创建和销毁的消耗。
  2. 提高响应速度,当有任务分配过来时,可以直接调度,不需要创建线程,速度快。
  3. 提高可管理性,使用线程池可以对线程进行统一的分配、调优和监管。

三. 线程池的参数

以标准库的线程池为例,它的参数列表如下:

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)

下面对这些参数进行介绍:

corePoolSize:核心线程数,即常备线程数

maximumPoolSize:最大线程数,常备线程数 + 临时线程数

keepAliveTime:线程的空闲时间,简单来说,就是临时线程活干完的时候,不会直接销毁临时线程,而是会观察一段时间,如果没有其他任务,再进行销毁。

TimeUnit unit:时间单位,m、ms等。

workQueue:工作队列,没有临时线程时,任务太多,核心线程(常备线程)做不完,则把任务存储到工作队列中。

threadFactory:线程工厂,用来创建线程,一般使用默认的线程工厂就可以了。

handler:拒绝策略,任务太多了,工作队列满了,就会执行拒绝策略。

常见的拒绝策略:

在这里插入图片描述

ThreadPoolExecutor.AbortPolicy:拒绝任务,抛出异常(直接拒绝,和领导吵一架)。

ThreadPoolExecutor.CallerRunsPolicy:由调用者来执行该任务(拒绝任务,让领导去做)。

ThreadPoolExecutor.DiscardOldestPolicy:把新任务加入,丢弃最早的任务。

ThreadPoolExecutor.DiscardPolicy:直接拒绝,什么也不做。

四. 线程池的工作流程

  1. 线程池刚创建时,线程池是一个空的,没有任何线程。
  2. 随着任务的提交,线程池开始创建线程:
    a. if (当前线程数 < corePoolSize) ,创建线程
    b. if (当前线程数 == corePoolSize) ,则把任务添加到工作队列中去
    c. 队列满了,if (当前线程数 < maximumPoolSize) ,创建线程(此时创建的为临时线程)
    d. 队列满了,if (当前线程数 == maximumPoolSize) ,执行拒绝策略
  3. 随着任务的执行,任务逐渐减少,线程有了空闲时间,则:
    if(空闲时间 > keepAliveTime && 当前线程数 > corePoolSize),则销毁线程,直到 当前线程数 == corePoolSize。

五. 使用Executors 创建常见的功能线程池

Executors为我们封装好了 4 种常见的功能线程池如下:

  1. 定长线程:FixedThreadPool
  2. 定时线程:ScheduledThreadPool
  3. 可缓存线程池:CachedThreadPool
  4. 单线程化线程池:SingleThreadExecutor

使用 Executors.newFixedThreadPool(10) 能创建出固定包含 10 个线程的线程池,该方法创建的线程池的返回值类型均为 ExecutorService。

定长线程:FixedThreadPool
源码:

    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

    public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),
                                      threadFactory);
    }

特点:定长线程池 核心线程数 == 最大线程数 ,即没有临时线程,且执行完毕会立刻回收,这种类型的线程池使用频率最高。

定时线程:ScheduledThreadPool
源码:

    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }
    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }

    public static ScheduledExecutorService newScheduledThreadPool(
            int corePoolSize, ThreadFactory threadFactory) {
        return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
    }
  **加粗样式** **加粗样式** public ScheduledThreadPoolExecutor(int corePoolSize,
                                       ThreadFactory threadFactory) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue(), threadFactory);
    }

特点:定时线程池的核心线程数量固定,虽然它的构造方法里面没有写最大线程的数量是多少,但是跟进查看源码可以知道,最大线程数量是等于 Integer.MAX_VALUE 的,工作队列是高度定制化的延迟阻塞队列DelayedWorkQueue,其实现原理和DelayQueue基本一样,核心数据结构是二叉最小堆的优先队列,队列满时会自动扩容,所以offer操作永远不会阻塞,maximumPoolSize也就用不上了,所以线程池中永远会保持至多有corePoolSize个工作线程正在运行。

可缓存线程池:CachedThreadPool
源码:

    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

    public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>(),
                                      threadFactory);
    }

特点:可缓存线程池的核心线程数 = 0,最大线程数为 Integer.MAX_VALUE ,它会在执行闲置60s后回收,任务队列为不储存元素的阻塞队列。适合于并发不固定的短期的小任务。

单线程化线程池:SingleThreadExecutor
源码:

    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

    public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>(),
                                    threadFactory));
    }

特点:单线程化线程池的核心线程数 == 最大线程数 == 1,执行完毕会立即回收,任务队列为链表结构的有界队列。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
LVS(Linux Virtual Server)是一种基于 Linux 系统的负载均衡集群技术,它主要用于将网络流量分发到多个服务器上,以提高系统的可靠性、可扩展性和性能。 LVS 集群一般包括四个组件:调度器(LVS 调度器)、前端服务器(负载均衡器)、后端服务器(真实服务器)和存储服务器(用于共享数据)。首先,调度器接收来自客户端的请求,然后根据配置的调度算法(如轮询、加权轮询、最小连接数等)将请求分发到多个前端服务器。前端服务器接收到请求后,通过相应的负载均衡算法将请求转发到后端的真实服务器上进行处理。在整个过程中,存储服务器用于存放共享的数据,以确保所有的真实服务器都能获取到相同的数据,并提供一致的服务。 LVS 集群的优点是能够提高网站的稳定性和可靠性,当某一台服务器出现故障时,调度器会自动将请求分发到其他可用的服务器上,从而保证服务的连续性。同时,LVS 集群还能够通过增加前端服务器和后端服务器的数量来提高系统的性能和吞吐量,以满足不断增长的用户需求。 在实际应用中,LVS 集群需要合理配置,包括选择合适的调度算法、调整每台服务器的权重、选择适当的硬件设备等。此外,还需要及时监控集群的运行状态,及时发现和解决故障,以确保整个系统的正常运行。 总的来说,LVS 负载均衡集群是一种强大而高效的集群技术,能够帮助企业提高系统的可靠性和性能,是现代互联网应用中不可或缺的重要组成部分。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木木是木木

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值