ThreadPoolExecutor关于Execute方法

第一次使用ThreadPoolTaskExecutor实现线程池的经历,反复修改了多次代码才正常使用 在一个向第三方平台推送消息的场景中,为了提高程序的执行效率,每次发送消息,都创建一个新的线程来完成发送消息的任务,为了提供线程的使用性能,我选择了ThreadPoolTaskExecutor线程池,结果在使用的过程中,出现了较多的问题,这里记录一下避免以后再出现类似的错误(这些错误是不应该出现的,还是对ThreadPoolTaskExecutor使用不熟悉造成的)。 阅读详情

ThreadPoolExecutor的两个核心集合:
一个是持有当前可用线程的集合HashSet<Worker> workers,
另一个是待执行的task的集合BlockingQueue<Runnable> workQueue

线程池之所以成为线程池是,我们在试图运行一个具体的task时,我们没有调用Thread.start()方法,而是通过worker线程对象来调用task中的run()方法。
注意start()会开启一个新的线程,而run()是运行在当前线程中的。

Execute()方法的逻辑

当我们调用ThreadPoolExecutor中的Execute方法时,线程池会对当前自身状态做出判断来决定是否创建新的worker来立即执行task,或者是将task放置在workQueue队列中。
Execute代码片段:

    int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        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);

在addWorker方法中,我们创建了一个封装task的worker对象。Worker内部类是一个Runnable接口的实现,addWorker创建完worker后,会启动worker自身持有的thread属性的start()方法来允许worker的run()方法。

        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 rs = runStateOf(ctl.get());

                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && 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;
                }
            }

而Worker类中run()方法调用的是ThreadPoolExecutor的runWorker(Worker w)方法,通过不断的查看持有task的集合workQueue中是否还有未执行的task来复用当前的worker线程。

        while (task != null || (task = getTask()) != null) {
                w.lock();
                // If pool is stopping, ensure thread is interrupted;
                // if not, ensure thread is not interrupted.  This
                // requires a recheck in second case to deal with
                // shutdownNow race while clearing interrupt
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                        task.run();
                    } catch (RuntimeException x) {
                        thrown = x; throw x;
                    } catch (Error x) {
                        thrown = x; throw x;
                    } catch (Throwable x) {
                        thrown = x; throw new Error(x);
                    } finally {
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }

关于processWorkerExit()方法的疑惑

在runWorker(Worker w)方法的最后,调用了processWorkerExit()方法。
这个方法的Javadoc是:

     * Performs cleanup and bookkeeping for a dying worker. Called
     * only from worker threads. Unless completedAbruptly is set,
     * assumes that workerCount has already been adjusted to account
     * for exit.  This method removes thread from worker set, and
     * possibly terminates the pool or replaces the worker if either
     * it exited due to user task exception or if fewer than
     * corePoolSize workers are running or queue is non-empty but
     * there are no workers.

其中将当前的worker()移除了workers集合,随之又创建一个idle的worker:

    if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
            decrementWorkerCount();

        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            completedTaskCount += w.completedTasks;
            workers.remove(w); // 将worker移除
        } finally {
            mainLock.unlock();
        }

        tryTerminate();

        int c = ctl.get();
        if (runStateLessThan(c, STOP)) {
            if (!completedAbruptly) {
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
                if (min == 0 && ! workQueue.isEmpty())
                    min = 1;
                if (workerCountOf(c) >= min)
                    return; // replacement not needed
            }
            addWorker(null, false); // 创建一个idle线程
        }

那为什么要把原来的worker移走呢?
我暂时的理解是,因为worker执行完一个task后,它的状态为terminated,不可能再转变成了runnable,所以我们需要用一个idle的worker去替代它。

那么问题又来了,idle的worker在addWorker中又会被启动,如果它什么都不做,难道又会在绕进processWorkerExit()方法中被另一个idle的worker替代?

有待思考。

