Java线程池理解与学习

简介: 线程过多就容易引发内存溢出,因此我们有必要使用线程池的技术线程池的好处降低资源消耗: 通过重复利用已创建的线程降低线程创建和销毁造成的消耗提高响应速度: 当任务到达时,任务可以不需要等待线程创建就能立即执行提高线程管理性: 线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源还会降低系统的稳定性,使用线程池可以进行统一的分配、调优和监控

线程过多就容易引发内存溢出,因此我们有必要使用线程池的技术


线程池的好处


降低资源消耗: 通过重复利用已创建的线程降低线程创建和销毁造成的消耗

提高响应速度: 当任务到达时,任务可以不需要等待线程创建就能立即执行

提高线程管理性: 线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源还会降低系统的稳定性,使用线程池可以进行统一的分配、调优和监控


线程池的创建


线程池的真正实现类是ThreadPoolExecutor,其中具有七个重要参数

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

corePoolSize

核心线程数。默认情况下核心线程会一直存活,但是当将allowsCoreThreadTimeOut设置为true时,核心线程也会超时回收。核心线程最开始并不会立即创建而是等任务来了再创建,然后存活下去


maximumPoolSize

最大线程数 。线程池所能容纳的最大线程数。当活跃线程数达到该数值后,后续的新任务将会阻塞。最大线程数 = 核心线程数 + 非核心线程数


keepAliveTime

非核心线程闲置超时时间 。如果超过该时长,非核心线程将会回收


unit

超时单位 。指定KeepAliveTime超时时间的单位。


workQueue

任务队列 。当核心线程全被使用的时候,且任务队列未满时候就会先将任务放到任务队列中


threadFactory

线程工厂 。用于指定为线程创建新线程的方式


handler

拒绝策略 。当最大线程数达到饱和时候需要执行的饱和策略


任务队列

任务队列是基于阻塞队列实现的,即采用生产者消费者模式,在Java中需要实现BlockingQueue接口,但Java已经为我们提供了7种阻塞队列的实现


ArrayBlockingQueue


一个由数组结构构成的有界阻塞队列(数组结构可配合指针实现一个环形队列)


LinkedBlockingQueue


一个由链表结构构成的有界阻塞队列,在未指明容量时默认为Integer.MAX_VALUE


PriorityBlockingQueue


一个支持优先级排序的无界队列,对元素没有要求,可以实现Comparable接口来进行比较


DelayQueue


类似于PriorityBlockingQueue,是二叉堆形成的无界优先队列。要求元素都实现DelayQueue接口,通过执行时延从队列中提取任务,时间没到任务取不出来


SynchronousQueue


一个不存储元素的阻塞队列,消费者线程调用take()方法时会发生阻塞,直到有一个生产者生产了一个元素,同理生产者调用put()方法


LinkedBlockingDeque


使用双向队列实现的有界双端阻塞队列。双端意味着可以像普通队列一样FIFO也可以像栈一样FILO


LinkedTransferQueue


这是一个无界队列


拒绝策略

当线程池的线程达到最大线程数时,需要执行拒绝策略,拒绝策略需要实现RejectedExecutionHandler接口,并实现rejectedExcution方法,Executors为我们实现了4种拒绝策略


AbortPolicy(默认):丢弃任务并抛出异常

CallerRunsPolicy:由调用线程处理该任务

DiscardPolicy:丢弃任务,但是不抛出异常

DiscardOldestPolicy:丢弃队列中最早未处理的异常

e82d158a6ee04d3487c060ad73788716.jpeg


功能线程池


定长线程池(newFixedThreadPool)

    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);
    }

特点 : 只有核心线程,线程数量固定,全是核心线程任务队列为链表的有界队列

应用场景: 控制线程最大并发数

缺点: 他的任务队列是LinkedBlockingQueue且没有指定容量,则当线程数满了之后就会一直放任务进任务队列,容易造成OOM


单线程化线程池(newSingleThreadExecutor)

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

特点:没有核心线程数只有非核心线程数,整个线程池表现为线程池数会根据任务量不断增长,没有增长,当任务执行完毕,空闲1分钟后释放线程

用途 :适合任务数比较密集,但每个任务执行时间较短的情况

缺点 : 如果任务多那么线程就会创建过多的线程,创建线程会很耗时并且容易导致OOM


定时线程池(newScheduledThreadPool)

    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }
    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }


特点: 和性能线程固定,非核心线程很多,执行完立即删除

应用场景: 执行定时或周期性的任务

缺点: 线程数量上限是Integer.MAX_VALUE


线程池中的方法

void execute(Runnable command);

执行任务


Future submit(Callable task)

提交任务task,用返回值Future获取任务执行结果


List<Future> invokeAll(Collection<? extends Callable> tasks)

提交tasks中所有的任务


List<Future> invokeAll(Collection<? extends Callable> tasks, long timeout, TimeUnit unit)

