Lors de l'utilisation du pool de threads, après avoir appelé la méthode shutdown(), le pool de threads n'acceptera plus de nouvelles tâches d'exécution. Cependant, les tâches placées dans la file d'attente des tâches avant d'appeler la méthode shutdown() doivent encore être exécutées. Cette méthode est une méthode non bloquante et sera renvoyée immédiatement après avoir été appelée. Elle n'attendra pas que toutes les tâches de la file d'attente des tâches soient exécutées avant de revenir. Jetons un coup d'œil au code source de la méthode shutdown(), comme indiqué ci-dessous.
public void shutdown() { //获取线程池的全局锁 final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { //检查是否有关闭线程池的权限 checkShutdownAccess(); //将当前线程池的状态设置为SHUTDOWN advanceRunState(SHUTDOWN); //中断Worker线程 interruptIdleWorkers(); //为ScheduledThreadPoolExecutor调用钩子函数 onShutdown(); // hook for } finally { //释放线程池的全局锁 mainLock.unlock(); } //尝试将状态变为TERMINATED tryTerminate(); }
En général, le code de la méthode shutdown() est relativement simple. Elle vérifie d'abord s'il y a l'autorisation de fermer le pool de threads, s'il y a l'autorisation, elle vérifie à nouveau s'il y a l'autorisation d'interrompre le thread de travail. il n'y a pas d'autorisation, cela lancera une exception SecurityException, le code est le suivant.
//检查是否有关闭线程池的权限 checkShutdownAccess(); //将当前线程池的状态设置为SHUTDOWN advanceRunState(SHUTDOWN); //中断Worker线程 interruptIdleWorkers();
Parmi eux, le code d'implémentation de la méthode checkShutdownAccess() est le suivant.
private void checkShutdownAccess() { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPermission(shutdownPerm); final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { for (Worker w : workers) security.checkAccess(w.thread); } finally { mainLock.unlock(); } } }
Le code de la méthode checkShutdownAccess() est relativement simple à comprendre. Il s'agit de détecter si vous avez l'autorisation de fermer le pool de threads, pendant lequel le verrouillage global du pool de threads est utilisé.
Ensuite, regardons le code source de la méthode advanceRunState(int), comme indiqué ci-dessous.
private void advanceRunState(int targetState) { for (;;) { int c = ctl.get(); if (runStateAtLeast(c, targetState) || ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c)))) break; } }
La logique globale de la méthode advanceRunState(int) est de déterminer si l'état actuel du pool de threads est l'état spécifié. L'état transmis dans la méthode shutdown() est SHUTDOWN. S'il est SHUTDOWN, il sera renvoyé directement ; si ce n'est pas SHUTDOWN, alors définit l'état actuel du pool de threads sur SHUTDOWN.
Ensuite, regardons la méthode interrompuIdleWorkers() appelée par la méthode showdown(), comme indiqué ci-dessous.
private void interruptIdleWorkers() { interruptIdleWorkers(false); }
Vous pouvez voir que la méthode interrompuIdleWorkers() appelle la méthode interrompuIdleWorkers(boolean), continuez à regarder le code source de la méthode interrompuIdleWorkers(boolean), comme indiqué ci-dessous.
private void interruptIdleWorkers(boolean onlyOne) { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { for (Worker w : workers) { Thread t = w.thread; if (!t.isInterrupted() && w.tryLock()) { try { t.interrupt(); } catch (SecurityException ignore) { } finally { w.unlock(); } } if (onlyOne) break; } } finally { mainLock.unlock(); } }
La logique globale du code ci-dessus est la suivante : obtenir le verrou global du pool de threads, parcourir tous les threads de travail, détecter si le thread est interrompu, sinon, et le thread de travail obtient le verrou, exécuter la méthode d'interruption du thread et relâchez-le Le verrou acquis par le thread. À ce stade, si le paramètre onlyOne est vrai, quittez la boucle. Sinon, parcourez tous les threads de travail et effectuez la même opération. Enfin, le verrou global du pool de threads est libéré.
Ensuite, jetons un coup d'œil à la méthode shutdownNow().
Si la méthode shutdownNow() du pool de threads est appelée, le pool de threads n'acceptera plus de nouvelles tâches d'exécution, et les tâches existantes dans la file d'attente des tâches seront ignorées, et le thread de travail en cours d'exécution sera également Interrompre immédiatement. En même temps, la méthode retournera immédiatement. Cette méthode a une valeur de retour, qui est la liste des tâches abandonnées dans la file d'attente des tâches actuelle. Le code source de la méthode
shutdownNow() est le suivant.
public List<Runnable> shutdownNow() { List<Runnable> tasks; final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { //检查是否有关闭权限 checkShutdownAccess(); //设置线程池的状态为STOP advanceRunState(STOP); //中断所有的Worker线程 interruptWorkers(); //将任务队列中的任务移动到tasks集合中 tasks = drainQueue(); } finally { mainLock.unlock(); } /尝试将状态变为TERMINATED tryTerminate(); //返回tasks集合 return tasks; }
La logique globale du code source de la méthode shutdownNow() est fondamentalement la même que la méthode shutdown(), sauf que la méthode shutdownNow() définit l'état du pool de threads sur STOP, interrompt tous les threads de travail et déplace toutes les tâches de la file d'attente des tâches vers la collection et le retour des tâches.
Vous pouvez voir que lorsque la méthode shutdownNow() interrompt tous les threads, la méthode interrompuWorkers() est appelée. Ensuite, nous examinerons le code source de la méthode interrompuWorkers(), comme indiqué ci-dessous.
private void interruptWorkers() { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { for (Worker w : workers) w.interruptIfStarted(); } finally { mainLock.unlock(); } }
La logique de la méthode interrompuWorkers() est relativement simple, qui consiste à obtenir le verrou global du pool de threads, à parcourir tous les threads de travail, à interrompre les threads dans l'ordre et enfin à libérer le verrou global du pool de threads.
À l'intérieur de la méthode interrompuWorkers(), la méthode interrompuIfStarted() de la classe Worker est en fait appelée pour interrompre le thread. Jetons un coup d'œil au code source de la méthode interrompuIfStarted() de la classe Worker, comme indiqué ci-dessous.
void interruptIfStarted() { Thread t; if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) { try { t.interrupt(); } catch (SecurityException ignore) { } } }
a constaté qu'il appelle essentiellement la méthode interruption() de la classe Thread pour interrompre le thread.
Lorsque le pool de threads appelle la méthode waitTermination(long, TimeUnit), elle bloquera le thread de l'appelant et ne reviendra pas tant que l'état du pool de threads n'est pas changé en TERMINATED ou que le délai d'attente est écoulé. la période est atteinte. Examinons ensuite le code source de la méthode waitTermination(long, TimeUnit), comme indiqué ci-dessous.
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { //获取距离超时时间剩余的时长 long nanos = unit.toNanos(timeout); //获取Worker线程的的全局锁 final ReentrantLock mainLock = this.mainLock; //加锁 mainLock.lock(); try { for (;;) { //当前线程池状态为TERMINATED状态,会返回true if (runStateAtLeast(ctl.get(), TERMINATED)) return true; //达到超时时间,已超时,则返回false if (nanos <= 0) return false; //重置距离超时时间的剩余时长 nanos = termination.awaitNanos(nanos); } } finally { //释放锁 mainLock.unlock(); } }
La logique globale du code ci-dessus est la suivante : obtenez d'abord le verrou exclusif du thread de travail, puis effectuez une boucle pour déterminer si le pool de threads actuel est déjà dans l'état TERMINATED. Si c'est le cas, renvoyez true directement, sinon vérifiez s'il est. a expiré. S'il a expiré, retournez false. S'il n'expire pas, réinitialisez le temps restant avant l'expiration du délai. Ensuite, entrez dans le cycle suivant et vérifiez à nouveau si le pool de threads actuel est dans l'état TERMINATED. Si tel est le cas, renvoyez directement true. Sinon, vérifiez s'il a expiré. S'il a expiré, renvoyez false. S'il n'expire pas, réinitialisez le temps restant avant l'expiration du délai. Cette boucle continue jusqu'à ce que l'état du pool de threads devienne TERMINATED ou expire.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!