自己动手写线程池——向JDK线程池进发( 四 )

工作线程的工作实现    @Override    public void run() {      // 先执行传递过来的第一个任务 这里是一个小的优化 让线程直接执行第一个任务 不需要      // 放入任务队列再取出来执行了      firstTask.run();      thisThread = Thread.currentThread();      while (!isStopped) {        try {          // 是否使用时间就在这里显示出来了          Runnable task = useTimed ? taskQueue.poll(keepAliveTime, unit) : taskQueue.take();          if (task == null) {            int i;            boolean exit = true;            // 如果当前线程数大于核心线程数 则使用 CAS 去退出 用于保证在线程安全下的退出            // 且保证线程的个数不小于 corePoolSize 下面这段代码需要仔细分析一下            if (ct.get() > corePoolSize) {              do{                i = ct.get();                if (i <= corePoolSize) {                  exit = false;                  break;                }              }while (!ct.compareAndSet(i, i - 1));              if (exit) {                return;              }            }          }else {            task.run();          }        } catch (InterruptedException e) {          // do nothing        }      }    }我们现在来仔细分析一下,线程退出线程池的时候是如何保证线程池当中总的线程数是不小于 corePoolSize 的!首先整体的框架是使用 CAS 进行实现,具体代码为 do ... while 操作,然后在 while 操作里面使用 CAS 进行测试替换,如果没有成功再次获取,当线程池当中核心线程的数目小于等于 corePoolSize 的时候也需要退出循环,因为线程池当中线程的个数不能小于 corePoolSize。因此使用 break 跳出循环的线程是不会退出线程池的 。
线程池实现的BUG在我们自己实现的线程池当中当线程退出的时候,workers 当中还保存这指向这个线程的对象,但是当线程退出的时候我们还没有在 workers 当中删除这个对象,因此这个线程对象不会被垃圾回收器收集掉,但是我们这个只是一个线程池实现的例子而已,并不用于生产环境,只是为了帮助大家理解线程池的原理 。

经验总结扩展阅读