提交tasks中所有的任务带超时时间


T invokeAny(Collection<? extends Callable> tasks)

提交tasks中的任务那个先执行完毕返回该任务的结果其它任务取消


T invokeAny(Collection<? extends Callable> tasks,long timeout, TimeUnit unit)

提交tasks中的任务那个先执行完毕返回该任务的结果其它任务取消带超时时间


shutdown与shutdownnow


shutdown

线程池状态修改为SHUTDOWN

不会接收新的任务,但已提交的会执行完, 只打断空闲线程


shutdownnow

修改线程池状态为stop

不接收新任务、打断所有线程、会将队列中的任务返回


相关文章
|
1月前
|
安全 Java 测试技术
Java并行流陷阱:为什么指定线程池可能是个坏主意
本文探讨了Java并行流的使用陷阱,尤其是指定线程池的问题。文章分析了并行流的设计思想,指出了指定线程池的弊端,并提供了使用CompletableFuture等替代方案。同时,介绍了Parallel Collector库在处理阻塞任务时的优势和特点。
|
2月前
|
XML Java 编译器
Java学习十六—掌握注解:让编程更简单
Java 注解(Annotation)是一种特殊的语法结构,可以在代码中嵌入元数据。它们不直接影响代码的运行,但可以通过工具和框架提供额外的信息,帮助在编译、部署或运行时进行处理。
98 43
Java学习十六—掌握注解:让编程更简单
|
21天前
|
存储 监控 小程序
Java中的线程池优化实践####
本文深入探讨了Java中线程池的工作原理,分析了常见的线程池类型及其适用场景,并通过实际案例展示了如何根据应用需求进行线程池的优化配置。文章首先介绍了线程池的基本概念和核心参数,随后详细阐述了几种常见的线程池实现(如FixedThreadPool、CachedThreadPool、ScheduledThreadPool等)的特点及使用场景。接着,通过一个电商系统订单处理的实际案例,分析了线程池参数设置不当导致的性能问题,并提出了相应的优化策略。最终,总结了线程池优化的最佳实践,旨在帮助开发者更好地利用Java线程池提升应用性能和稳定性。 ####
|
18天前
|
监控 Java 开发者
深入理解Java中的线程池实现原理及其性能优化####
本文旨在揭示Java中线程池的核心工作机制,通过剖析其背后的设计思想与实现细节,为读者提供一份详尽的线程池性能优化指南。不同于传统的技术教程,本文将采用一种互动式探索的方式,带领大家从理论到实践,逐步揭开线程池高效管理线程资源的奥秘。无论你是Java并发编程的初学者,还是寻求性能调优技巧的资深开发者,都能在本文中找到有价值的内容。 ####
|
1月前
|
监控 安全 Java
在 Java 中使用线程池监控以及动态调整线程池时需要注意什么?
【10月更文挑战第22天】在进行线程池的监控和动态调整时,要综合考虑多方面的因素,谨慎操作,以确保线程池能够高效、稳定地运行,满足业务的需求。
112 38
|
25天前
|
存储 缓存 监控
Java中的线程池深度解析####
本文深入探讨了Java并发编程中的核心组件——线程池,从其基本概念、工作原理、核心参数解析到应用场景与最佳实践,全方位剖析了线程池在提升应用性能、资源管理和任务调度方面的重要作用。通过实例演示和性能对比,揭示合理配置线程池对于构建高效Java应用的关键意义。 ####
|
1月前
|
Java 大数据 API
14天Java基础学习——第1天:Java入门和环境搭建
本文介绍了Java的基础知识,包括Java的简介、历史和应用领域。详细讲解了如何安装JDK并配置环境变量,以及如何使用IntelliJ IDEA创建和运行Java项目。通过示例代码“HelloWorld.java”,展示了从编写到运行的全过程。适合初学者快速入门Java编程。
|
2月前
|
存储 SQL 小程序
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))
这篇文章详细介绍了Java虚拟机(JVM)的运行时数据区域和JVM指令集,包括程序计数器、虚拟机栈、本地方法栈、直接内存、方法区和堆,以及栈帧的组成部分和执行流程。
41 2
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))
|
1月前
|
Prometheus 监控 Cloud Native
JAVA线程池监控以及动态调整线程池
【10月更文挑战第22天】在 Java 中,线程池的监控和动态调整是非常重要的,它可以帮助我们更好地管理系统资源,提高应用的性能和稳定性。
97 4
|
1月前
|
JavaScript Java 项目管理
Java毕设学习 基于SpringBoot + Vue 的医院管理系统 持续给大家寻找Java毕设学习项目(附源码)
基于SpringBoot + Vue的医院管理系统,涵盖医院、患者、挂号、药物、检查、病床、排班管理和数据分析等功能。开发工具为IDEA和HBuilder X,环境需配置jdk8、Node.js14、MySQL8。文末提供源码下载链接。