java线程池(ThreadPool)的使用

Java性能优化学习之 巧用线程池ThreadPool 一、相关概念: 线程池可以看做容纳线程的容器; 一个应用程序最多只能有一个线程池; ThreadPool静态类通过QueueUserWorkItem()方法将工作函数排入线程池; 每排入一个工作函数,就相当于请求创建一个线程; 二、ThreadPool的作用: 总结:线程池是为突然大量爆发的线程设计的,通过有限的几个固定线程... 阅读详情

java.util.concurrent.ThreadPoolExecutor类来创建完成基础pool

ThreadPoolExecutor(int corePoolSize,

                   int maximumPoolSize,

                   long keepAliveTime,

                   TimeUnit unit,

                   BlockingQueue<Runnable> workQueue,

                   ThreadFactory threadFactory,

                   RejectedExecutionHandler handlaer)

下面对参数进行说明

1:corePoolSize:表示核心线程池的大小.当提交一个任务时,如果当前核心线程池的线程个数没有达到corePoolSize,则会创建新的线程来执行所提交的任务,即使当前核心线程池有空闲的线程。如果当前线程核心池的线程个数达到了corePoolSize,则不再重新创建线程.如果调用了prestartCoreThread()或者 prestartAllCoreThreads(),线程池创建的时候所有的核心线程都会被创建并且启动。

2:maximumPoolSize:表示当前线程池能创建线程的最大个数.如果当阻塞队列已满时,并且当前线程个数没有超过maximumPoolSize的话,就会创建新的线程来执行任务。

3:keepAliveTime:空闲线程存活时间。如果当前线程池的线程个数已经超过了corePoolSize,并且线程空闲时间超过了keepAliveTime的话,就会将这些空闲线程销毁,这样可以尽可能降低系统资源消耗。

4:unit:时间单位.为keepAliveTime指定时间单位。

5:workQueue:阻塞队列.用于保存任务的阻塞队列,可以使用 ArrayBlockingQueue, LinkedBlockingQueue, SynchronousQueue, PriorityBlockingQueue,DelayedWorkQueue根据不同的队列类,赋予该线程池不同的功能。后续会详细介绍

6:threadFactory:创建线程的工程类.可根据该线程池实际作用业务需求)创建自己特有的名称,这样的话当出现bug时可以即使定位问题,找到原因所在

7:handler:饱和策略.当线程阻塞队列中任务已满并且已达到最大线程数,那么说明该当前线程池已经处于饱和状态了,无法再创建新的线程来接收任务来,那么此时就需要采用一种策略来处理这种情况。目前通用采用的策略有以下这几种:

  1. AbortPolicy: 直接拒绝提交的任务,并抛出RejectedExecutionException异常;

  2. CallerRunsPolicy:只用调用者所在的线程来执行任务;

  3. DiscardPolicy:不处理直接丢弃掉任务;

  4. DiscardOldestPolicy:丢弃掉阻塞队列中存放时间最久的任务,执行当前任务

java.util.concurrent.Executors提供了4种不同类型线程池来供我们使用。本质是创建不同的workQueue来提供不同功能

1:Executors.newFixedThreadPool(int nThreads) 

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }


public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),
                                      threadFactory);

Executors提供了两种不同构建方法,不同在于是否自定义指定ThreadFactory。从上述源码可知道newFixedThreadPool的

workQueue使用是LinkedBlockingQueue(底层基于链表保存数据),指定capacity(容量)=Integer.MAX_VALUE,意味该队列是一个无界队列;核心线程数与最大线程数相同;这样的设置使得该线程池的实际线程数达到核心线程数后的任务都会保存到任务队列中等待执行,理论上是不会出现触发饱和策略的情况。使用该线程池时注意如果任务过大,或任务执行时间过长导致队列中挤压任务过大会导致内存溢出。

2:Executors. newCachedThreadPool()

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }




public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>(),
                                      threadFactory);
    }

从上述源码可以看出,newCachedThreadPool的两种构建方法的差距为是否需要自定义ThreadFactory。指定核心线程数为0,最大线程数为int的最大值,workQueue使用SynchronousQueue(简单理解SynchronousQueue是一个没有容量,是无缓冲等待队列,是一个不存储元素的阻塞队列,必须等队列中的添加元素被消费后才能继续添加新的元素),keepAliveTime=60s.这样的设置在多任务情况下,每提交一个任务pool就会启用一个线程来处理任务(如果当前pool中无空闲线程可用的话).当任务结束,pool会清理空闲时间超过60s的线程。优点:在少任务的情况下,可以起到一定缓存线程的作用(减少创建不必要的线程,最大化利用空闲线程)一但任务过多,该pool会创建与任务数相对应的线程数

3:Executors.newSingleThreadExecutor

public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }


public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>(),
                                    threadFactory));
    }

