java的线程池ThreadPoolExecutor原理解析

本文深入解析Java线程池实现类ThreadPoolExecutor,包括基本使用、工作原理图解和源码分析。重点探讨了核心线程数、最大线程数、保活时间和阻塞队列等关键概念,以及execute方法、addWorker和runWorker的执行流程。通过源码解析,帮助读者理解线程池的工作机制和拒绝策略。
摘要由CSDN通过智能技术生成

使用多线程,必然要用到线程池,而ThreadPoolExecutor是java中线程池的重要实现类,理解ThreadPoolExecutor有助于我们更好地理解线程池、甚至去自定义自己的线程池。

基本使用

  1. 初始化线程池
Executor executor=new ThreadPoolExecutor(0,Integer.MAX_VALUE,60, TimeUnit.MILLISECONDS,new SynchronousQueue<Runnable>());
  1. 执行对应的任务
executor.execute(runnable);

原理图解

我们先来看一下ThreadPoolExecutor的工作原理图解,不明白不要紧,再继续看完源码分析便会明白了
ThreadPoolExecutor工作原理图解

源码分析

源码中,我们重点分析构造方法和几个重要的方法,execute、addWorker、runWorker和getTask

  1. 构造方法及参数
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler)
  • int corePoolSize:核心线程数量,线程池中始终保持活跃的线程数量,不管有无任务,该数量的线程始终在运行或者等待运行
  • int maximumPoolSize:线程池最大数量,线程中最大允许的线程数量,任务多于该数量时便会使用拒绝策略去拒绝执行任务
  • long keepAliveTime、TimeUnit unit:保活时间,如果线程空闲时,还能保持活跃多久
  • BlockingQueue workQueue:阻塞队列,如果任务现在无法直接执行,则会考虑放到队列中等待,运行中的任务执行完后再从队列中取出任务一一执行
  • RejectedExecutionHandler handler:拒绝策略,如果收到的任务多于线程池最大数量,则会使用拒绝策略去拒绝执行
  1. execute执行任务 方法分析:对外提供的执行任务方法,也是线程池的入口方法
  • 分析前,先介绍几个重要的数据结构
    • Worker: 负责运行任务的中断控制和任务的管理,实现了runnable接口,持有一个Thread对象
    • 运行时任务集合:private final HashSet workers = new HashSet<>();
    • 阻塞队列:private final BlockingQueue workQueue;
  • execute方法分析
    1. 首先判断核心线程数是否已满,未满则作为核心线程去执行
    2. 队列是否已满,未满则放到队列中等待执行
    3. 线程池是否已满,未满则分配非核心线程执行
    4. 否则使用拒绝策略
public void execute(Runnable command) {
    int c = ctl.get();
    //1. 运行任务数和核心线程数作比较
    //   如果运行任务数少,则新建一个线程作为核心线程,并执行该任务
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
    //2. 如果一个任务能够放到队列中
    //     再次检查,当前线程池状态不是RUNNING,则回滚队列并使用拒绝策略
    //     如果当前线程池线程为空,则添加该任务并执行
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
    //3. 如果能放到线程池中,则作为非核心线程去执行
    //4. 否则使用拒绝策略进行拒绝
        else if (!addWorker(command, false))
            reject(command);
    }
  • worker之addWorker,添加任务
    1. 创建Worker和线程
    2. 将worker添加到集合中
    3. 让线程开始执行
private boolean addWorker(Runnable firstTask, boolean core) {
    boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
        	//1. 创建Worker和线程
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    //2. 将worker添加到集合中
                    int rs = runStateOf(ctl.get());
                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        workers.add(w);
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                //3. 让线程开始执行
                if (workerAdded) {
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
}
  • worker之runWorker: 真正的执行任务,上一步的线程执行时,因为持有的是worker任务,所以线程执行会调用worker的runWorker方法
    1. 先执行当前任务
    2. 当前任务为空就通过getTask方法从阻塞队列中依次拿出任务去执行
    3. 任务执行分为三个小步骤
      • 做执行前的准备工作
      • 执行任务
      • 做执行后的善后工作
final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
           //1. 此行为关键代码,循环获取任务并执行
            while (task != null || (task = getTask()) != null) {
                w.lock();
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                  //执行前做一些准备工作
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                       //执行任务
                        task.run();
                    } catch (RuntimeException x) {
                        thrown = x; throw x;
                    } catch (Error x) {
                        thrown = x; throw x;
                    } catch (Throwable x) {
                        thrown = x; throw new Error(x);
                    } finally {
                       //执行任务后的善后工作
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
        	//处理worker退出
            processWorkerExit(w, completedAbruptly);
        }
    }
  • getTask方法:获取任务
    1. 检查一:线程终止,并且队列为空时,直接返回
    2. 检查二:工作线程数目以及是否超时
    3. 根据超时状态从队列中取出任务
private Runnable getTask() {
		//标记是否超时
        boolean timedOut = false; // Did the last poll() time out?
		//无限循环从队列中获取任务,无任务时线程会阻塞等待任务,不消耗CPU资源
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);
            //1. 检查一:线程终止且队列为空,直接返回null
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }
            int wc = workerCountOf(c);
            //标记线程是否可以超时停止
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
			//2. 检查二:工作线程数目以及是否超时
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }
			//3. 从队列中取出任务并返回
            try {
            	//poll方法:从BlockingQueue取出一个队首的对象,如果在指定时间内,
            队列一旦有数据可取,则立即返回队列中的数据。否则知道时间超时还没有数据可取,返回null
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }
  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值