Java并发编程(五)—线程池ThreadPoolExecutor详解

ThreadPoolExecutor创建线程池详解 该接口是真正的线程池接口。上面的ThreadPoolExecutor以及下面的都是该接口的实现类。Future submit(Runnable task):提交Runnable任务到线程池,返回Future对象,由于Runnable没有返回值,也就是说调用Future对象get()方法返回null。Future submit(Callable task):提交Callable任务到线程池,返回Future对象,调用Future对象get()方法可以获取Callable的返回值。 阅读详情

前言

在Java并发场景下,Java线程池是最经常运用的并发框架,而且在诸如Tomcat、数据库等工具中也都用到了Java线程池。合理地使用线程池可以给编程带来很多好处。

  • 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
  • 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
  • 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统稳定性,使用线程池可以统一分配、调用和监控。

线程池的结构组成

线程池的结构主要指的是线程池的大小、任务队列、饱和策略。

  • 线程池的大小:corePoolSize(线程池的基本大小)是线程池中保持活动的最小线程数。maximumPoolSize(线程池最大数量)是线程池允许创建的最大线程数。
  • 任务队列:用于存储等待处理的任务,任务队列时阻塞队列。常用的任务队列有:ArrayBlockingQueue,一个基于数组结构的有界阻塞队列,按照FIFO原则对任务进行排序;LinkedBlockingQueue,一个基于链表结构的阻塞队列,按照FIFO原则对任务进行排序;SynchronousQueue,一个不存储任务的阻塞队列,每加入一个任务后需要等到任务被线程移出处理后才能加入下一个任务。
  • 线程工厂(ThreadFactory):线程工厂用于创建线程池中的线程。
  • 饱和策略(RejectedExecutionHandler):当线程池满了以后(线程达到最大线程数,任务队列也满的情况下)采用的任务处理策略。默认策略是AbortPolicy,直接抛出异常。除此之外还有,CallerRunsPolicy,只用调用者所在线程来运行任务;DiscardOldestPolicy,丢弃任务队列里最近的一个任务,并执行当前任务;DiscardPolicy,不处理,直接丢弃。
  • 线程活动保持时间(KeepAliveTome):线程池的工作线程空闲后,保持存活的时间。

线程池的工作流程

在程序中向线程池提交任务时,线程池就开始了工作。

  1. 向线程池提交一个新任务,判断核心线程池(corePoolSize个的线程)里的线程是否都在工作,如果不是,则创建一个新的工作线程来执行任务。如果核心线程池里面的线程都在执行任务,进入下一步;
  2. 线程池工作队列是否已满。如果工作队列没有满,将任务加入到工作队列。如果工作队列已满,进入下一步。
  3. 再次判断线程池中的线程是否都处于工作状态。如果没有,则创建一个新的工作线程来执行任务。如果都在运行,执行饱和策略。

在这里插入图片描述

通过源码看ThreadPoolExecutor执行原理

我们从提交任务开始分析。使用ThreadPoolExecutor时调用execute()方法提交任务。在介绍执行原理的之前,线介绍ThreadPoolExecutor的一个重要属性ctl。这个属性是一个AtomicInteger类型的数据。它的主要作用是记录当前线程池中运行线程的数量以及线程池的状态。其中前4位记录运行状态,后28位记录线程最大数量。

private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int COUNT_MASK = (1 << COUNT_BITS) - 1; //等于2^29-1
//判断线程池状态
 private static int runStateOf(int c)     { return c & ~COUNT_MASK; }
 
 /**
  * 状态有RUNNING、SHUTDOWN、STOP 、TIDYING、TERMINATED         
  */
 private static final int RUNNING    = -1 << COUNT_BITS;
 private static final int SHUTDOWN   =  0 << COUNT_BITS;
 private static final int STOP       =  1 << COUNT_BITS;
 private static final int TIDYING    =  2 << COUNT_BITS;
 private static final int TERMINATED =  3 << COUNT_BITS;
 //计算运行状态的线程数量
 private static int workerCountOf(int c)  { return c & COUNT_MASK; }
