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

来源:互联网 发布:sql联合主键查询 编辑:程序博客网 时间:2024/06/06 15:50

在线程池中活跃线程数达到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这个全局锁,影响并发效率,阻塞队列可以很好的缓冲。

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

原创粉丝点击