Java并发:一篇搞定线程池

原文地址:https://www.nowcoder.com/discuss/152050?type=0&order=0&pos=6&page=0

本文是在原文的基础+理解,想要系统学习,请看原文地址。

线程池介绍

1.1 线程池的概念

线程池(thread pool): 一种线程使用模式。线程的创建销毁是十分消耗资源的(线程创建消耗内存、线程上下文切换从消耗CPU资源)。使用线程池可以更加充分的协调应用CPU、内存、网络、I/O等系统资源。在程序启动首先创建线程,在程序启动后可以将任务直接扔到线程池中,由线程池来执行这个任务。

1.2 线程池的解决的问题

①线程创建销毁会开辟祸首虚拟机栈、本地方法栈和程序技术器等线程私有内存。

②如不加控制,线程数量在达到一定值时,由于线程上下文切换需要互斥、通信,会造成CPU资源浪费,极端情况下,系统分配的时间片都用来完成上下文切换,而没有时间去执行真正的任务。

③频繁的创建销毁线程增加并发编程的风险。

④线程池可以解决线程过多时的等待或友好的决绝服务。

1.3 线程池作用

①利用线程池管理复用线程,控制最大并发数。(避免由于先吃过多,造成完成上下文切换而真正任务不执行)

②实现任务线程队列缓存策略和拒绝机制。(优雅的处理线程过多情况)

③实现某些与实践相关的功能。(可以利用线程池完成定时任务)

④隔离线程环境。(可以将不同类型的线程池放到一台服务器,隔离不同服务,避免线程相互影响)

1.4 线程池的有点

①降低资源消耗,避免频繁的内存申请和销毁

②提高响应速度,不需要完成线程的创建,直接执行任务(前提是线程池中有空闲的线程)

③提高线程的可管理性,使用线程池可以同理管理、分配、调优和监控。

线程池创建

首先从ThreadPoolExecutor构造方法来讲自定义ThreadFactory和RejectedExecutionHandler,编写一个最简单的线程池。通过ThreadPoolExecutor的execute和addWorker两个核心方法。

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
......
}

参数说明:

①corePoolSize:表示核心线程数:

corePoolSize=0,则任务执行完之后没有其他任务进入会销毁鲜线程池中的线程

corePoolSize>0,本地任务执行完毕后,线程池会保留corePoolSize个线程

②maximumPoolSize:表示线程池能够容纳同时执行的最大线程数

maximumPoolSize>=1,如果线程池中的线程执行,则数量大于等于1.

如果需要执行的线程数大于maximumPoolSize个线程,需要第五个参数handler来处理,缓存还是 丢弃。

③keepAliveTime:表示线程池中的线程空闲时间

当空闲时间达到keepAliveTime时,同时线程池中线程数大于信合线程数,则这个线程会被销毁。

利用这个参数,可以避免资源的浪费。

当allowCoreThreadTimeOut = true,核心线程超时也会被回收。

由源码可知,allowCoreThreadTimeOut是由volatile修饰,说明这个值变化对说有线程池中的线程可见,由于没有赋初值,默认值是false,表示核心线程超时不会被回收。

可以由方法设定,如果设置为true时,要保证线程空闲时间<=0,即表示空闲立马回收。

    private volatile boolean allowCoreThreadTimeOut;

    public void allowCoreThreadTimeOut(boolean value) {
        if (value && keepAliveTime <= 0)
            throw new IllegalArgumentException("Core threads must have nonzero keep alive times");

        allowCoreThreadTimeOut = value;
    }

④unit:表示时间单位

keepAliveTime的单位通常是TimeUnit.SECONDS.

⑤workQueue:表示缓存队列

当请求的线程数大于最大的线程并发数,线程会进入这个blockingQueue,阻塞保证出队入队的原子性

⑥threadFactory:线程工厂

用来生产一组相同任务的线程。

线程池的命名是通过给这个factory增加组名前缀来实现的。

虚拟机栈在分析时知道线程任务是那个线程工厂生产的。

⑦handler:表示拒绝策略的对象

当待执行的线程大于阻塞队列的最大值时,可以通过该策略处理请求,一种简单的限流保护,策略模式。

优雅的拒绝策略包括:

保存数据库进行消费填谷;在空闲的事再提取出来执行

转向某个提示页面

打印日志

2.1.1 corePoolSize 核心线程数量

    线程池中应该报纸的线程数量,即使线程处于空闲期间,线程也会存在于线程池,除非设置allowCoreThreadTimeOut这个参数是false。当线程池中的线程数量少于核心线程数量,线程池会创建一个新的线程来执行这个任务,即使线程池存在空闲线程也会创建新线程。等线程池中的线程数量等于信心线程数量,这时不会再产生线程,任务会被放在队列中。

如果嗲用线程池的prestartAllCoreThreads(),线程池会提前创建并启动所有核心线程。

    public int prestartAllCoreThreads() {
        int n = 0;
        while (addIfUnderCorePoolSize(null))
            ++n;
        return n;
    }

2.1.2 maximumPoolsize 线程池最大线程数,同时执行的线程

    线程池允许创建的最大线程数

若队列满,并且已经创建的线程数小于最大线程数(固定线程数),则线程池会再创建新的线程放入到works中执行任务。无界队列参数没用。cachedThreadPool无效。

原文地址:https://www.cnblogs.com/dc-earl/p/11122370.html

时间: 2024-08-02 02:09:40

Java并发:一篇搞定线程池的相关文章

和朱晔一起复习Java并发(一):线程池

和我之前的Spring系列文章一样,我们会以做一些Demo做实验的方式来复习一些知识点. 本文我们先从Java并发中最最常用的线程池开始. 从一个线程池实验开始 首先我们写一个方法来每秒一次定时输出线程池的基本信息: private void printStats(ThreadPoolExecutor threadPool){ Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> { log.info("

Java并发(八)计算线程池最佳线程数

目录 一.理论分析 二.实际应用 为了加快程序处理速度,我们会将问题分解成若干个并发执行的任务.并且创建线程池,将任务委派给线程池中的线程,以便使它们可以并发地执行.在高并发的情况下采用线程池,可以有效降低线程创建释放的时间花销及资源开销,如不使用线程池,有可能造成系统创建大量线程而导致消耗完系统内存以及“过度切换”(在JVM中采用的处理机制为时间片轮转,减少了线程间的相互切换) . 但是有一个很大的问题摆在我们面前,即我们希望尽可能多地创建任务,但由于资源所限我们又不能创建过多的线程.那么在高

Java并发编程——Executor接口及线程池的使用

在如今的程序里,单线程的程序,应该已经比较少了,而Java语言是内置支持多线程并发的,大家都说Java语言内置支持多线程,非常非常的强大和方便,但一直没有深入研究jdk内concurrent包.今天就认真学习了一下java.util.concurrent包,发现jdk多线程编程果然是强大和方便.本文是学习java.util.concurrent包内线程池及相关接口的一些总结. 任务接口抽象 Runnable接口 在java.lang包内,为多线程提供了Runnable接口. public int

【Java并发编程】21、线程池ThreadPoolExecutor源码解析

一.前言 JUC这部分还有线程池这一块没有分析,需要抓紧时间分析,下面开始ThreadPoolExecutor,其是线程池的基础,分析完了这个类会简化之后的分析,线程池可以解决两个不同问题:由于减少了每个任务调用的开销,它们通常可以在执行大量异步任务时提供增强的性能,并且还可以提供绑定和管理资源(包括执行任务集时使用的线程)的方法.下面开始分析. 二.ThreadPoolExecutor数据结构 在ThreadPoolExecutor的内部,主要由BlockingQueue和AbstractQu

Java并发编程、多线程、线程池…

Java多线程干货系列(1):Java多线程基础http://www.importnew.com/21136.html#comment-651146 40个Java多线程问题总结http://www.importnew.com/18459.html#comment-651217 Java线程面试题 Top 50http://www.importnew.com/12773.html Java并发编程:Thread类的使用http://www.cnblogs.com/dolphin0520/p/39

java并发编程(4)--线程池的使用

转载:http://www.cnblogs.com/dolphin0520/p/3932921.html 一. java中的ThreadPoolExecutor类 java.util.concurrent.ThreadPoolExecutor类时线程池中最核心的一个类,因此如果要透彻的了解java中线程池,必须先了解这个类.下面看ThreadPoolExecutor类的具体实现源码: 在ThreadPoolExecutor类中提供了四个构造方法: public class ThreadPoolE

java并发编程(2)线程池的使用

一.任务和执行策略之间的隐性耦合 Executor可以将任务的提交和任务的执行策略解耦 只有任务是同类型的且执行时间差别不大,才能发挥最大性能,否则,如将一些耗时长的任务和耗时短的任务放在一个线程池,除非线程池很大,否则会造成死锁等问题 1.线程饥饿死锁 类似于:将两个任务提交给一个单线程池,且两个任务之间相互依赖,一个任务等待另一个任务,则会发生死锁:表现为池不够 定义:某个任务必须等待池中其他任务的运行结果,有可能发生饥饿死锁 2.线程池大小 注意:线程池的大小还受其他的限制,如其他资源池:

《Java源码分析》:线程池 ThreadPoolExecutor

<Java源码分析>:线程池 ThreadPoolExecutor ThreadPoolExecutor是ExecutorService的一张实现,但是是间接实现. ThreadPoolExecutor是继承AbstractExecutorService.而AbstractExecutorService实现了ExecutorService接口. 在介绍细节的之前,先介绍下ThreadPoolExecutor的结构 1.线程池需要支持多个线程并发执行,因此有一个线程集合Collection来执行

Java 中几种常用的线程池

Java 中几种常用的线程池 转载 : https://www.cnblogs.com/sachen/p/7401959.html 原创 2016年04月14日 23:29:01 标签: java / 线程池 / Executor 878 概述: 在java内置API中操作线程所用到的类为Thread.创建线程一般有两种方式, 继承Thread方式 实现Runnable方式,并以runnable作为target创建Thread 在Android中的耗时任务一般都需要另开线程来执行,常常需要用线程