public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        /*
         * Proceed in 3 steps:
         *
         * 1. 如果正在运行少于corePoolSize数量的线程,则创建一个新的线程执行任务。
         *  然后调用addWorker以原子操作的方式检查(runState)线程工作状态和(workCount)工作线程数量。
         *  通过返回false来确定在此时不应该添加线程。
         *
         * 2.如果任务可以加入到队列中,那么我们仍然需要检查是否应该添加一个线程
         * (因为自上次检查后现有的线程可能已经死亡),
         *  或者自从进入此方法后池关闭了。 
         *  所以我们重新检查状态,如果必要的话,如果没有则回滚入队,或者如果没有,则启动新的线程。
         *
         * 3.如果工作队列已满,再次尝试添加一个新线程。 
         *  如果失败,执行饱和策略。
         */
        int c = ctl.get(); //获取线程数量状态位,通过workerCountOf()方法获取运行的线程数量
        //当前运行线程小于corePoolSize
        if (workerCountOf(c) < corePoolSize) {
        	//为true,新建线程执行任务
            if (addWorker(command, true))
                //任务加入线程池成功
                return;
            c = ctl.get();
        }
        //1.尝试加入到工作队列中 isRunning{c < SHUTDOWN}是判断线程池是否在运行
        //2.因为ctl.get()的初始值时 RUNNING | 0位负数(也只有RUNNING状态的值为负数)
        //3.将任务加入到工作队列中
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        //再次尝试执行任务
        else if (!addWorker(command, false))
        	//失败则执行饱和策略
            reject(command);
    }
/**
 * 向线程池加入任务
 */
private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (int c = ctl.get();;) {
            // Check if queue empty only if necessary.
            //判断线程池状态
            if (runStateAtLeast(c, SHUTDOWN)  
                && (runStateAtLeast(c, STOP)
                    || firstTask != null
                    || workQueue.isEmpty()))
                return false;

            for (;;) {
                if (workerCountOf(c)
                    >= ((core ? corePoolSize : maximumPoolSize) & COUNT_MASK))
                    return false;
                    //通过原子操作增加线程运行数量
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                c = ctl.get();  // Re-read ctl
                if (runStateAtLeast(c, SHUTDOWN))
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
            }
        }

        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
        	//初始化新的Worker,包括新的工作线程
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    int c = ctl.get();

                    if (isRunning(c) ||
                        (runStateLessThan(c, STOP) && firstTask == null)) {
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        workers.add(w);
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                	//开始任务工作
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

以上就是线程池执行任务的主要代码逻辑。

说完线程池的运行流程后,还有个细节就是线程池的keepAlive机制。我们知道,线程池有个重要的参数是keepAliveTime,它的含义是规定时间内,如果当前运行的线程数量大于corepoolSize时,空闲线程在keepAliveTime的时间内没取到任务时就结束线程。

final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
           //获取task
            while (task != null || (task = getTask()) != null) {
                w.lock();
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                    beforeExecute(wt, task);
                    try {
                        task.run();
                        afterExecute(task, null);
                    } catch (Throwable ex) {
                        afterExecute(task, ex);
                        throw ex;
                    }
                } finally {
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            //线程退出
            processWorkerExit(w, completedAbruptly);
        }
    }

上面的代码我们可以看到在获取不到task时线程就会退出。其中task是提交是的任务,这个任务执行完以后,就开始从getTask()方法中获取。我们看下getTask()方法。

