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

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


相关文章
|
2月前
|
Java 调度 数据库
Java并发编程:深入理解线程池
在Java并发编程的海洋中,线程池是一艘强大的船,它不仅提高了性能,还简化了代码结构。本文将带你潜入线程池的深海,探索其核心组件、工作原理及如何高效利用线程池来优化你的并发应用。
|
2月前
|
存储 监控 Java
Java多线程优化:提高线程池性能的技巧与实践
Java多线程优化:提高线程池性能的技巧与实践
70 1
|
2月前
|
安全 Java 数据库
一天十道Java面试题----第四天(线程池复用的原理------>spring事务的实现方式原理以及隔离级别)
这篇文章是关于Java面试题的笔记,涵盖了线程池复用原理、Spring框架基础、AOP和IOC概念、Bean生命周期和作用域、单例Bean的线程安全性、Spring中使用的设计模式、以及Spring事务的实现方式和隔离级别等知识点。
|
2月前
|
存储 监控 安全
一天十道Java面试题----第三天(对线程安全的理解------>线程池中阻塞队列的作用)
这篇文章是Java面试第三天的笔记,讨论了线程安全、Thread与Runnable的区别、守护线程、ThreadLocal原理及内存泄漏问题、并发并行串行的概念、并发三大特性、线程池的使用原因和解释、线程池处理流程,以及线程池中阻塞队列的作用和设计考虑。
|
24天前
|
设计模式 架构师 Java
Java开发工程师转架构师需要学习什么
Java开发工程师转型为架构师需掌握多项技能:精通Java及框架、数据库与分布式系统;熟悉设计模式与架构模式;积累项目经验;提升沟通与领导力;持续学习新技术;培养系统设计与抽象能力;了解中间件及开发工具;并注重个人特质与职业发展。具体路径应结合个人目标与实际情况制定。
46 18
|
1月前
|
监控 Java 调度
【Java学习】多线程&JUC万字超详解
本文详细介绍了多线程的概念和三种实现方式,还有一些常见的成员方法,CPU的调动方式,多线程的生命周期,还有线程安全问题,锁和死锁的概念,以及等待唤醒机制,阻塞队列,多线程的六种状态,线程池等
108 6
【Java学习】多线程&JUC万字超详解
|
1月前
|
Java 调度 开发者
Java并发编程:深入理解线程池
在Java的世界中,线程池是提升应用性能、实现高效并发处理的关键工具。本文将深入浅出地介绍线程池的核心概念、工作原理以及如何在实际应用中有效利用线程池来优化资源管理和任务调度。通过本文的学习,读者能够掌握线程池的基本使用技巧,并理解其背后的设计哲学。
|
1月前
|
缓存 监控 Java
Java中的并发编程:理解并应用线程池
在Java的并发编程中,线程池是提高应用程序性能的关键工具。本文将深入探讨如何有效利用线程池来管理资源、提升效率和简化代码结构。我们将从基础概念出发,逐步介绍线程池的配置、使用场景以及最佳实践,帮助开发者更好地掌握并发编程的核心技巧。
|
1天前
|
存储 NoSQL Java
使用 Java 了解和学习 NoSQL 数据库:三个主要优势
使用 Java 了解和学习 NoSQL 数据库:三个主要优势
5 0
|
1月前
|
缓存 监控 Java
java中线程池的使用
java中线程池的使用