线程池中为什么要使用阻塞队列?

在线程池中活跃线程数达到corePoolSize时,线程池将会将后续的task提交到BlockingQueue中,为什么这样设计呢?

在一个task提交到线程池时,假设可以被线程池中的一个线程执行,则进行以下过程:

exeute ---》addWorker(Runnable command, boolean core)---》workers.add(w),启动线程执行任务(获取全局锁ReentrantLock mainLock

具体源码如下:

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        int c = ctl.get();
        //如果当前正在运行的线程数小于corePoolSize,则创建新的线程
        //执行当前任务
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        //如果当前运行的线程数大于等于corePoolSize或者线程创建失败
        //则把当前任务放入工作队列
        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);
        }
        //如果线程池任务无法加入到工作队列(说明工作队列满了)
        //创建一个线程执行任务。如果新创建后当前运行的线程数大于
        //maximumPoolSize则拒绝执行任务
        else if (!addWorker(command, false))
            reject(command);
    }
private boolean addWorker(Runnable firstTask, boolean core){
        //省略部分代码
        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            //这里就将提交的任务封装成为Worker了
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
                //使用加锁的方式原子添加工作线程
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    //在获得锁期间再次检查线程池的运行状态:如果
                    //线程池已经关闭或者任务为空则抛出异常
                    int rs = runStateOf(ctl.get());
                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) 
                            throw new IllegalThreadStateException();
                        //加入Worker数组
                        workers.add(w);
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                    //如果添加成功则启动线程执行任务
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

上述代码中:

w = new Worker(firstTask);
final Thread t = w.thread;

Worker实现了Runnable接口,里面定义了一个final变量Thread thread

Worker的构造函数为:

Worker(Runnable firstTask) {
       setState(-1); // inhibit interrupts until runWorker
       this.firstTask = firstTask;
       this.thread = getThreadFactory().newThread(this);
}
run函数为:

public void run() {
       runWorker(this);
}
final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
            while (task != null || (task = getTask()) != null) {
                w.lock();
                try {
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    task.run();
                    afterExecute(task, thrown);
                } finally {
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
   }

看完上述代码后,我们可以得出:

线程池创建线程需要获取mainlock这个全局锁,影响并发效率,阻塞队列可以很好的缓冲。

另外一方面,如果新任务的到达速率超过了线程池的处理速率,那么新到来的请求将累加起来,这样的话将耗尽资源。

你可能感兴趣的:(并发多线程)