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

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


相关文章
|
3天前
|
缓存 Java
深入理解Java并发编程:线程池的应用与优化
【5月更文挑战第30天】本文将深入探讨Java并发编程中的一个重要主题——线程池。我们将详细解析线程池的概念、应用及其优化方法,帮助读者更好地理解和使用线程池,提高程序的性能和效率。
|
2天前
|
缓存 监控 安全
Java的线程池和线程安全
Java的线程池和线程安全
|
1天前
|
JavaScript Java 测试技术
Java项目基于ssm+vue.js的网络类课程思政学习系统附带文章和源代码设计说明文档ppt
Java项目基于ssm+vue.js的网络类课程思政学习系统附带文章和源代码设计说明文档ppt
5 0
|
2天前
|
缓存 安全 Java
Java的线程池与并发工具类技术性文章
Java的线程池与并发工具类技术性文章
7 0
|
2天前
|
Java
Java并发编程:深入理解线程池
【5月更文挑战第30天】本文将深入探讨Java并发编程中的一个重要概念——线程池。我们将了解线程池的基本概念,如何创建和使用线程池,以及线程池的优点和缺点。此外,我们还将讨论一些与线程池相关的高级主题,如自定义线程工厂,拒绝策略和线程池的关闭。通过本文,读者将对Java线程池有一个全面的理解,并能在实际开发中有效地使用线程池。
|
2天前
|
Java 调度
如何合理设置Java线程池大小
如何合理设置Java线程池大小
6 0
|
3天前
|
监控 Java 调度
Java并发编程:线程池的原理与实践
【5月更文挑战第30天】 在现代软件开发中,尤其是Java应用中,并发编程是一个不可忽视的领域。线程池作为提升应用性能和资源利用率的关键技术之一,其正确使用和优化对系统稳定性和效率至关重要。本文将深入探讨线程池的核心原理、常见类型以及在实际开发中的使用案例,旨在帮助开发者更好地理解和运用线程池技术,构建高性能的Java应用程序。
|
3天前
|
监控 算法 Java
深入理解Java并发编程:线程池的应用与优化
【5月更文挑战第30天】 在Java开发中,线程是实现并发处理的基础。然而,随着系统复杂性的增加和资源管理的需要,合理利用线程池已成为提升性能、保证系统稳定性的关键策略。本文将探讨线程池的核心原理,分析其应用场景,并提出优化线程池性能的实践建议,旨在帮助开发者更高效地使用Java进行并发编程。
|
3天前
|
安全 Java 调度
Java并发编程:线程池深入解析
【5月更文挑战第29天】本文将详细探讨Java中的线程池技术,包括其基本原理、使用方法以及在实际开发中的应用。我们将通过实例代码和性能分析,深入理解线程池的优势和潜在问题,为高效、安全的并发编程提供指导。
|
3天前
|
监控 Java 开发者
深入理解Java并发编程:线程池的工作原理与实践
【5月更文挑战第29天】 在现代Java应用开发中,高效地管理并发任务是至关重要的。本文将深入探讨Java线程池的核心机制,揭示其背后的设计哲学和运作模式。通过分析线程池的优势、工作过程及关键参数,结合实例演示如何合理配置和优化线程池以提高应用程序的性能和响应能力。