private Runnable getTask() {
        boolean timedOut = false; // Did the last poll() time out?

        for (;;) {
          //......
          // Are workers subject to culling?
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }
            try {
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : //keepAliveTime时间内获取不到就返回null
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

上面的代码不难理解,在工作队列中,通过poll()方法获取task,如果keepAliveTime时间内获取不到就继续循环获取任务,在接下来的循环中,timeOut设置为true,可以看到如果工作队列没有任务排队时,会返回null。这个时候while循环结束,会执行processWorkerExit()方法清除线程。

线程池的使用

《阿里Java开发规范》中提到的三条建议

首先说一下《阿里Java开发规范》中提到的三条建议。

  1. 【强制】创建线程或线程池时请指定有意义的线程名称,方便出错时回溯。
  2. 【强制】线程资源必须通过线程池提供,不允许在应用中自行显式创建线程。 说明:使用线程池的好处是减少在创建和销毁线程上所花的时间以及系统资源的开销,解决资源不足的问题。如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或者“过度切换”的问题。
  3. 线程池不允许使用 ExecutorsExecutors去创建,而是通过ThreadPoolExecutor去创建,这样的处理方式让写同学更加明确线程池运行规则,避资源耗尽风险。
    说明: Executors返回的线程池对象的弊端 如下 :
    1)FixedThreadPool和 SingleThreadPoolPool: 允许的请求队列长度为 Integer.MAX_VALUE,可 能会堆积大量的请求,从而导致 OOM。
    2)CachedThreadPool 和 ScheduledThreadPool : 允许的创建线程数量 为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。
线程池的主要参数配置

