首页 > 其他分享 >聊一聊关于线程池的那些事情

聊一聊关于线程池的那些事情

时间:2024-05-13 18:41:46浏览次数:21  
标签:队列 核心 keepAliveTime 任务 聊一聊 线程 关于 执行

 

在现代软件开发中,线程池是一种广泛应用的并发执行模式,尤其在处理大量短暂异步任务的场景中,线程池能够提高程序性能,减少资源消耗。本文将深入探讨Java线程池的工作原理,包括其核心参数、执行过程以及应用场景等方面。

一、线程池的核心参数
Java线程池在java.util.concurrent包下的ThreadPoolExecutor类中实现。创建线程池时,可以通过构造函数指定七个参数,分别控制线程池的行为:

线程池的配置参数对于其性能和效率具有重要影响。以下是线程池配置的七个关键参数:

(1)核心线程数(corePoolSize):线程池中的基本线程数,即使在线程处于空闲状态时,也不会被销毁,除非设置了allowCoreThreadTimeOut。

(2)最大线程数(maximumPoolSize):线程池中允许的最大线程数。当工作队列已满,且正在执行的线程数等于核心线程数时,线程池会创建新的线程来处理任务,直到线程数达到最大线程数。

(3)队列容量(workQueue):用于存放待执行的任务的队列。当提交的任务数超过核心线程数时,新任务会被存放在队列中等待执行。

(4)线程空闲时间(keepAliveTime):当线程数大于核心线程数时,这是多余空闲线程在终止前等待新任务的最长时间。

(5)时间单位(unit):keepAliveTime参数的时间单位,如TimeUnit.SECONDS。

(6)线程工厂(ThreadFactory):用于创建新线程的工厂,可以通过自定义线程工厂来设置新创建线程的名称、优先级、是否为守护线程等。

(7)拒绝策略(RejectedExecutionHandler):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。当然,Java提供了四种策略:直接抛出异常、使用调用者所在的线程来运行任务、丢弃队列中最靠前的任务,然后尝试再次执行任务、直接丢弃任务。

 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
        this.ctl = new AtomicInteger(ctlOf(-536870912, 0));
        this.mainLock = new ReentrantLock();
        this.workers = new HashSet();
        this.termination = this.mainLock.newCondition();
        if (corePoolSize >= 0 && maximumPoolSize > 0 && maximumPoolSize >= corePoolSize && keepAliveTime >= 0L) {
            if (workQueue != null && threadFactory != null && handler != null) {
                this.corePoolSize = corePoolSize;
                this.maximumPoolSize = maximumPoolSize;
                this.workQueue = workQueue;
                this.keepAliveTime = unit.toNanos(keepAliveTime);
                this.threadFactory = threadFactory;
                this.handler = handler;
            } else {
                throw new NullPointerException();
            }
        } else {
            throw new IllegalArgumentException();
        }
    }

  

 

二、线程池的执行过程

线程池的执行过程可以分为以下几个步骤:

  1. 当提交一个新任务到线程池时,线程池首先判断核心线程数是否已满。如果未满,则创建一个新线程执行任务;如果已满,则进入下一步。

  2. 如果核心线程数已满,线程池会检查工作队列是否已满。如果队列未满,则将新任务添加到队列中等待执行;如果队列已满,则进入下一步。

  3. 如果工作队列已满,线程池会判断当前线程数是否已达到最大线程数。如果未达到,则创建一个新线程执行任务;如果已达到,则根据设置的拒绝策略处理新任务。

   4.在线程执行任务的过程中,如果线程空闲时间超过了设定的keepAliveTime,且当前线程数大于核心线程数,那么多余的线程将被销毁,以释放系统资源。

 

三、线程池的管理与调优
合理配置线程池的参数对于提高应用程序的性能至关重要。以下是一些管理和调优线程池的建议:

  1.合理设置核心和最大线程数:核心线程数应该根据系统资源和任务类型来设置。最大线程数则应考虑到系统的负载能力,避免过多线程竞争资源导致的性能下降。

  在CPU密集型任务中,核心线程数一般设置为CPU核心数或CPU核心数加一,而在IO密集型任务中,核心线程数则设置为2倍的CPU核心数或CPU核心数除以(1-阻塞系数)

  2.选择合适的工作队列:根据任务的性质选择合适的队列类型,如无界队列、有界队列等。
  3.合理配置线程存活时间:对于非核心线程,合理的存活时间可以避免频繁创建和销毁线程所带来的开销。
  4.定制拒绝策略:根据应用场景选择或定制拒绝策略,合理处理无法立即执行的任务。

 

四、线程池的优势与潜在问题

  1. 线程池的优势

(1)降低系统开销:通过复用线程,避免了频繁创建和销毁线程所带来的开销,提高了系统的响应速度和吞吐量。

(2)提高资源利用率:线程池能够根据实际任务量动态调整线程数量,充分利用系统资源,避免资源浪费。

