首页 > 其他分享 >线程池笔记

线程池笔记

时间:2023-10-24 18:14:51浏览次数:27  
标签:队列 核心 笔记 corePoolSize 任务 线程 超时

  1. 日常所说的“核心线程”、“非核心线程”是一个虚拟的概念,是为了方便描述而虚拟出来的概念
  2. 在代码中并没有标记哪些线程为“核心线程”或者“非核心线程”。所有线程都是一样的。

线程池是如何实现的?

  在Java中,线程池中所谓的“线程”,其实就是一个静态内部类Worker,它是基于AQS实现的,并实现Runnable。存放在线程池的HashSet<Worker> workers成员变量中。
  而需要执行的任务,则放在BlockingQueue<Runnable> workQueue中。这样,整个线程实现的基础思想就是:从workerQueue中获取任务,放在worker中进行处理。

静态内部类Worker:
private final class Worker extends AbstractQueuedSynchronizer implements Runnable {......}

线程池的核心参数

  • corePoolSize 核心线程数量
  • maximunPoolSize 最大线程数量 ,一般 maximunPoolSize > corePoolSize
  • keepAliveTime 空闲线程的存活时间
  • 存活时间单位
  • workQueue 任务队列(共计5种,按照不同的业务场景使用不同的队列)
  • RejectedExecutionHandler 拒绝策列

线程池的线程会在何时创建与销毁

创建

首先,线程池在创建之初并不会创建线程当任务来临后才会创建第一个线程,每次创建线程都是做出如下判断:

  1. 如果正在运行的线程数量 < corePoolSize,那么马上创建线程运行这个任务;
  2. 如果正在运行的线程数量 >= corePoolSize,那么将这个任务放入队列;
  3. 如果这时候队列满了,而且正在运行的线程数量 < maximumPoolSize,那么还是要创建非核心线程立刻运行这个任务;
  4. 如果队列满了,而且正在运行的线程数量 >= 于maximumPoolSize,那么线程池会抛出异常RejectExecutionException。

销毁

  当空闲线程大于空闲存活时间,就会销毁掉。直到线程数量等于核心线程数。剩下的线程就是核心线程。

核心线程是否能销毁

  ThreadPoolExecutor中存在一个参数allowCoreThreadTimeOut,此参数表示是否允许核心线程超时,默认为 false,所以一般情况下,是不会销毁的。
  如果调整参数,是可以做到销毁核心线程的。

核心方法- getWork() 获取任务方法

当线程完成当前任务后,会进入死循环,不断的尝试获取任务。

  • 如果 生存时间 > keepAliveTime,会返回 null
  • 如果 生存时间 < keepAliveTime,会阻塞获取
// 线程池源码,获取任务
// 为分析而简化后的代码
private Runnable getTask() {
    boolean timedOut = false;
    for (;;) {
        int c = ctl.get();
        int wc = workerCountOf(c);

        // timed变量用于判断是否需要进行超时控制。
        // allowCoreThreadTimeOut默认是false,也就是核心线程不允许进行超时;
        // wc > corePoolSize,表示当前线程池中的线程数量大于核心线程数量;
        // 对于超过核心线程数量的这些线程,需要进行超时控制
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

        if (timed && timedOut) {
            // 如果需要进行超时控制,且上次从缓存队列中获取任务时发生了超时,那么尝试将workerCount减1,即当前活动线程数减1,
            // 如果减1成功,则返回null,这就意味着runWorker()方法中的while循环会被退出,其对应的线程就要销毁了,也就是线程池中少了一个线程了
            if (compareAndDecrementWorkerCount(c))
            return null;
            continue;
        }

        try {
            Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take();

            // 注意workQueue中的poll()方法与take()方法的区别
            //poll方式取任务的特点是从缓存队列中取任务,最长等待keepAliveTime的时长,取不到返回null
            //take方式取任务的特点是从缓存队列中取任务,若队列为空,则进入阻塞状态,直到能取出对象为止

            if (r != null) return r;
            timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
        }
    }
}

线程池的拒绝策略

