我是靠谱客的博主 无奈眼睛,最近开发中收集的这篇文章主要介绍线程池讲解之ThreadPoolExecutor,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

ThreadPoolExecutor核心参数:

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

ThreadPoolExecutor核心参数简介:

  • corePoolSize:核心线程数
  • maximumPoolSize:最大线程数
  • keepAliveTime:线程存活时间
  • unit:线程存活时间的时间单位
  • workQueue:阻塞队列
  • threadFactory:线程工厂
  • handler:拒绝策略

ThreadPoolExecutor核心参数执行作用(重点+常见问题): 

当线程数小于核心线程数(corePoolSize)时,通过线程工厂(threadFactory)创建线程并执行任务。

当线程数大于等于核心线程数(corePoolSize)且阻塞队列(workQueue)未满时,将任务放入阻塞队列中等待执行。

当线程数大于等于核心线程数(corePoolSize)、阻塞队列(workQueue)已满并且线程数小于最大线程数(maximumPoolSize)时,创建线程并执行任务。

当线程数大于最大线程数(maximumPoolSize)时,触发拒绝策略(handler)。

 源码解析(jdk1.6):

public class ThreadPoolExecutor extends AbstractExecutorService {

    //执行任务时的入口
    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
		//addIfUnderCorePoolSize线程数小于核心线程数时执行该方法
        if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
			//调用队列的offer方法将任务插入队列,若队列已满则返回false
            if (runState == RUNNING && workQueue.offer(command)) {
                if (runState != RUNNING || poolSize == 0)
                    ensureQueuedTaskHandled(command);
            }
			//addIfUnderMaximumPoolSize线程数大于核心线程、小于最大线程并且阻塞队列已满
            else if (!addIfUnderMaximumPoolSize(command))
				//如果线程数大于最大核心线程数时执行拒绝策略
                reject(command); // is shutdown or saturated
        }
    }

    private boolean addIfUnderCorePoolSize(Runnable firstTask) {
        Thread t = null;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
			//线程数小于核心线程数时执行该方法
            if (poolSize < corePoolSize && runState == RUNNING)
                t = addThread(firstTask);//创建线程并执行封装好的任务
        } finally {
            mainLock.unlock();
        }
        return t != null;
    }

    private boolean addIfUnderMaximumPoolSize(Runnable firstTask) {
        Thread t = null;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
			//线程数大于核心线程、小于最大线程并且阻塞队列已满
            if (poolSize < maximumPoolSize && runState == RUNNING)
                t = addThread(firstTask);
        } finally {
            mainLock.unlock();
        }
        return t != null;
    }


    //拒绝策略
    void reject(Runnable command) {
		//调用接口方法
        handler.rejectedExecution(command, this);
    }
}

常见的阻塞队列有哪些?

  • ArrayBlockingQueue:数组实现的有界阻塞队列。
  • LinkedBlockingQueue:链表实现的无界阻塞队列。
  • PriorityBlockingQueue:数组实现的无界且优先排序的阻塞队列。

 拒绝策略有哪些?

  • AborPolicy : 直接抛出异常。默认策略。
  • CallerRunsPolicy : 用调用者所在的线程来执行。
  • DiscardOldesPolicy ; 丢弃阻塞队列中最前的任务,并执行当前任务。
  • DiscardPolicy : 直接丢弃任务。
  • 自定义:实现RejectedExecutionHandler接口。

 核心线程(corePoolSize)在执行完任务后会被怎么处理?

结合代码讲解~~~,创建线程并执行任务的主要方法:addThread(runnable)

    private Thread addThread(Runnable firstTask) {
        Worker w = new Worker(firstTask);
        Thread t = threadFactory.newThread(w);
        boolean workerStarted = false;
        if (t != null) {
            if (t.isAlive()) // precheck that t is startable
                throw new IllegalThreadStateException();
            w.thread = t;
            workers.add(w);
            int nt = ++poolSize;
            if (nt > largestPoolSize)
                largestPoolSize = nt;
            try {
                t.start();
                workerStarted = true;
            }
            finally {
                if (!workerStarted)
                    workers.remove(w);
            }
        }
        return t;
    }

 从代码中可以开到最终将任务封装成Worker对象,而Worker类实现了Runnable接口所有其本身也可以让线程执行。

直接上Worker类的主要方法~~~

    private final class Worker implements Runnable {

        /**
         * 线程启动时调用的run方法
         */
        public void run() {
            try {
                hasRun = true;
                Runnable task = firstTask;
                firstTask = null;
				//task != null 判定用来执行当前任务,task = getTask()) != null用来执行队列中的任务等等
                while (task != null || (task = getTask()) != null) {
					//执行任务
                    runTask(task);
                    task = null;
                }
            } finally {
                workerDone(this);
            }
        }
    }

到这里还是没有说的重点啊~~~不要急重点就在getTask()方法中~~~

    Runnable getTask() {
        for (;;) {
            try {
                int state = runState;
                if (state > SHUTDOWN)
                    return null;
                Runnable r;
                if (state == SHUTDOWN)  // Help drain queue
                    r = workQueue.poll();
				//poolSize > corePoolSize表示非核心线程进行销毁,allowCoreThreadTimeOut主要用来判定核心线程是否可以销毁,可设置
                else if (poolSize > corePoolSize || allowCoreThreadTimeOut)
					//keepAliveTime线程存活时间,从队列中拿任务时,若队列为空则在keepAliveTime时间内阻塞线程
                    r = workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);
                else
					//若队列为空时阻塞核心线程,等待添加任务
                    r = workQueue.take();
                if (r != null)
                    return r;
                if (workerCanExit()) {
                    if (runState >= SHUTDOWN) // Wake up others
                        interruptIdleWorkers();
                    return null;
                }
                // Else retry
            } catch (InterruptedException ie) {
                // On interruption, re-check runState
            }
        }
    }

问题总结:核心线程在执行完任务后会到阻塞队列中获取任务进行执行,若队列中没有任务则挂起线程等待任务,若将allowCoreThreadTimeOut属性设置为true则在等待超时后销毁线程。

 非核心线程在执行完任务后会被怎么处理?

源码就不在粘贴了,查看上面的代码吧~~~

非核心线程执行完任务后也会到阻塞队列中获取任务执行,若没有任务根据存活时间(keepAliveTime)等待超时候销毁线程。

最后

以上就是无奈眼睛为你收集整理的线程池讲解之ThreadPoolExecutor的全部内容,希望文章能够帮你解决线程池讲解之ThreadPoolExecutor所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(39)

评论列表共有 0 条评论

立即
投稿
返回
顶部