线程复用的实质就是在Tread内的Runnable的run()方法中不断的获取任务,执行任务。
线程池内将保留核心线程数量的死循环线程,其余线程在没有任务时在超时间后若再无任务则销毁(run()方法执行结束)。
任务获取:
ThreadPoolExecutor.getTask()这个方法内主要做3件事情:①检查线程池状态;②判断是否支持任务等待超时(timed);③跟据timed选择对应方法,从BlockingQueue中获取任务。
在第三步中涉及到BlockingQueue.poll(long timeout, TimeUnit unit)和BlockingQueue#take()两个方法,两个方法都会尝试阻塞当前线程直到被唤醒,差别在于第一个方法在到达等待时间后会自动唤醒,第二个方法只能主动唤醒。
BlockingQueue.poll(long timeout, TimeUnit unit)->Condition.awaitNanos(long nanosTimeout)->LockSupport.parkNanos(Object blocker, long nanos)->Unsafe.park(boolean b,long nanos)
BlockingQueue.take()->Condition.await()->LockSupport.park(Object blocker)->Unsafe.park(boolean b,long nanos)
执行任务:
ThreadPoolExecutor.runWorker(Worker w)上述方法由Worker.run()调用,当上述方法执行完毕同时Worker.run()也将执行完毕,对应当Thread将被销毁。其中当Worker.firstTask为Worker创建时传入的任务,所以在复用时为null,因此当ThreadPoolExecutor.getTask()返回null,线程结束。
唤醒线程:
当通过ThreadPoolExecutor.execute(Runnable command)方法传入任务时,若存活线程数已超过核心线程数(少于则直接新建Worker),并且线程池已处于运行状态(否则尝试通过新建Worker启动线程池),此时会去调用BlockingQueue.offer(E e)方法,将任务放入BlockingQueue之中,并调用Condition.signal()方法唤醒一个之前阻塞的线程(LockSupport.unpark(Thread thread))。
网友评论