(3)简化编程:线程池提供了一套完整的线程管理机制,使得开发者无需关心线程的创建、销毁和调度等细节,降低了编程复杂度。

  1. 线程池的潜在问题

(1)线程数量配置不当:线程池大小设置不合理可能导致资源浪费或任务处理不及时。

(2)任务依赖问题:如果任务之间存在依赖关系,线程池可能无法正确地处理这些依赖关系。

(3)线程安全问题:多线程环境下,共享资源的访问需要谨慎处理,以避免竞态条件和死锁等问题。


结论
线程池是处理并发任务的强大工具,但它也需要根据具体的应用场景进行细致的配置和管理。理解线程池的工作原理和参数含义,可以帮助开发者更好地利用线程池提高应用程序的性能和稳定性。希望本文能为您深入理解线程池提供一定的帮助。

标签:队列,核心,keepAliveTime,任务,聊一聊,线程,关于,执行
From: https://www.cnblogs.com/zaevn00001/p/18112356

相关文章

  • libuv线程
    1、概述  libuv的线程API与Linux的pthread的API在使用方法和语义上很接近,因为要跨平台,所以libuv支持的线程API个数很有限。libuv中只有一个主线程,主线程上只有一个eventloop。如下为创建线程的一个简单示例:#include<stdio.h>#include<uv.h>voidthread_fun(void*arg)......
  • 关于str.split()[0]的详细讲解
    示例代码:输入:>>>str="helloboy<[www.doiido.com]>byebye"输入:>>>str.split("[")[1].split("]")[0]输出:'www.doiido.com'解释:split(“[”)表示以“[”为分隔符。**[1]**表示获取“[”之后的内容。split(“]”)表示以“]”为分隔符。[0]表示获取“]”之前的内容再......
  • C#异步与多线程
    c#的异步与多线程异步与多线程首先,异步是相对于同步的一个概念,在同步环境下,程序允许至某处需要等待的位置,会发生阻塞,直到达到条件才会继续向下运行;而异步操作则可以在需要等待的位置,跳过等待,执行其他内容,通常异步处理的事务不能相互存在影响。多线程指的是,同时使用多个线程执行......
  • WinForm中UI控件不支持从非创建控件的线程进行访问
    背景在WindowsForms应用程序中,UI控件(如按钮、文本框等)被设计为不支持从非创建控件的线程(通常是主UI线程)进行访问。尝试从其他线程访问UI控件会导致不可预测的行为,包括应用程序崩溃。Control.CheckForIllegalCrossThreadCalls属性用于在调试过程中帮助开发者发现这类潜在问......
  • mybatis多线程插入数据表已经事务回滚
    importlombok.extern.slf4j.Slf4j;importorg.apache.commons.collections4.CollectionUtils;importorg.apache.commons.collections4.ListUtils;importorg.apache.ibatis.session.ExecutorType;importorg.apache.ibatis.session.SqlSession;importorg.apache.ibati......
  • C#多线程
    目录C#线程概述定义程序、进程、线程基本语法C#可以通过Thread、ThreadPool、Task(推荐)创建线程。前台线程和后台线程共享数据保护机制优缺点/应用场景优缺点常见的应用场景总结C#线程概述定义线程(thread)是计算机科学中将进程划分为两个或多个线程(实例)或子进程,由单处理器(单线程......
  • C#的关于窗体的类库方案 - 开源研究系列文章
          这次想到了以前编写的关于应用的那个类库,不过当时的只是定义了显示接口,然后调用窗体显示。现在想到要把这个关于窗体的类库进行集合,统一调用,于是就把原来的代码进行了修改完善,终于得到了这次这个例子。      这个例子主要实现了4种关于窗体的形式。第1种为普......
  • 关于为随机函数PRF的入门认知
    伪随机函数(PseudoRandomFunction,即PRF)在密码学中是一个重要的概念,是一个基础的密码学原语。基本概念PRF是一个确定性的函数。我们记定义在$(K,X,Y)$上的函数$F$,其中$K$是密钥空间,$X$和$Y$分别是输入和输出空间。对于PRF,给定确定的密钥k,函数$F$应该看上去是一个定义在$X\rig......
  • 关于病给与我的苦情诗
    关于病给与我的苦情诗cage宣布与「流感」成为宿敌。似乎离不开我的不仅仅有学不会的数学,还有这春去秋来的病。时运不济啊,突如其来的感冒打扰到我平静的生活,似乎开始在平静的生活中再度掀起涟漪。我不得不更早的睡,却更晚的入眠;我不得不喝更多的水,吃更多的药,却得到更“惨烈”......
  • 线程池中抛出的异常,主线程可以catch到吗
    印象中,线程池抛出的异常主线程可以catch到,但前段时间碰到个问题,在系统出现异常时,由于线程池任务中没有catch异常的代码,主线程虽有catch异常代码,但却没有catch到异常,导致排查问题比较费劲。故对此处进行研究,并记录。一、JVM异常处理先来看一下jvm对未捕获的异常如何处理1......