从方法名称上也可以知道该线程池与单例有关,newSingleThreadExecutor的两种构建方法的差距为是否需要自定义ThreadFactory,指定核心线程数与最大线程为1(代表整个线程池中的线程数永远为1个即Single),workQueue使用是LinkedBlockingQueue(底层基于链表保存数据),指定capacity(容量)=Integer.MAX_VALUE,意味该队列是一个无界队列。整个线程池中只有一个线程执行阻塞队列中的所有任务。

4:Executors.newScheduledThreadPool(int corePoolSize)

//ScheduledThreadPoolExecutor继承了ThreadPoolExecutor 通过查看源码发现
//本质仍然是调用是使用以下的ThreadPoolExecutor的构造函数
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }


public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1));
    }

public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1, threadFactory));
    }


创建一个可以用来给定延时后执行异步任务或周期性执行任务的线程池。workQueue使用是DelayedWorkQueue。DelayedWorkQueue 阻塞队列:保证执行任以及能够周期执行任务,在执行定时任务的时候,每个任务执行时间不同,所以DelayedWorkQueue的工作就是按照执行时间的升序来排序,执行时间距离当前时间越近的任务在最前面

当上述java提供的4种线程池不能满足与我们实际应用,我们需要根据业务不同,通过设置不同参数构建不同的线程池来实现不同业务场景。

如何合理的配置线程池参数(可根据使用线程池的用途来分析):

想要合理的配置线程池,就必须首先分析任务特性,我们可以从以下几个角度来进行分析:

1:任务的性质:任务 属于哪种类型,是属于CPU密集型任务 ,还是属于IO密集型任务,还是属于混合型任务

2:任务的优先级:任务的执行是否会依赖某种属性定义为高,中,低。例如时间,或任务的重要程度

3:任务的执行时间:长,中,短

4:任务的依赖性:是否依赖其他外部资源,如访问外部api接口。

不同的性质的任务可以放到不同规模的线程池分开处理。CPU密集型任务配置尽可能少的线程数量,如配置Ncpu+1个线程的线程池。IO密集型任务则由于需要等待IO操作,线程并不是一直在执行任务,则配置尽可能多的线程,如2*Ncpu。混合型的任务,如果可以拆分,则将其拆分成一个CPU密集型和一个IO型任务,只要这两个执行时间相差不是太大,那么分解后执行的吞吐率要高于串行执行的吞吐率,如果这两个任务执行时间相差太大,则没必要进行分解.通过Runtime.getRuntime().availableProcessors()方法我们可以获得当前设备的CPU个数。

优先级不同的任务可以使用优先级队列PriorityBlockingQueue(可排序阻塞队列)来处理。它可以让优先级高的任务先得到执行,如果一直有优先级高的任务被提交到队列里,那么优先级低的任务可能永远不能执行( 饥饿线程)。

依赖访问外部api接口任务,因为线程发起请求后需要等待api响应,如果等待的时间越长CPU空闲时间就越长,那么线程数应该设置越大,这样才能更好的利用CPU。(针对这种情况请求一定要设置超时时间,超时时间值的大小最好根据实测接口访问平均时间来定)

建议阻塞队列最好是使用有界队列,如果采用无界队列的话,一旦任务积压在阻塞队列中的话就会占用过多的内存资源,甚至会使得系统崩溃。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Java:实现自定义线程池ThreadPool算法(附完整源码) 阅读详情

相关推荐

从Arduino IDE到Atmel Studio:ATmega328P开发的进阶之路

本文探讨了从Arduino IDE转向Atmel Studio进行ATmega328P开发的进阶路径。通过对比两者差异,详细介绍了Atmel Studio的环境配置、寄存器操作思维、烧录方法及高级调试功能,帮助开发者突破Arduino的封装限制,实现对单片机底层硬件的精细控制与性能优化,提升嵌入式开发的专业能力。

weixin_29193259的博客 122

Java并发包之SynchronousQueue实践学习笔记

介绍 Java 6的并发编程包中的SynchronousQueue是一个没有数据缓冲的BlockingQueue(队列只能存储一个元素),生产者线程对其的插入操作put必须等待消费者的移除操作take,反过来也一样,消费者移除数据操作必须等待生产者的插入。 不像ArrayBlockingQueue或LinkedListBlockingQueue,SynchronousQueue内部并没

吟啸徐行 8220

企业微信消息推送API实战:5步搞定可信IP与域名配置(含Python代码示例)

本文详细解析了企业微信消息推送API实战中的关键配置步骤,特别是可信IP与可信域名的配置流程。通过5个清晰步骤,结合Python代码示例,指导开发者快速完成安全通信链路搭建,避免常见错误,确保消息推送服务稳定可靠。

qsc9012345的博客 996

创建线程的方法?