ThreadPoolExecutor(二)——execute 1.execute方法 /** * Executes the given task sometime in the future. The task * may execute in a new thread or in an existing pooled thread. * * If the task cannot be submitted for 阅读详情

相关推荐

【Java线程池03】ThreadPoolExecutor的execute方法执行流程

ThreadPoolExecutor的execute方法执行流程前言【Java线程池01】Java线程池简介此文中对Java线程池简介,包含线程池相关的几个类的关系等。【Java线程池02】ThreadPoolExecutor类概述此文介绍了ThreadPoolExecutor的构造函数、核心字段以及核心方法这篇文章将学习总结ThreadPoolExecutor的核心方法execute的执行流程源...

龙腾四海365的专栏 2609

ThreadPoolExecutor的execute方法

execute方法是将任务提交到线程池中的核心方法。线程池的执行流程可以通过execute内部进行的逻辑判断得知。

舒一笑的博客 1957

ThreadPoolExecutor.execute(Runnable command) 方法的完整执行流程

本文详细解析了 ThreadPoolExecutor.execute(Runnable command) 方法的完整执行流程。该方法通过 ctl 状态变量判断线程池运行情况,按照核心线程数→任务队列→非核心线程的顺序处理任务提交。当核心线程未满时直接创建线程执行任务;否则尝试入队,并在队列满后尝试创建非核心线程。若所有途径均失败,则触发拒绝策略。源码分析展示了状态检查、线程创建、队列管理和拒绝处理的关键逻辑,并附流程图说明整体控制流程。该方法体现了线程池"核心线程优先→队列缓冲→弹性扩容→拒绝保护

SlothLu的博客 1143

0.9.4、线程池—— ThreadPoolExecutor.execute 处理逻辑

文章目录前言接口 Executor.execute(Runnable command);ThreadPoolExecutor.executeThreadPoolExecutor.submitThreadPoolExecutor.execute 源码流程图 前言 在 线程池——核心线程数、阻塞队列、最大线程数之间的关系 中我们从运行流程层面了解了线程池处理任务的顺序。 在 ThreadPoolExecutor 的基础变量 ctl 、 runState 和 workerCount 中,我们对线程中比较关键的几个

༺ bestcxx的专栏 ༻ 6132

一致性总线CMN600AE-ARM系列

主要介绍一致性总线CMN600AE,根据arm官网的spec来概述其模块。提示:以下是本篇文章正文内容,下面案例可供参考CMN600ae是基于Mesh拓扑结构,对外支持AMBA CHI/ACE-LITE等接口,内部改用路由结构转发数据,并提供硬件一致性和系统缓存,还支持多芯片互联。CMN600在T16FFC上可以做到2Ghz,另外AE版本增加了车轨芯片的安全功能,总线内部采用EDC检查,接口采用的奇校验。

tujiuguo3994的博客 6297

CSP-J/S复赛文件组织与freopen读写全攻略,避免爆零

在信息学竞赛的上机考试中,代码能力固然重要,但文件组织与输入输出重定向往往是决定成败的关键细节。许多选手习惯在线评测环境,对本地文件命名、目录层级和读写方式缺乏系统认知,导致算法正确却因文件名拼写错误或freopen使用不当而遗憾失分。理解评测系统的工作原理,掌握从建立准考证号目录到规范命名源文件,再到使用freopen进行文件流重定向的标准流程,是每位参赛者的必备技能。这种工程化习惯不仅适用于CSP-J/S复赛,也是未来参加NOI等更高水平竞赛的基础。本文从文件组织的底层逻辑出发,结合实战案例,系统讲解考

weixin_32466193的博客 594

线程池(三)ThreadPoolTaskExecutor(2)两种提交方法

前面提到了线程池提交任务有两种方法: 无返回值的任务使用public void execute(Runnable command) 方法提交; 有返回值的任务使用public <T> Future<T> submit(Callable) 方法提交。 下面具体来看下两者的应用以及区别。 一、与主线程执行顺序的区别: 1、 (1)public void execut...

w_t_y_y的博客 2万+

03 - AMDGPU驱动架构概览

本文介绍了AMDGPU驱动的整体架构,重点分析其图形驱动(AMDGPU)和计算驱动(KFD)的双重结构。KFD驱动作为HSA架构的核心组件,包含进程管理、设备管理等模块,其中SVM功能在kfd_svm.c实现。文章详细解析了KFD的核心组件、初始化流程及字符设备接口,并阐述了TTM框架在GPU内存管理中的作用。通过架构图和代码片段展示了AMDGPU与KFD的协作机制,为后续深入理解SVM实现奠定基础。

图形/计算GPU的驱动与虚拟化技术分享园地 3371

线程池ThreadPoolExecutor中submit方法和execute方法的区别和关系

ThreadPoolExecutor是线程池,其继承AbstractExecutorService,如下代码: package java.util.concurrent; import java.util.ArrayList; import java.util.ConcurrentModificationException; import java.util.HashSet; import ...

任枫的博客 4055

嵌入式模拟电路面试题大全及参考答案(持续更新)

高输入阻抗:由于晶体管的基极-发射极(BJT)或栅极-源极(MOSFET)电压很低,跨导放大器具有很高的输入阻抗。低输出阻抗:晶体管的集电极-发射极或漏极-源极电阻较低,提供较低的输出阻抗。电压控制:输入信号控制晶体管的跨导,从而控制输出电流。晶体管:作为放大器的核心,可以是BJT或MOSFET。偏置电路:为晶体管提供稳定的工作点,确保其在放大区域内工作。负载电阻:与晶体管的集电极或漏极连接,将电流转换为电压。晶体管的选择:根据所需的增益、速度和功率消耗选择合适的晶体管。偏置稳定性。

大模型大数据攻城狮的专栏 989

3D医学影像开发入门<一>:VS2019+DCMTK3.6.8编译及环境配置

3D医学影像开发入门:VS2019+DCMTK3.6.8编译及环境配置

欧特GO 1308

ThreadPoolExecutor submit和execute方法的区别

可以看到 异常被放到 FutureTask 中 ,只有在 调用 get 方法的时候才会被抛出。

面朝大海,春暖花开 3650

3 路由引入

在大型企业网络中,网络规模十分庞大,选用单一的路由协议无法满足网络的需求,因此多种路由协议共存的情况十分常见。或者出于业务逻辑或行政管理的考虑,会在不同的网络结构中设计和部署不同的路由协议,使路由的层次结构更加清晰可控。路由引入是具有方向性的,将路由信息从路由协议A引入到路由协议B(A-to-B),则路由协议B可获知A中的路由信息,但是此时,A还并不知晓B路由协议中的路由信息,除非配置B-to-A的路由引入。表3-1:各种路由协议的优先级。通过路由引入,可以实现路由信息在不同路由协议间传递。

lwljh134的博客 621

ThreadPoolExecutor的execute()和submit()方法

我希望使用多线程执行一个运算,并且线程执行完毕后我要获取执行结果。其实使用线程池ThreadPoolExecutor的execute()和submit()方法都可以。 使用execute()的话,事先定义一个存放返回结果的集合,开辟线程时,将集合的元素作为参数代入自定义的Runnable接口的实现类中,多线程执行完毕后遍历集合即可获得运算结果。 使用submit()的话,可以在submit()...

m0_37822338的博客 1万+

30天Python入门(第一天:Python入门)

30天带你入门Python,这是第一天

Science prince的博客 584

麻辣香锅病毒分析

Spicy Hot Pot浏览器劫持病毒(麻辣香锅病毒)从2020年初被安全公司监测到,因其病毒模块带有MLXG_KM被安全行业代称麻辣香锅病毒。目前通过各种激活工具传播, 包括暴风激活、小马激活和KMS激活等诸多工具,疑似与下载站进行合作推广此类激活工具。Spicy Hot Pot 是一个浏览器劫持 Rootkit,它会将用户的主页更改为指向恶意软件操作员控制的页面,此外还会将内存转储从机器上传到预定义的服务器,并结合本地更新功能以确保其保持更新。通常浏览器劫持者会通过更改用户主页的恶意可执行文件或注册表

不忘初心,护天下安全! 4788

ThreadPoolExecutor的execute方法执行流程

ThreadPoolExecutor的execute方法执行流程 前言 【Java线程池01】Java线程池简介 此文中对Java线程池简介,包含线程池相关的几个类的关系等。 【Java线程池02】ThreadPoolExecutor类概述 此文介绍了ThreadPoolExecutor的构造函数、核心字段以及核心方法 这篇文章将学习总结ThreadPoolExecutor的核心方法execute的执行流程 *源码 ** 源码分析 从上述执行流程中我们可以得知,其核心点为addWorker方法,下

qq_35615598的博客 2616

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

ThreadPoolExecutor 源码分析 - execute() 方法

知识回顾 线程池的几种状态 RUNNING 、SHUTDOWN 等 线程池的核心参数 corePoolSize 和 maximumPoolSize 等 线程池的工作原理 核心线程 -> 阻塞队列 -> 非核心线程 -> 拒绝策略 如何判断线程池的状态和线程数量:通过 AtomicInteger ctl 变量的高低位判断 Worker 对象的介绍(对一个线程任务的包装) ThreadPoolExecutor#workers 属性 线程池中有一个 workers 集合,里面记录了所有的工作

nimo10050的博客 860

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

深入理解ThreadPoolExecutor中execute()方法原理

前言 为什么要使用线程池 1.在Java中,如果每个请求到达就创建一个新线程,开销是相当大的。在实际使用中,服务器在创建和销毁线程上花费的时间和消耗的系统资源都相当大,甚至可能要比在处理实际的用户请求的时间和资源要多的多。 2.除了创建和销毁线程的开销之外,活动的线程也需要消耗系统资源。如果在一个jvm里创建太多的线程,可能会是系统由于过度消耗内存或“切换过度”而导致系统资源不足。 3.为了防止资源不足,服务器应用程序需要采取一些办法来限制任何给定时刻处理的请求数目,尽可能减少创建和销毁的线程的次数

张家煦的博客 3895

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

ThreadPoolExecutor execute方法解析

Executor 顶级接口 定义了最关键的execute方法 public interface Executor { /** * Executes the given command at some time in the future. The command * may execute in a new thread, in a pooled thread, or in the calling * thread, at the discretion of the

cao_luobin的博客 1817

线程池ThreadPoolExecutor中execute和submit方法对比

方法定义: // ExecutorService接口中定义的方法: Future<?> submit(Runnable task); <T> Future<T> submit(Runnable task, T result); <T> Future<T> submit(Callable<T> task); // Threa...

weixin_38569499的博客 3090

线程池ThreadPoolExecutor的execute和submit方法在程执行发生异常会怎么样

本文章是通过源码介绍ThreadPoolExecutor 两种提交线程的方式,在线程执行异常,线程池的处理方式

wyz0923的博客 781

线程池(二) -- 源码解析ThreadPoolExecutor中的execute()方法

ThreadPoolExector实际上就是一个生产消费模式,当调用execute()方法添加任务线程时,相当于生产者生产数据元素,workers线程池中的线程执行任务线程或从阻塞队列中获取任务线程执行时,相当于消费者消费数据元素。 在源码分析execute方法之前,需要弄清楚下面几个问题。 1)、线程池中的线程是什么样的线程对象? 2)、线程池中的线程用什么来进行存储? 3)、处于等待状态的任务线程又放在那里? 4)、线程池中的线程是如何获取并执行这些处于等待状态中的任务线程的? 首先区.

铭 1616

线程池原理(三):ThreadPoolExecutor核心方法之execute()方法

即执行),否则maximumPoolSize。最大线程数maximumPoolSize,则创建新的线程来处理任务,执行这一步骤需要获取。线程(在这种情况下,我们总是启动一个),或当队列是满的(在这种情况下,我们必。2)如果当前运行的线程数等于或大于核心线程数corePoolSize,则将当前提交的任务放入。1)如果当前运行的线程少于核心线程数corePoolSize,则创建新的线程来执行当前提交。execute() 方法是线程池 ThreadPoolExecutor 中最核心的方法,由前边的。

liang8999的博客 1593

Java 多线程线程池-ThreadPoolExecutor的execute方法分析

0.ThreaPoolExecutor的类图 1.线程池类的一些重要属性 //AtomicInteger占位32位 private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); private static final int COUNT_BITS = Integer.SIZE - ...

lihongtai的专栏 1150

java线程池源码解析:ThreadPoolExecutor源码,execute方法、addWorker方法解析

线程池哪部需要维持的一个最小的数量的工作线程,工作线程数量不足这个数量的时候,新来的任务都会提交一个新的工作线程,任务不会放入 队列。工作线程数到达这个数量的时候,新来的的任务,都会放入这个队列中。线程池 的作用不用太说了,线程池会按照一定的规则,创建和维护一定数量的线程。shuntdown: 此时不可以接收新的任务,但是可以正常处理,但是不再接受新的任务,并且终端空闲的工作状态。任务列表和工作线程,都为空。线程池哪位维护了一个队列,用来存储待处理的任务,每个线程都可以从该队列获取任务进行处理。

Andrew_lee's blog 579
上一篇: 递归设计
下一篇: docker工作笔记1 -- 开启docker Rest api的远程调用
AlainGogogo
博客等级 码龄18年 5粉丝 20原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值