JAVA线程池理解

线程池的优势

解决资源开销避免重复的new Thread对象,重复使用一个线程对象。

用户线程(UT),内核线程(KLT)

用户线程: 应用层自己管理线程
内核线程:操作系统管理线程

JVM hostport使用的是什么线程

内核线程(KLT)

ThreadPoolExector线程池参数

  1. 核心线程数(corePoolsize)
  2. 最大线程数(MaxmumpoolSize)
  3. 线程生存时间(keepAliveTime)
  4. 生存时间单位(unit)
  5. 工作队列(wordQueue)

阻塞队列 > (假设队列满了,所有入列操作必须等待,也就是被堵塞。 如果队列为空,只能进行入列操作,所有出列操作必须等待,也就是被堵塞)

  1. 线程工程(ThreadFactory)
  2. 拒绝策略(handler)

如何最大线程数和队列全部占满如何处理的方式

  1. AbortPolicy(默认策略)
    这是默认的拒绝策略。当线程池饱和时,新任务的提交将会抛出RejectedExecutionException,通知调用者发生了拒绝。
  2. CallerRunsPolicy(调用者线程中执行)
    当线程池饱和时,新任务会在调用者线程中直接执行。这种策略可能会导致调用者线程被阻塞,因为它本来可能想要提交新的任务。
  3. DiscardPolicy(直接丢弃任务)
    当线程池饱和时,新任务将被丢弃,没有任何处理。这可能导致丢失任务,不推荐在需要完全处理所有任务的情况下使用
  4. DiscardOldestPolicy (丢弃最早的任务)
    当线程池饱和时,尝试将最早加入队列的任务丢弃,以便为新任务腾出空间。

线程池存放过程和执行过程

  1. 提交存放过程
    在这里插入图片描述

顺序 核心线程 —> 阻塞队列 —> 最大线程

  1. 流程解释

当任务提交之后,线程池首先会检查当前线程数,如果当前的线程数小于核心线程数(corePoolSize),比如最开始创建的时候线程数为 0,则新建线程并执行任务。
当提交的任务不断增加,创建的线程数等于核心线程数(corePoolSize),新增的任务会被添加到 workQueue 任务队列中,等待核心线程执行完当前任务后,重新从 workQueue 中获取任务执行。
假设任务非常多,达到了 workQueue 的最大容量,但是当前线程数小于最大线程数(maximumPoolSize),线程池会在核心线程数(corePoolSize)的基础上继续创建线程来执行任务。
假设任务继续增加,线程池的线程数达到最大线程数(maximumPoolSize),如果任务继续增加,这个时候线程池就会采用拒绝策略来拒绝这些任务。

线程池生命周期

在这里插入图片描述
Running
能接受新任务以及处理已添加的任务
Shutdown
不接受新任务,可以处理已经添加的任务
Stop
不接受新任务,不处理已经添加的任务,并且中断正在处理的任务
Tidying
所有的任务已经终止,记录的”任务数量”为0,负责记录线程池的运行状态与活动线程数量
Terminated
线程池彻底终止,则线程池转变为terminated状态

线程池是如何实现线程的复用

代码

    final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // 释放锁 设置work的state=0 允许中断
        boolean completedAbruptly = true;
        try {
            //一直执行 如果task不为空 或者 从队列中获取的task不为空
            while (task != null || (task = getTask()) != null) {
                    task.run();//执行task中的run方法
                }
            completedAbruptly = false;
        } finally {
            //1.将 worker 从数组 workers 里删除掉
            //2.根据布尔值 allowCoreThreadTimeOut 来决定是否补充新的 Worker 进数组 workers
            processWorkerExit(w, completedAbruptly);
        }
    }

解释:

可以看到,实现线程复用的逻辑主要在一个不停循环的 while 循环体中。
通过获取 Worker 的 firstTask 或者通过 getTask 方法从 workQueue 中获取待执行的任务
直接通过 task.run() 来执行具体的任务(而不是新建线程),一个线程在一个while中不停的执行其他run方法从而实现线程复用。

  • 35
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值