1、实现 Runnable 接口 实现 Runnable 接口,然后重写 run() 方法,之后只需要把这个实现了 run() 方法的实例传到 Thread 类中就可以实现多线程。 2、继承 Thread 类 继承 Thread 类,并重写了其中的 run() 方法。 3、线程池创建线程 3.1使用ThreadPoolExecutor类 public ThreadPoolExecutor(int corePoolSize, ...

tdt008的博客 203

从理想光源到部分相干:Abbe与Hopkins模型在计算光刻中的演进与选择

本文深入探讨了计算光刻中Abbe模型与Hopkins模型的演进与选择,分析了理想光源与部分相干光源在光刻仿真中的关键差异。Abbe模型基于理想点光源假设,计算简洁但存在精度局限;Hopkins模型则通过互强度函数和TCC技术,更准确地模拟现实中的部分相干光源,尤其适用于先进节点光刻工艺。文章还提供了模型选择的实用建议,帮助工程师在精度与效率间取得平衡。

weixin_29217235的博客 297

从零构建:用Arduino和MCP2515模块搭建你的第一个CAN Bus网络

本文详细介绍了如何使用Arduino和MCP2515模块从零搭建CAN Bus网络,实现温湿度数据的传输与显示。涵盖硬件连接、软件配置、发送端与接收端代码实现,以及系统调试和进阶应用,帮助初学者快速掌握CAN总线通信技术。

d6e7f8的博客 832

Java多线程编程学习总结(二)

  (尊重劳动成果,转载请注明出处:https://blog.youkuaiyun.com/qq_25827845/article/details/84894463冷血之心的博客) 系列文章: Java多线程编程学习总结(一) Java多线程编程学习总结(二) 前序:        距离上一篇多线程的总结:Java多线程编程学习总结(一)已经很长一段时间了,在这半年的工作与学习中,我对Java多线...

冷血之心的博客 950

C++,使用Qt设计一个登录窗口

使用Qt设计一个登录界面

heyu0311的博客 2991

SynchronousQueue 同步队列

1、概述 第一次接触SynchronousQueue,是在java提供的四种线程池中,缓存线程池的源码实现中看到(缓存线程池允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM,不建议使用): public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE,

跨语言,跨平台,跨应用 1862

龙头复盘神器/复盘于导出工具最新版5.6

龙头复盘神器,复盘于导出工具

初入python踩过的坑 8234

Palantir的Ontology:从静态知识图谱到动态业务引擎的跃迁

本文探讨了Palantir的Ontology技术如何将静态知识图谱升级为动态业务引擎。通过引入函数和行动作为核心元素,Ontology实现了业务逻辑的自动化响应与执行,显著提升物流、能源等领域的运营效率。文章详细解析了其混合存储引擎、状态监听网络等关键技术设计,并对比展示了传统架构与Ontology架构的业务价值差异。

weixin_42570296的博客 200

Java线程深入学习(五)

第六章、线程管理 6.1 线程组 类似于在计算机中使用文件夹管理文件,也可以使用线程组来管理线程。在线程祖中定义一组相似(相关)的线程,在线程组中也可以定义子线程组。 Thread类有几个构造方法允许在创建线程时指定线程组,如果在创建线程时没有指定线程组则该线程就属于父线程所在的线程组。JVM在创建main线程时会为它指定一个线程组,因此每个java线程都有一个线程组与之关联,可以调用线程的getThreadGroup()方法返回线程组。 线程组开始是处于安全的考虑设计用来区分不同...

xxyneymar的博客 369

数据库小技能:数据导入脚本

背景:版本大升级,从2.0升级到3.0 ,服务端开发语言从c#换到java语言。数据库类型从microsalft sql server 换到mysql。数据来源于微信,用于查询卡bin。

专注于计算机研发知识和资讯分享 774

Java中ThreadPool线程池的详细使用指南

摘要:本文详细介绍了Java线程池的三种使用场景:1)无参数任务场景,展示了如何创建固定大小线程池、使用CountDownLatch同步任务完成状态;2)带参数任务场景,演示了如何通过final变量传递参数并封装任务执行逻辑;3)带超时控制的线程池使用方法,涉及线程池的优雅关闭和超时处理。每种场景都包含了完整的代码示例和异常处理机制,适用于不同的并发编程需求。

录大大i的博客 374

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

Java线程池ThreadPool详解

Java线程池ThreadPool详解1. 线程池概述1.1 线程池简介1.2 线程池特点1.3 线程池解决的问题2. 线程池原理分析2.1 线程池总体设计2.6 线程池流转状态2.2 线程池执行流程2.3 线程池核心参数2.4 线程池饱和策略2.5 线程池阻塞队列2.7 关闭线程池3. 线程池工具类4. Executors创建线程池注意事项5. 线程池手动创建6. SpringBoot创建线程池 1. 线程池概述 1.1 线程池简介 线程池(Thread Pool)是一种基于池化思想管理线程的工具,经常出

