Java并发系列一《线程池原理》

目录

前言

一、线程池原理

1.线程池创建方式

2. 线程池7大参数

3.执行原理

二、源码分析

1.走进线程池 execute 方法

2.其他..

三、应用场景

四、总结



前言

本文内容线程池总结,包括线程池原理、线程池部分源码分析、线程池实践应用案例。 


一、线程池原理

提示:首先我们可以从线程池的7大参数为入口,展开讲下 多种阻塞队列、多种拒绝策略的异同。其次讲利用Excutors创建线程池的几种创建方式及存在的内存溢出等问题,最后讲线程池的执行原理,新建线程及线程回收的原理。

1.线程池创建方式

Executors类为我们提供了各种类型的线程池,经常使用的方法有:

public static ExecutorService newSingleThreadExecutor()
public static ExecutorService newFixedThreadPool(int nThreads)
public static ExecutorService newCachedThreadPool()
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)

但是阿里开发手册是不允许使用Executors类创建的,强制使用ThreadPoolExecutor创建线程池。

Executors创建线程池弊端如下

        newSingleThreadExecutor 和 newFixedThreadPool允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM。

         newCachedThreadPool 和 newScheduledThreadPool允许的创建的线程数为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM。

2. 线程池7大参数

        线程池构造方法之一:

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

① corePoolSize核心线程的数量,默认不会被回收掉,但是如果设置了allowCoreTimeOut为true,那么当核心线程闲置时,也会被回收。

② maximumPoolSize :线程池能容纳的最大线程数量,上限被CAPACITY限制(2^29-1)。

③ keepAliveTime:闲置线程被回收的时间限制,也就是闲置线程的存活时间。

④ unit :keepAliveTime的单位

⑤ workQueue :用于存放提交但未执行的任务。

        1.LinkedBlockingQueue:用链表实现的有界阻塞队列,容量可以选择进行设置,不设置的话,将是一个无边界的阻塞队列,最大长度为Integer.MAX_VALUE.

//上限为Integer最大值,内存耗尽风险。
public LinkedBlockingQueue() { this(Integer.MAX_VALUE); }

        2. ArrayBlockingQueue:用数组实现的有界阻塞队列,必须设置容量。

//队列容量可控,默认非公平锁
public ArrayBlockingQueue(int capacity) { his(capacity, false); }
//如果 fair==true 队列在插入或删除时访问阻塞的线程,按先进先出顺序处理,反之访问顺序未指定
public ArrayBlockingQueue(int capacity, boolean fair) {
        if (capacity <= 0)
            throw new IllegalArgumentException();
        this.items = new Object[capacity];
        lock = new ReentrantLock(fair);
        notEmpty = lock.newCondition();
        notFull =  lock.newCondition();
    }

⑥ threadFactory :创建线程的工厂类

⑦ handler:当任务执行失败时,使用handler通知调用者,代表拒绝的策略

JDK内置了四种拒绝策略:

  • DiscardOldestPolicy策略:丢弃任务队列中最早添加的任务,并尝试提交当前任务;

  • CallerRunsPolicy策略:调用主线程执行被拒绝的任务,这提供了一种简单的反馈控制机制,将降低新任务的提交速度。

  • DiscardPolicy策略:默默丢弃无法处理的任务,不予任何处理。

  • AbortPolicy策略:直接抛出异常,阻止系统正常工作。(默认策略)

3.执行原理

execute 源码分析


二、源码分析

1.走进线程池 execute 方法

由源码我们可以看出,execute 方法核心内容分为3步。上述注释里已经大致说明了 execute 方法的3步。

  • 第1步:空处理,线程数小于核心线程数,成功创建核心线程加入任务并退出。
  • 第2步:isRunning 方法判断线程池是否接受新任务并处理排队的任务 ,满足则将任务加入队列。
    • 内层的 if-else 用来处理线程池不接受新任务之前的线程已被销毁完的情况。
    • 线程池不接受新任务的情况是拒绝任务;线程已被销毁完的情况是新建非核心线程。
  • 第3步:核心线程数已满&&阻塞队列已满,则尝试创建非核心线程,失败则拒绝任务

代码如下:

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        int c = ctl.get();
        //如果当前线程数量小于核心线程数量,执行addWorker创建新线程执行command任务
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        //如果当前是运行状态,将任务放入阻塞队列,double-check线程池状态
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            //再次check,发现线程池状态不是运行状态了,移除刚才添加进来的任务并拒绝该任务
            if (! isRunning(recheck) && remove(command))
                reject(command);
            //处于运行状态,但是没有线程,创建线程
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        //尝试创建新的非核心线程,失败则reject任务
        else if (!addWorker(command, false))
            reject(command);
    }











2.其他..

代码如下():

 

...












三、应用场景

1.一次请求里多次调用其他系统接口。

        比如我们系统A生产环境,调用其他系统B的接口平均耗时100ms,但是一次请求中入参的list里有20条数据需要调用B系统。如果使用单线程方式,耗时=100ms*20=2秒,外加我们系统处理逻辑耗时+我们系统插入、修改以及查redis或者redis不存在时查库耗时,总的下来最少2秒多,但是生产接口是不允许耗时这么久的。因此就用线程池对该功能进行优化,将响应时间控制在300ms以内。

2.读取多个文件


四、总结

以上就是线程池的原理及源码分析,以及在何种情况下使用线程池的总结。

掌握:

  1. 线程池七大参数意义
  2. 线程池执行原理
  3. 何时新建、回收线程
  4. 应用场景

内容补充中...

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值