乱人伦 国语对白海角社区,五月激情丁香婷婷综合中文字幕,欧美伊人婷婷久久五月综合,亚洲精品无amm毛片,亚洲男人第一无码AV网站,国产日韩欧美丝袜一区二区,亚洲一区精品在线观看

如何优雅的关闭 Java线程池-世界排名买球平台

如何优雅的关闭 Java线程池

2026-01-17 02:48:10投稿人:足球外圍app下載(湘潭)有限公司圍觀228663 評(píng)論

如何優(yōu)雅的關(guān)閉 Java線程池

簡(jiǎn)介 在開發(fā)中使用線程池去執(zhí)行異步任務(wù)是比較普遍的操作 ,然而雖然有些異步操作我們并不十分要求可靠性和實(shí)時(shí)性 ,但總歸業(yè)務(wù)還是需要的。如果在每次的服務(wù)發(fā)版過(guò)程中 ,我們不去介入線程池的停機(jī)邏輯 ,那么很有可能就會(huì)造成線程池中隊(duì)列的任務(wù)還未執(zhí)行完成,自然就會(huì)造成數(shù)據(jù)的丟失 。

探究

注意 ,本文所有前提是對(duì)進(jìn)程進(jìn)行下線時(shí)使用的是kill -15

我們知道Spring已經(jīng)實(shí)現(xiàn)了自己的優(yōu)雅停機(jī)方案,詳細(xì)請(qǐng)參考o(jì)rg.springframework.context.support.AbstractApplicationContext#registerShutdownHook ,然后主要看調(diào)用的org.springframework.context.support.AbstractApplicationContext#doClose, 在這個(gè)方法里定義了容器銷毀的執(zhí)行順序

protected void doClose() {   // Check whether an actual close attempt is necessary...  if (this.active.get() && this.closed.compareAndSet(false, true)) {    if (logger.isDebugEnabled()) {     logger.debug("Closing " + this);   }   LiveBeansView.unregisterApplicationContext(this);   try {     // Publish shutdown event.    publishEvent(new ContextClosedEvent(this));   }   catch (Throwable ex) {     logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);   }   // Stop all Lifecycle beans, to avoid delays during inpidual destruction.   if (this.lifecycleProcessor != null) {     try {      this.lifecycleProcessor.onClose();    }    catch (Throwable ex) {      logger.warn("Exception thrown from LifecycleProcessor on context close", ex);    }   }   // Destroy all cached singletons in the context's BeanFactory.   destroyBeans();   // Close the state of this context itself.   closeBeanFactory();   // Let subclasses do some final clean-up if they wish...   onClose();   // Reset local application listeners to pre-refresh state.   if (this.earlyApplicationListeners != null) {     this.applicationListeners.clear();    this.applicationListeners.addAll(this.earlyApplicationListeners);   }   // Switch to inactive.   this.active.set(false);  } }

我們先主要關(guān)注下destroyBeans這個(gè)方法  ,看bean的銷毀邏輯是什么 ,然后看到了下面的一個(gè)bean的銷毀順序邏輯,具體方法在org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#destroySingletons

private final MapdisposableBeans = new LinkedHashMap<>();  public void destroySingletons() {   if (logger.isTraceEnabled()) {    logger.trace("Destroying singletons in " + this);  }  synchronized (this.singletonObjects) {    this.singletonsCurrentlyInDestruction = true;  }  String[] disposableBeanNames;  synchronized (this.disposableBeans) {    disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());  }  for (int i = disposableBeanNames.length - 1; i >= 0; i--) {    destroySingleton(disposableBeanNames[i]);  }  this.containedBeanMap.clear();  this.dependentBeanMap.clear();  this.dependenciesForBeanMap.clear();  clearSingletonCache(); }

可以看到最至關(guān)重要的就是一個(gè)屬性disposableBeans,這個(gè)屬性是一個(gè)LinkedHashMap , 因此屬性是有序的,所以銷毀的時(shí)候也是按照某種規(guī)則保持和放入一樣的順序進(jìn)行銷毀的 ,現(xiàn)在就是要確認(rèn)這個(gè)屬性里到底存的是什么 。

經(jīng)過(guò)調(diào)試發(fā)現(xiàn) ,在創(chuàng)建bean的org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean方法中 ,會(huì)調(diào)用一個(gè)方法org.springframework.beans.factory.support.AbstractBeanFactory#registerDisposableBeanIfNecessary  , 在這個(gè)方法中會(huì)調(diào)用org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#registerDisposableBean然后將當(dāng)前創(chuàng)建的bean放入到屬性disposableBeans中,那么現(xiàn)在來(lái)看一下放入的邏輯什么?

相關(guān)代碼貼一下

protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {   AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);  if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {     if (mbd.isSingleton()) {       // Register a DisposableBean implementation that performs all destruction      // work for the given bean: DestructionAwareBeanPostProcessors,      // DisposableBean interface, custom destroy method.      registerDisposableBean(beanName,                             new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));    }    else {       // A bean with a custom scope...      Scope scope = this.scopes.get(mbd.getScope());      if (scope == null) {         throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");      }      scope.registerDestructionCallback(beanName,                                        new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));    }  }}

org.springframework.beans.factory.support.AbstractBeanFactory#requiresDestruction

protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) {   return (bean != null &&    (DisposableBeanAdapter.hasDestroyMethod(bean, mbd) || (hasDestructionAwareBeanPostProcessors() &&      DisposableBeanAdapter.hasApplicableProcessors(bean, getBeanPostProcessors())))); }

經(jīng)過(guò)兩個(gè)方法可以看到如果一個(gè)bean的scope是singleton并且這個(gè)bean實(shí)現(xiàn)了org.springframework.beans.factory.DisposableBean這個(gè)接口的destroy()方法 ,那么就會(huì)滿足條件 。

現(xiàn)在可以確定一點(diǎn),如果我們將線程池交給Spring管理,并且實(shí)現(xiàn)它的close方法,就可以在應(yīng)用收到下線信號(hào)的時(shí)候執(zhí)行這個(gè)bean的銷毀方法,那么我們就可以在銷毀方法中寫線程池的停機(jī)邏輯