`

简洁之美-java5线程池源码赏析(下)

阅读更多

简洁之美-java5线程池源码赏析(下)

            by  davy

在上篇中,大家了解线程池对线程的控制,本篇将重点介绍线程是如何被复用的。其实关键就在于,addIfUnderCorePoolSizecommand)和addIfUnderMaximumPoolSize(command)新建立的线程会不停地从缓冲队列里获取待执行的任务并执行。只要线程池的缓冲队里有任务,线程就不会消亡,就会得到复用。缓冲队列里没有待处理的任务,并且线程超过了预定义的允许空闲时间,线程就会消亡。接下来看一下addIfUnderCorePoolSizeRunnable command)方法,其代码如下:

privateboolean 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();

        }

        if (t == null)  returnfalse;

        t.start();

        returntrue;

 }

简单地说,就是先建立线程,并启动线程。我们关心的是线程启动后,其执行的任务时什么。addThread(firstTask)的代码如下:

private Thread addThread(Runnable firstTask)

{

        Worker w = new Worker(firstTask);

        Thread t = threadFactory.newThread(w);

        if (t != null) {

            w.thread = t;

            workers.add(w);

            int nt = ++poolSize;

            if (nt > largestPoolSize)

                largestPoolSize = nt;

        }

        return t;

 }

Worker是一个内部类,是对真正要执行的任务的包装。Thread t = threadFactory.newThread(w);其实就是新建立了一个Thread实例t,并使该线程ttarget=W(Worker).这样当线程t启动后,Worker.run()会执行。下面就来看一下Worker的真面目吧,代码如下(限于篇幅只贴关键代码):

        publicvoid run()

 {

            Try

 {

                Runnable task = firstTask;

                firstTask = null;

                while (task != null || (task = getTask()) != null)

{

                    runTask(task);

                    task = null;

                }

            } finally

{

                workerDone(this);

            }

        }

    重点就是while循环,当前处理的任务不为null就执行当前的任务;如果当前处理的任务是null就从线程池的缓冲队列里获取任务来执行。getTask()其实就是从缓冲队列取出任务,不再详细介绍。也就是说,只要缓冲队列里还有待处理的任务,Workerrun()方法就会执行下去,而执行WorkerThread实例t就不会空闲,不会消亡。这样线程就得到了复用。

    篇后语:

    高手就是高手,顶级高手的代码没有过多的华丽,其朴素、精炼、简洁令人叹为观止。JDK中随处可见顶级高手的代码,不妨观摩拜读。在jdk1.5线程池的代码中,没有Synchronized关键字,用的都是Lock和同步(阻塞)队列,因为后者的性能更优。在下才疏学浅,生怕粗俗肤浅的理解会亵渎高手的代码。因此,文中不当之处,恳请大家批评指正,不胜感激。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics