深入理解Java多线程-线程池(ThreadPool)

本文深入探讨Java多线程中线程池的使用,包括核心线程数、最大线程数、存活时间等参数意义。讲解了线程池的四种策略:CallerRunsPolicy、AbortPolicy、DiscardPolicy、DiscardOldestPolicy。分析了常用线程池类型如FixedThreadPool、SingleThreadExecutor、CachedThreadPool和ScheduledThreadPool的工作原理,以及线程池的关闭方法。同时,文章还涵盖了自定义线程池和线程池源码解析,帮助理解线程池的内部机制。
摘要由CSDN通过智能技术生成

在java多线程开发中,一般使用线程的时候都是创建一个Thread对象,然后调用start方法执行,这样做没有什么问题,但是如果有多任务并发执行的时候,你可能需要频繁地创建多个线程来执行任务,这样会造成性能方面的问题,体现如下:

1.大量的线程的创建和销毁,本身就是一个很大的性能开销

2.大量线程同时运作的时候,会造成资源紧张,我们知道线程的底层机制就是切分CPU的时间,在大量线程互相抢占资源的时候,可能会造成阻塞现象

基于上面的原因,JDK为我们提供了线程池。线程池可以帮我们管理一定数量的线程,通过重复使用线程来避免大量线程的创建和销毁,从而提高了线程的使用效率

线程池的使用:

关于线程池,首先要了解ThreadPoolExecutor 类,创建线程池就是通过这个类去创建的,它的构造函数如下:

public ThreadPoolExecutor(int corePoolSize,    //核心线程数量
                          int maximumPoolSize,    //最大线程数量
                          long keepAliveTime,    //非核心线程的空余存活时间
                          TimeUnit unit,    //存活时间的单位
                          BlockingQueue<Runnable> workQueue,    //保存待执行任务的队列
                          ThreadFactory threadFactory,    //创建新线程使用的工厂
                          RejectedExecutionHandler handler // 当任务无法执行时的处理器
                          ) {

                }


下面来详细解析一下各个参数的含义:

1.corePoolSize (核心线程数量)

默认情况下,核心线程会一直处于存活状态,即使它们是闲置的。如果将ThreadPoolExecutor的allowCoreThreadTimeOut属性设置为true,那么核心线程也会在超时之后结束,超时时间就是参数中设置的keepAlivTime的值

值得注意的是,当线程数量小于核心线程数时,有任务要执行时,即使当前有空闲线程也会创建一个新的核心线程

2.maximumPoolSize(最大线程数量)

包括核心线程数 + 非核心线程数量,如果任务队列满的情况下,并且线程总数小于最大线程数,此时会创建一个新的线程来执行任务

3.keepAliveTime(非核心线程的存活时间)

意思是非核心线程在没有任务执行的情况下的最大的存活时间,也就是说非核心线程在空闲了一定时间以后就会挂掉,当然如果线程池设置 allowCoreThreadTimeOut(true),核心线程也一样会有这种存活期限

4.unit (存活时间单位)

5.workQueue(任务队列)

线程池中的任务队列,我们提交给线程池的Runnable任务就保存在这个队列中。这是一个BlockQueue类型的结构,属于阻塞队列, 类似于生产者消费者模式,队列中有任务的时候才能进行取出,当队列满的时候,添加也会被阻塞

6.threadFactory(创建线程的工厂)

通过这个工厂类,我们可以给创建线程取名字或者优先级之类的参数

7.handler (任务饱和策略)

主要有四种策略:

CallerRunsPolicy:只要线程池没有关闭,就直接用调用者所在线程来运行任务

AbortPolicy:直接抛出RejectedExecutionException异常

DiscardPolicy:不通知地把任务抛弃了,不干了

DiscardOldestPolicy:把队列中呆了最久的那个任务抛弃了,然后再调用execute方法重试

workQueue(任务队列)的分析:

线程池中使用的队列是BlockQueue接口,常用的实现有以下几种:

1.ArrayBlockingQueue:基于数组,有界,先进先出原则,一般不用

2.LinkedBlockingQueue:基于链表,按先进先出排序,Executors.newFixedThreadPool() 使用的就是个队列

3.SynchronousQueue:这个队列不保存任务,只负责传递,Executors.newCachedThreadPool就使用了这个队列,当有任务到来时如果当前没有空闲的线程,就会创建一个线程来执行新任务

4.PriorityBlockingQueue:具有优先级的任务队列

下面我们封装一个自己的线程池,代码如下:

public class MyThreadPool {

    private final String TAG = this.getClass().getSimpleName();
    // 核心线程数为 CPU数*2
    private static final int CORE_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; 
    private static final int MAXIMUM_POOL_SIZE = 64;    // 线程队列最大线程数
    private static final int KEEP_ALIVE_TIME = 1;    // 保持存活时间 1秒
    //任务队列
    private final BlockingQueue<Runnable> mWorkQueue = new LinkedBlockingQueue<>(128);
    //创建线程的工厂
    private final ThreadFactory DEFAULT_THREAD_FACTORY = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);

        public Thread newThread(Runnable r) {
            Thread thread = 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值