《阿里Java开发规范》关于线程池的使用主要是强调通过更多参数的设定使线程池有更强的操作性和可管理性。那么线程池ThreadPoolExecutor都有哪些主要的参数呢?

  • corePoolSize(线程池的基本大小)是线程池中保持活动的最小线程数。
  • 任务队列:用于存储等待处理的任务,任务队列时阻塞队列。常用的任务队列有:ArrayBlockingQueue,一个基于数组结构的有界阻塞队列,按照FIFO原则对任务进行排序;LinkedBlockingQueue,一个基于链表结构的阻塞队列,按照FIFO原则对任务进行排序;SynchronousQueue,一个不存储任务的阻塞队列,每加入一个任务后需要等到任务被线程移出处理后才能加入下一个任务。建议使用有界队列,可以增加稳定性,无界队列在异常情况下可能会导致无限的加入任务使程序崩溃
  • 线程工厂(ThreadFactory)用于创建线程池中的线程,可以确定线程的属性名称等。
  • 饱和策略(RejectedExecutionHandler,当线程池满了以后(线程达到最大线程数,任务队列也满的情况下)采用的任务处理策略。默认策略是AbortPolicy,直接抛出异常。除此之外还有,CallerRunsPolicy,只用调用者所在线程来运行任务;DiscardOldestPolicy,丢弃任务队列里最近的一个任务,并执行当前任务;DiscardPolicy,不处理,直接丢弃。
  • 线程活动保持时间(KeepAliveTome):线程池的工作线程空闲后,保持存活的时间。如果任务很多,并且任务执行的时间较短,可以调大时间,提高线程的利用率。
合理的配置线程池
要合理的配置线程池,可以根据以下几方面来分析:
  • 任务的性质:CPU密集型任务、IO密集型任务、混合任务
  • 任务的优先级:高、中、低等
  • 任务的执行时间:长、短
  • 任务的依赖性:是否依赖其他系统资源,如数据库连接

一点建议:比如CPU密集型任务则需要配置较少的线程。因为任务会使用大量CPU资源,过多的线程可能会造成CPU压力过大,导致线程切换频繁,从而效率变低。一般配置N+1个线程(N是CPU的数量)。IO密集型任务会有大量时间等待IO操作,所以可能多配置一些线程。比如2N个线程(N是CPU的数量)。

总结

线程池在并发编程中是很重要的角色。合理的使用线程池可以提高程序运行效率,并且帮助我们方便的管理和监控线程的运行。所以了解线程池的运行原理是必须的。这里主要介绍了线程池的执行流程并且从源码角度分析了运行原理。

参考资料:《Java并发编程的艺术》、《Java编程思想》、《阿里Java开发规范》
无人机精准降落辅助系统核心技术解析 接近地面时(<10米)切换至基于图像的视觉伺服(IBVS),依据图像特征点偏移(如靶标图案、LED标记)微调姿态,消除位置累积误差。通过SRUKF(平方根无迹卡尔曼滤波) 算法融合三类数据,输出6自由度位姿估计(精度达厘米级),抑制单一传感器噪声。权值根据信噪比动态调整。模型预测控制(MPC):针对斜坡降落,构建包含平台倾角、风扰的动力学方程,滚动求解最优油门序列。动态照明适配:针对夜间或低光照场景,系统向降落平台发送亮度调节指令,如增强红外信标强度或调整可见光LED阵列,确保特征识别鲁棒性。 阅读详情

相关推荐

【SPSS操作】Non-parametric ANCOVA (Quade‘s) in SPSS

在SPSS中执行Quade的非参数ANCOVA需要手动计算步骤,因为SPSS没有内置的菜单选项。以下是详细的操作指南。

weixin_43689393的博客 1278

多线程处理大数据量数据

最近公司需要一个新的需求,需要一个接口去跑数据。数据量还蛮大的,大约50-60万数据(一条一条执行),其中还涉及到与其他接口的交互,因此这些数据跑下来要耗时很久,因此设计了一个方案,使用多线程的方式进行处理。 方案1 每次重数据库表中取一定量的数据(自己按实际情况定义)放在线程池缓存队列里,启动10个线程去线程池里去取数据。(相当于生产者和消费者的关系),这里需要有一个触发点,当我缓存里没有数据时,需要再次从数据库中再次获取数据。 方案2 在数据库表中添加一个线程号字段,用来记录该条数据...

码代码的小朋友 6445

并网逆变器学习笔记5---三电平DPWM

三电平DPWM

圆桌骑士的博客 1万+

线程池工具类

阿里文档推荐使用自定义线程池,因为java自带线程池都会有可能造成内存不足的问题。自定义线程池,根据服务器配置定制线程池核心线程、最大线程等,是最好的方式。

qq_36138652的博客 3262

OpenWrt虚拟机磁盘扩容实战:从SquashFS到ext4的完整避坑指南

本文详细介绍了OpenWrt虚拟机磁盘扩容的完整流程,重点对比了SquashFS和ext4文件系统在扩容操作上的关键差异。通过五步安全迁移法和直接分区调整方案,帮助用户有效解决磁盘空间不足问题,同时提供高级技巧和故障排除指南,确保扩容过程顺利无坑。

weixin_29251131的博客 230

fatal: unable to access ‘https://github.com/Stability-AI/stablediffusion.git/‘解决方案

本文主要介绍在安装 stable-diffusion-webui 时出现的 fatal: unable to access 'https://github.com/Stability-AI/stablediffusion.git/': Failed to connect to github.com port 443 after 21071 ms: Couldn't connect to server 问题的解决方案,希望能对你有所帮助。

水滴的博客 5685

Java线程池ThreadPoolExecutor详解(一篇就够了)

Executor框架主要由三部分组成,任务,任务的执行者,执行结果,ThreadPoolExecutor和ScheduledThreadPoolExecutor的设计思想也是将这三个关键要素进行了解耦,将任务的提交和执行分离。任务在和中任务是指实现了Runnable接口和Callable接口的类,中将任务转换成FutureTask类,中任务被转换成类,该类继承FutureTask,并重写了run方法,实现了延时执行任务和周期性执行任务。任务的执行者包括任务执行机制的核心接口Executor的接口的和。...

m0_67401270的博客 3259

【图论】系列(七)图论的中心性度量方法及重要性评价指标

图论中的中心性度量方法是用来衡量图中各个节点(或顶点)相对重要性的指标。

qq_30066733的博客 1075

Java并发编程 之线程池ThreadPoolExecutor详解

文章目录线程池定义使用案例ThreadPoolExecutor 参数详解Executors 线程池工厂工具类 线程池定义 java.util.concurrent.ThreadPoolExecutor 使用案例 package fireland.yangqian.thread; import java.util.Random; import java.util.concurrent.Execu...

const_ 8016

电路中的DGND、GROUND、GROUND_REF的区别,VREF、VCC、VDD、VEE和VSS的区别?

DGND是数字地,是数字电路部分的公共基准端,用于连接数字电路的接地。

XU157303764的博客 2338

计算机网络实验报告实验七可靠传输TCP协议分析

计算机网络实验报告实验七可靠传输TCP协议分析

m0_56638814的博客 966

线程池的单例模式实现

在实际应用中,可以根据具体需求,使用不同的线程池类型和配置。你可以根据应用场景选择适合的线程池类型,如 CachedThreadPool、SingleThreadExecutor 等,并根据具体需求进行线程池的配置。在上述示例中,我们使用了懒汉式的单例模式实现,即在需要时才创建线程池实例。通过 getInstance() 方法获取线程池实例,如果实例尚未创建,则会在该方法内部创建一个新的线程池实例。线程池的单例模式实现是为了确保在整个应用程序中只有一个线程池实例,从而避免资源浪费和重复创建。

kankan_s的专栏 655

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

java线程池使用详解ThreadPoolExecutor使用示例

一 使用线程池的好处 二 Executor 框架 2.1 简介 2.2 Executor 框架结构(主要由三大部分组成) 1) 任务(Runnable /Callable) 2) 任务的执行(Executor) 3) 异步计算的结果(Future) 2.3 Executor 框架的使用示意图 三 (重要)ThreadPoolExecutor 类简单介绍 3.1 ThreadPoolExecutor 类分析 3.2 推荐使用 ThreadPoolExecutor 构造函数创建线程池 四 ..

