线程池开发的使用(3)

-->>继续跟踪代码到addIfUnderCorePoolSize(Runnable firstTask):函数名称就可以看出来这个函数要执行的什么;如果线程池的线程小于核心线程数corePoolSize就新建线程加入任务并启动线程【在今后的开发中尽量把需要做的功能在函数名体现出来】

private boolean addIfUnderCorePoolSize(Runnable firstTask) {
        Thread t = null;
        final ReentrantLock mainLock = this.mainLock;//获取当前线程池的锁
        mainLock.lock();//加锁
        try {
            /*
            这里线程池线程大小还需要判断一次;前面的判断过程中并没有加锁,因此可能在execute方法判断的时候poolSize小于corePoolSize,而判断完之后,在其他线程中又向线程池提交了任务,就可能导致poolSize不小于corePoolSize了,所以需要在这个地方继续判断
            */
            if (poolSize < corePoolSize && runState == RUNNING)
                t = addThread(firstTask);//新建线程
        } finally {
            mainLock.unlock();
        }
        if (t == null)
            return false;
        t.start();//若创建线程超过,就启动线程池的线程
        return true;
    }
    private Thread addThread(Runnable firstTask) {
        Worker w = new Worker(firstTask);//worker:ThreadPoolExecutor的内部类;
        Thread t = threadFactory.newThread(w);//使用线程工厂创建一个线程
        if (t != null) {
            w.thread = t;
            workers.add(w);//保存线程池正在运行的线程
            int nt = ++poolSize;//线程池的线程数加1
            if (nt > largestPoolSize)
                largestPoolSize = nt;
        }
        return t;
    }

-->>接下来定位worker类,看看线程池里的线程是如何执行的

上面的addIfUnderCorePoolSize(..)已经把线程启动了;现在就直接查看worker 的run()方法了

public void run() {
    try {
        Runnable task = firstTask;//该线程的第一个任务,执行完后就从阻塞队列取任务执行
        firstTask = null;
        while (task != null || (task = getTask()) != null) {//getTask()从队列去任务执行
            runTask(task);//线程执行任务
            task = null;
        }
    } finally {
        workerDone(this);//若任务全部执行完,就开始尝试去停止线程池;这部分代码就不再追踪下去,有兴趣的读者可以自己打开源码分析,不必害怕,学习大神们的编码方式,看源码能让你学习到很多
    }
}
 private void runTask(Runnable task) {
    final ReentrantLock runLock = this.runLock;
    runLock.lock();
    try {
        //多次检查线程池有没有关闭
        if (runState < STOP &&
            Thread.interrupted() &&
            runState >= STOP)
            thread.interrupt();
           
        boolean ran = false;
        //这里就可以继承ThreadPoolExecutor,并覆盖beforeExecute(...)该方法,来做一些执行任务之前的统计工作或者用来保存正在执行的任务
        beforeExecute(thread, task);
        try {
            task.run();
            ran = true;
            //这里就可以继承ThreadPoolExecutor,并覆盖beforeExecute(...)该方法,来做一些执行任务完成之后的统计工作或者用来保存正在执行的任务
            afterExecute(task, null);
            ++completedTasks;//统计总共执行的任务数
        } catch (RuntimeException ex) {
            if (!ran)
                afterExecute(task, ex);
            throw ex;
        }
    } finally {
        runLock.unlock();
    }
}

至此线程池基本的流程完了;

再说说我在项目中的使用:
MyExtendThreadPoolExecutor 继承了 ThreadPoolExecutor,并覆盖了其中的一些方法

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/f3ab44edbdc4f3781cc50dc6ad454faa.html