在添加工作任务时,工作队列满后,会执行拒绝策略(都是静态内部类

  • AbortPolicy:直接抛出拒绝异常,默认项
  • CallerRunsPolicy:由线程池的调用者线程去执行多余的方法,串行执行。场景:所有任务都要执行。
  • DiscardOledestPolicy:放弃等待队列中最老的数据,迎接新的数据
  • DiscardPolicy:直接无视,不做任何处理。不添加队列,不报错,不做标识

逻辑:查看 ThreadPoolExcutor.java 文件中 public void execute(Runnable var1) {......} 方法

标签:队列,核心,笔记,corePoolSize,任务,线程,超时
From: https://www.cnblogs.com/zz-1q/p/17785416.html

相关文章

  • 什么是线程池?工作中线程池的应用
    一、什么是线程池简单理解,它就是一个管理线程的池子。它帮我们管理线程,避免增加创建线程和销毁线程的资源损耗。因为线程其实也是一个对象,创建一个对象,需要经过类加载过程,销毁一个对象,需要走GC垃圾回收流程,都是需要资源开销的。提高响应速度。如果任务到达了,相对于从线程池拿线程,......
  • 专题课笔记:深度学习的基础、应用与挑战
    模块一:深度学习基础1.1感知机与多层感知机感知机:Rosenblatt的基础神经网络模型,于1957年提出。多层感知机:在感知机基础上引入隐藏层和激活函数,为深度学习奠定基础。1.2卷积神经网络(CNN)原理与结构:LeNet-5是最早的CNN之一,但真正崭露头角是在2012年AlexNet在ImageNet竞赛中的胜利......
  • 为什么单线程Redis能那么快
    单线程澄清Redis的单线程,指的是Redis的键值对读写由一个线程来完成。Redis的多线程:持久化异步删除集群数据同步网络IO(Redis6.0引入,5.0及之前都是单线程)......
  • 线程池
    codeimportosimporttimefromconcurrent.futures.threadimportThreadPoolExecutordeftest(n):print(f'n:{n}-os.getpid:{os.getpid()}')time.sleep(2)return'hello'#定义一个回调函数,异步提交完后,有结果自动调用该函数defcall_back(n):p......
  • 《代码大全》阅读笔记03
    第五章:软件构建中的设计1、软件的首要技术使命就是管理复杂度,以简单性作为努力目标的标记方案对此最有帮助。2、好的设计是迭代的,你尝试设计的越多,你的最终方案就会约好。3、隐藏实现、封装变化。 第六章:可以工作的类1、类的接口应该提供一致的抽象。很多问题都是由于违背......
  • 升讯威在线客服系统的并发高性能数据处理技术:为多线程处理同步数据
    我在业余时间开发维护了一款免费开源的升讯威在线客服系统,也收获了许多用户。对我来说,只要能获得用户的认可,就是我最大的动力。最近客服系统成功经受住了客户现场组织的压力测试,获得了客户的认可。客户组织多名客服上线后,所有员工同一时间打开访客页面疯狂不停的给在线客服发消......
  • 在C++中,互斥变量(std::mutex)是用于保护共享资源的重要工具,但它们确实有一些局限性,其中
    在C++中,互斥变量(std::mutex)是用于保护共享资源的重要工具,但它们确实有一些局限性,其中之一是无法保证包含指针的区域的多线程安全。这是因为互斥锁本质上只能保护它们所保护的代码块,而不会考虑指针指向的数据。下面是一些与互斥锁和指针相关的常见问题和注意事项:共享数据的复制:......
  • 有道云笔记之备选方案Obsidian和Notion
    有道云笔记限制登录设备在商业项目中一般都会有plana、planb,对于云笔记,我也在寻找planb,有道云笔记在国内市场已经占据了很大的份额。同类型中的就不再去挑选了,我觉得商业软件,迟早也会走到有道云笔记这一步的,早在很多年前就目睹了为知笔记收费迁移到有道云笔记。在知乎上看到很多推......
  • Chromium 消息循环和线程池详解
    Chromium中的多线程机制由base库提供,要理解Chromium中的多线程机制,首先要理解的概念就是 base::MessageLoop 和 base::TaskScheduler ,它们两个是Chromium多线程的基础1. MessageLoop详解base::MessageLoop 代表消息循环,它不会主动创建新的线程,默认情况下它使用当前......
  • Java使用多线程异步执行批量更新操作方法
    一、核心技术Java提供了Executor框架来实现多线程任务的执行。我们可以通过创建ExecutorService对象来管理线程池,然后将任务提交给这个线程池执行。Executor框架的优点在于,它可以自动管理线程数量,以最大化利用CPU和内存资源。二、具体实现方法1、创建一个数据更新任务类,实现Run......