xu_yong_lin的博客 5万+

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

JUC并发编程之ThreadPoolExecutor线程池详解

复习了一下的知识,今天来总结下ThreadPoolExecutor线程池。

ghost_spuerman的博客 1243

Java并发编程:ThreadPoolExecutor常用线程池

目录 线程池的分类 常用线程池(ThreadPoolExecutor)示例 CachedThreadPool FixedThreadPool SingleThreadExecutor ThreadPoolExecutor类分析 三种线程池(返回ThreadPoolExecutor)构造方法 ThreadPoolExecutor中的成员变量 三种线程池(返回ThreadPoolEx...

Jodness' Blogs 1万+

并发编程 — ThreadPoolExecutor 线程池实现原理

一、线程池的概念 线程池(Thread Pool)是一种基于池化思想管理线程的工具。类似于我们连接数据库的连接池。 线程池解决的核心问题就是资源管理问题。在并发环境下,系统不能够确定在任意时刻中,有多少任务需要执行,有多少资源需要投入。这种不确定性将带来以下若干问题: 创建一个线程,却需要调用操作系统内核的 API,然后操作系统要为线程分配一系列的资源,创建成本很高 频繁申请/销毁资源和调度资源,将带来额外的消耗,可能会非常巨大。 对资源无限申请缺少抑制手段,易引发系统资源耗尽的风险。 系统无法合

small_love的专栏 2081

ThreadPoolExecutor详解及线程池优化

前言 ThreadPoolExecutor在concurrent包下,是我们最常用的类之一。无论是做大数据的,还是写业务开发,对其透彻的理解以及如何发挥更好的性能,成为了我们在更好的coding道路上必不可少的基础。 为什么用线程池? 如果并发的请求数量非常多,但每个线程执行的时间很短,这样就会频繁的创建和销毁线程,如此一来会大大降低系统的效率。这就是线程池的目的了。线程池为线程生命周期的开销和资...

Deegue 1万+

java线程池ThreadPoolExecutor详解及使用

java线程池ThreadPoolExecutor的使用 在日常开发中我们经常会使用多线程,但是当线程数量达到一定程度时,频繁的创建线程、执行任务、销毁线程就会造成资源的浪费和性能的开销,那么这个时候就要考虑使用线程池了,它可以很好的避免这个问题,尤其是程序中需要创建大量的生存周期很短的线程时,更应该考虑使用线程池。 线程池的概念 线程池(ThreadPool),简单的说,它就是一个装有线程的池子,我们只需把任务(多线程执行的内容)交给线程池来处理,和数据库连接池、Http连接池的概念差不多的,通过维护

weixin_44178366的博客 4616

JAVA线程池详解(ThreadPoolExecutor)

随着计算机行业的飞速发展,摩尔定律逐渐失效,多核CPU成为主流。使用多线程并行计算逐渐成为开发人员提升服务器性能的基本武器。如果你要成为一个好的工程师,还是得比较好地掌握这个知识,很多线上问题都是因为没有用好线程池导致的。即使你为了谋生,也要知道,这基本上是面试必问的题目,而且面试官很容易从被面试者的回答中捕捉到被面试者的技术水平。

ChengHuanHuaning的博客 8155

Java并发编程 —— ThreadPoolExecutor线程池详解

线程池是一种池化技术,是管理一系列线程的资源池。当有任务要处理时,直接从线程池中获取线程来处理,处理完之后线程并不会立即被销毁,而是等待下一个任务。这样实现线程的复用,避免重复创建与销毁线程的开销和大量线程上下文切换,提高系统效率和并发度。 使用线程池的好处: 1. **降低资源消耗**。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。 2. **提高响应速度**。当任务到达时,任务可以不需要等到线程创建就能立即执行。 3. **提高线程的可管理性**。线程是稀缺资源,如果无限制的创建,不仅会消耗系

m0_56602092的博客 4734

线程池 ThreadPoolExecutor 配置参数详解

本篇 介绍 Java 中的线程池 ThreadPoolExecutor 配置参数

Huazie 3134

Java并发编程 - 线程池ThreadPoolExecutor详解

是Java中实现线程池的一种强大工具,它可以灵活地配置线程池的各种参数,以适应不同的应用场景。合理配置线程池可以显著提高系统的响应速度和吞吐量,同时减少资源消耗。在设计线程池时,应该根据具体的需求仔细考虑各种参数的选择,以确保线程池能够高效稳定地运行。

qq_33240556的博客 1179

Java线程池之ThreadPoolExecutor

(1)自己创建一个单线程串行执行任务,如果任务执行失败而终止那么没有任何补救措施,而线程池还会新建一个线程,保证池的正常工作。(1)线程池中刚开始没有线程,当一个任务提交给线程池后,线程池会创建一个新线程来执行任务。整个线程池表现为线程数会根据任务量不断增长,没有上限,当任务执行完毕,空闲。,意味着:全部都是救急线程(60s 后可以回收),救急线程可以无限创建。时,会放入无界队列排队。(3)如果队列选择了有界队列,那么任务超过了队列大小时,会创建。并没有线程空闲,这时再加入任务,新加的任务会被加入。

YouPromise的博客 1512

java线程池ThreadPoolExecutor详解

创建一个新线程时使用的工厂,可以用来设定线程名、是否为daemon线程等等,threadFactory创建的线程也是采用new Thread()方式,threadFactory创建的线程名都具有统一的风格:pool-m-thread-n(m为线程池的编号,n为线程池内的线程编号)当向线程池提交一个任务时,若线程池已创建的线程数小于corePoolSize,即便此时存在空闲线程,也会通过创建一个新线程来执行该任务,直到已创建的线程数大于或等于corePoolSize。线程池所允许的最大线程个数。

qq_37080455的博客 1068

一文详解线程池ThreadPoolExecutor

虽然实现线程池的方式有多种,由于阿里规范中,推荐使用ThreadPoolExecutor来实现线程池,且实际使用中也较多,所以这里主要结合ThreadPoolExecutor来探索。线程池的状态代表了线程池当前的运行状态,并且这些状态在对线程池进行操作(如关闭线程池、尝试执行任务等)时起着关键作用。:一个拒绝策略,当任务太多,无法被线程池及时处理,且工作队列已满时,线程池会使用这个拒绝策略来处理新来的任务。:这是线程池的初始状态,表示线程池正常运行,可以接受新任务,并且可以处理阻塞队列中的任务。

weixin_40709965的博客 1208
上一篇: Java并发编程(四)—基于队列同步器的可重入锁
下一篇: Android探索之路(二)—View的工作流程
Coding-ls
博客等级 码龄11年 41粉丝 61原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值