靖节先生的博客 8488

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

java 线程池ThreadPool

java 线程池 1.为什么要使用线程池? 使用线程池主要有下面三种有点: 频繁的创建/销毁线程对系统资源消耗比较大,使用线程池可以复用已创建的线程。 可以控制当前线程的数量,并发线程过多,可能会导致资源消耗过多,严重时会造成服务器崩溃。 可以对线程进行统一处理,比如关闭应用,关闭线程池就可关闭线程。 2.线程池实现 jdk中 java.util.concurrent包已经帮助我们实现线程池的逻辑。 ThreadPoolExecutor的实现关系如下图。 我们先看一下类的构造方法: //

大米饭 205

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

C++11线程池ThreadPool(模仿Java的ThreadPoolExecutor)

C++11线程池ThreadPool功能描述使用示例关键函数说明创建阻塞队列BlockingQueue创建线程池ThreadPool提交任务shutdown线程池设计思想BlockingQueue设计execute执行流程ctl变量设计BlockingQueue必须实现函数说明Task类型实现要求源码BlockingQueue.hThreadPool.h码云链接 功能描述 实现一种基于C++11的线程池ThreadPool,模仿Java的ThreadPoolExecutor; 使用示例 #include"T

xin_hen的博客 1132

JAVA线程池——ThreadPool

前言 线程的使用在 Java 开发中已经屡见不鲜了,在并发编程,分布式的场景中更是常客,但是对于线程的使用可能一些职场新人还是会有些不熟悉,今天这篇我们就先来介绍一下关于 Java 的 Thread 使用。 Thread Thread的使用 关于Thread的那些事 线程池ThreadPool 线程池参数 Java自带线程池 SignalThreadPool ...

weixin_42669785的博客 402

Java-ThreadPool线程池总结

无论是哪家公司,都很重视Spring框架技术,重视基础,所以千万别小看任何知识。面试是一个双向选择的过程,不要抱着畏惧的心态去面试,不利于自己的发挥。同时看中的应该不止薪资,还要看你是不是真的喜欢这家公司,好了希望这篇文章对大家有帮助!《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)**无论是哪家公司,都很重视Spring框架技术,重视基础,所以千万别小看任何知识。

2401_83915450的博客 369

Java——ThreadPool线程池

1. 为什么使用线程池 当并发执行线程数量很多时,且每个线程执行很短的时间就结束了,这样,我们频繁的创建、销毁线程就大大降低了工作效率(创建和销毁线程需要时间、资源)。 java中的线程池可以达到这样的效果:一个线程执行完任务之后,继续去执行下一个任务,不被销毁,这样线程利用率提高了。 假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。 2. 线程池作用 线程池作用就是限制系统中

Yawn 902

java 线程池 ThreadPool

Java 线程池 ThreadPool 问题: 单开线程的方式:new Thread(() -> {…})。已经很简单了,我为什么要用线程池。如果你需要成千上百个呢,这就需要用有一个统一的管理了。 线程池: 它有什么好处呢,减少线程的创建、销毁。反复利用这几个线程来执行所有新老任务。 线程池的源码,下面解读每个参数 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,

huangjiangmin 1105

java ThreadPool线程池的使用,线程池工具类

实际上java已经提供线程池的实现ExecutorService。 为了更方便的使用和管理。这里提供一个线程池工具类,方便大家的使用。 直接看看代码: 使用 public static void main(String[] args) { //实例化一个固定数目的线程池。具体参考类的构造方法 ThreadPool threadPool=ne...

Gogym的博客 1155

Java线程池ThreadPool

1、线程池基础 1.1 什么是线程池 线程池是一种多线程处理形式,处理过程中可以将任务添加到队列中,然后在创建线程后自动启动这些任务。这里的任务就是我们学过的实现了Runnable或Callable接口的实现对象。 1.2 使用线程池有哪些优势 ...

zhouth94的博客 254

【Java】线程池ThreadPool学习与使用

线程池的自我介绍 如果不使用线程池,每个任务都新开一个线程处理 ◆ 一个线程 ◆ for 循环创建线程 ◆ 当任务数量上升到 1000 这样开销太大,我们希望有固定数量的线程,来执行这 1000 个线程,这样就避免了反复创建并销毁线程所带来的开销问题。 线程池的好处 加快响应速度 合理利用CPU和内存 统一管理 线程池适合应用的场合 服务器接受到大量请求时,使用线程池技术是非常合适的,它可以大大减少线程的创建和销毁次数,提高服务器的工作效率实际上,在开发中,如果需要创建5个以上的线程,那么就可以使用线程池来

qq_24991197的博客 439
上一篇: Kafka出现丢失数据,重复数据的解决方案
下一篇: 深入了解kafka机制
F_Hello_World
博客等级 码龄11年 38粉丝 58原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值