Rumah  >  Artikel  >  Java  >  Apakah dasar penolakan kumpulan benang Java

Apakah dasar penolakan kumpulan benang Java

WBOY
WBOYke hadapan
2023-05-14 08:13:05805semak imbas

Pemikiran Reka Bentuk Kolam

Reka bentuk kolam seharusnya bukan istilah baharu. Yang biasa kami seperti kolam benang java, kolam sambungan jdbc, kolam sambungan redis, dsb. adalah pelaksanaan yang mewakili jenis reka bentuk ini.

Reka bentuk ini pada mulanya akan menetapkan sumber, dan masalah yang diselesaikan adalah untuk mengimbangi penggunaan setiap pemerolehan sumber, seperti kos mencipta benang, kos mendapatkan sambungan jauh, dsb. Sama seperti ketika anda pergi ke kantin untuk mendapatkan makanan, makcik yang menyediakan makanan akan terlebih dahulu meletakkan beberapa bahagian nasi di situ nasi dan menyediakan sayur-sayuran pada masa yang sama, yang lebih cekap.

Selain memulakan sumber, reka bentuk pengumpulan juga termasuk ciri berikut: nilai awal kumpulan, nilai aktif kumpulan, nilai maksimum kumpulan, dll. Ciri ini boleh dipetakan terus kepada ahli kumpulan Kolam benang Java dan kolam sambungan pangkalan data dalam sifat.

Masa apabila kumpulan benang mencetuskan dasar penolakan

Berbeza daripada kumpulan sambungan sumber data, sebagai tambahan kepada saiz awal dan nilai kumpulan maksimum, urutan pool juga mempunyai barisan menyekat tambahan.

Kolam sambungan sumber data secara amnya mencetuskan dasar penolakan apabila bilangan sambungan yang diminta melebihi nilai maksimum kumpulan sambungan Dasar ini biasanya untuk menyekat dan menunggu masa yang ditetapkan atau secara langsung mengeluarkan pengecualian.

Apakah dasar penolakan kumpulan benang Java

Seperti yang ditunjukkan dalam rajah, jika anda ingin tahu bila kumpulan benang mencetuskan penolakan, anda perlu menjelaskan maksud khusus bagi tiga parameter di atas, iaitu hasil daripada penyelarasan keseluruhan ketiga-tiga parameter ini, dan Ia bukan semata-mata bahawa melebihi bilangan maksimum benang akan mencetuskan penolakan utas Apabila bilangan tugasan yang diserahkan lebih besar daripada corePoolSize, ia akan diletakkan dalam penampan baris gilir sahaja penimbal telah diisi, ia akan dinilai sama ada tugas yang sedang dijalankan adalah lebih besar daripada maxPoolSize Jika kurang daripada nilai, urutan baharu akan dibuat untuk diproses. Apabila ia lebih besar daripada nilai, dasar penolakan dicetuskan.

Ringkasannya ialah: apabila bilangan tugasan semasa yang diserahkan lebih besar daripada (maxPoolSize + queueCapacity), dasar penolakan kumpulan urutan akan dicetuskan.

JDK mempunyai 4 strategi penolakan kolam benang terbina dalam

Takrifan antara muka strategi penolakan

Dalam menganalisis kumpulan benang yang disertakan dengan JDK Sebelum menolak dasar, mula-mula lihat antara muka dasar penolakan yang ditakrifkan oleh JDK, seperti berikut:

public interface RejectedExecutionHandler {      void rejectedExecution(Runnable r, ThreadPoolExecutor executor);  }

Antara muka ditakrifkan dengan sangat jelas Apabila dasar penolakan dicetuskan, kumpulan benang akan hubungi dasar khusus yang anda tetapkan untuk memindahkan tugasan yang diserahkan pada masa ini Dan contoh kumpulan benang itu sendiri diserahkan kepada anda untuk diproses.

CallerRunsPolicy (dasar pemanggil menjalankan)

public static class CallerRunsPolicy implements RejectedExecutionHandler {          public CallerRunsPolicy() { }          public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {              if (!e.isShutdown()) {                  r.run();              }          }      }

Fungsi: Apabila dasar penolakan dicetuskan, selagi kumpulan benang tidak ditutup, ia akan diproses oleh urutan semasa yang menyerahkan tugasan.

Senario penggunaan: biasanya digunakan dalam senario di mana kegagalan tidak dibenarkan, keperluan prestasi tidak tinggi dan keselarasan adalah kecil, kerana kumpulan benang tidak akan ditutup dalam keadaan biasa, yang ialah, penyerahan Tugas pasti akan dijalankan, tetapi oleh kerana ia dilaksanakan oleh utas pemanggil itu sendiri, apabila tugasan itu diserahkan beberapa kali, ia akan menyekat pelaksanaan tugas berikutnya, dan prestasi serta kecekapan secara semula jadi akan menjadi perlahan.

AbortPolicy (abort policy)

public static class AbortPolicy implements RejectedExecutionHandler {          public AbortPolicy() { }          public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {              throw new RejectedExecutionException("Task " + r.toString() +                                                   " rejected from " +                                                   e.toString());          }      }

Fungsi: Apabila dasar penolakan dicetuskan, pengecualian yang enggan melaksanakan akan dilemparkan secara langsung, yang bermaksud untuk membatalkan dasar Iaitu untuk mengganggu proses pelaksanaan semasa

Senario penggunaan: Tiada senario khas untuk ini, tetapi satu perkara ialah pengecualian yang dilemparkan mesti dikendalikan dengan betul.

Dasar lalai dalam ThreadPoolExecutor ialah AbortPolicy Siri ThreadPoolExecutors antara muka ExecutorService tidak mempunyai dasar penolakan yang jelas, jadi dasar lalai adalah ini.

Tetapi sila ambil perhatian bahawa baris gilir contoh kumpulan benang dalam ExecutorService tidak terhad, yang bermaksud bahawa dasar penolakan tidak akan dicetuskan walaupun memori telah habis. Apabila anda menyesuaikan contoh kumpulan benang, anda mesti mengendalikan pengecualian yang dilemparkan apabila strategi dicetuskan apabila menggunakan strategi ini, kerana ia akan mengganggu proses pelaksanaan semasa.

DiscardPolicy (dasar buang)

public static class DiscardPolicy implements RejectedExecutionHandler {          public DiscardPolicy() { }          public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {          }      }

Fungsi: Buang tugas ini secara senyap-senyap tanpa mencetuskan sebarang tindakan

Penggunaan senario: Anda boleh menggunakannya jika tugasan yang anda serahkan tidak penting. Kerana ia adalah pelaksanaan kosong dan akan menelan tugas anda secara senyap. Jadi strategi ini pada asasnya tidak lagi diperlukan

BuangPolisi Lama (buang polisi lama)

public static class DiscardOldestPolicy implements RejectedExecutionHandler {          public DiscardOldestPolicy() { }          public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {              if (!e.isShutdown()) {                  e.getQueue().poll();                  e.execute(r);              }          }      }

Fungsi: Jika kumpulan benang tidak ditutup, pop naikkan elemen kepala baris gilir di dalam, dan kemudian cuba laksanakan

Senario penggunaan: Strategi ini masih akan membuang tugas, dan ia akan senyap apabila membuang, tetapi cirinya ialah ia membuang tugas lama yang tidak dilaksanakan, dan Ia adalah tugas dengan keutamaan yang lebih tinggi untuk dilaksanakan.

Berdasarkan ciri ini, senario yang saya boleh fikirkan adalah untuk menerbitkan mesej dan mengubah suai mesej Selepas mesej diterbitkan, ia belum dilaksanakan pada masa ini kali ini, mesej yang tidak dilaksanakan Jika versi lebih rendah daripada versi mesej yang dihantar pada masa ini, ia boleh dibuang. Kerana mungkin terdapat mesej dengan versi mesej yang lebih rendah dalam baris gilir yang akan dibariskan untuk pelaksanaan, anda mesti membandingkan versi mesej apabila benar-benar memproses mesej.

Strategi penolakan yang dilaksanakan oleh pihak ketiga

dubbo中的线程拒绝策略

public class AbortPolicyWithReport extends ThreadPoolExecutor.AbortPolicy {      protected static final Logger logger = LoggerFactory.getLogger(AbortPolicyWithReport.class);      private final String threadName;      private final URL url;      private static volatile long lastPrintTime = 0;      private static Semaphore guard = new Semaphore(1);      public AbortPolicyWithReport(String threadName, URL url) {          this.threadName = threadName;          this.url = url;      }      @Override      public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {          String msg = String.format("Thread pool is EXHAUSTED!" +                          " Thread Name: %s, Pool Size: %d (active: %d, core: %d, max: %d, largest: %d), Task: %d (completed: %d)," +                          " Executor status:(isShutdown:%s, isTerminated:%s, isTerminating:%s), in %s://%s:%d!",                  threadName, e.getPoolSize(), e.getActiveCount(), e.getCorePoolSize(), e.getMaximumPoolSize(), e.getLargestPoolSize(),                  e.getTaskCount(), e.getCompletedTaskCount(), e.isShutdown(), e.isTerminated(), e.isTerminating(),                  url.getProtocol(), url.getIp(), url.getPort());          logger.warn(msg);          dumpJStack();          throw new RejectedExecutionException(msg);      }      private void dumpJStack() {         //省略实现      }  }

可以看到,当dubbo的工作线程触发了线程拒绝后,主要做了三个事情,原则就是尽量让使用者清楚触发线程拒绝策略的真实原因。

1)输出了一条警告级别的日志,日志内容为线程池的详细设置参数,以及线程池当前的状态,还有当前拒绝任务的一些详细信息。可以说,这条日志,使用dubbo的有过生产运维经验的或多或少是见过的,这个日志简直就是日志打印的典范,其他的日志打印的典范还有spring。得益于这么详细的日志,可以很容易定位到问题所在

2)输出当前线程堆栈详情,这个太有用了,当你通过上面的日志信息还不能定位问题时,案发现场的dump线程上下文信息就是你发现问题的救命稻草。

3)继续抛出拒绝执行异常,使本次任务失败,这个继承了JDK默认拒绝策略的特性

Netty中的线程池拒绝策略

private static final class NewThreadRunsPolicy implements RejectedExecutionHandler {          NewThreadRunsPolicy() {              super();          }          public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {              try {                  final Thread t = new Thread(r, "Temporary task executor");                  t.start();              } catch (Throwable e) {                  throw new RejectedExecutionException(                          "Failed to start a new thread", e);              }          }      }

Netty中的实现很像JDK中的CallerRunsPolicy,舍不得丢弃任务。不同的是,CallerRunsPolicy是直接在调用者线程执行的任务。而 Netty是新建了一个线程来处理的。

所以,Netty的实现相较于调用者执行策略的使用面就可以扩展到支持高效率高性能的场景了。但是也要注意一点,Netty的实现里,在创建线程时未做任何的判断约束,也就是说只要系统还有资源就会创建新的线程来处理,直到new不出新的线程了,才会抛创建线程失败的异常。

activeMq中的线程池拒绝策略

new RejectedExecutionHandler() {                  @Override                  public void rejectedExecution(final Runnable r, final ThreadPoolExecutor executor) {                      try {                          executor.getQueue().offer(r, 60, TimeUnit.SECONDS);                      } catch (InterruptedException e) {                          throw new RejectedExecutionException("Interrupted waiting for BrokerService.worker");                      }                      throw new RejectedExecutionException("Timed Out while attempting to enqueue Task.");                  }              });

activeMq中的策略属于最大努力执行任务型,当触发拒绝策略时,在尝试一分钟的时间重新将任务塞进任务队列,当一分钟超时还没成功时,就抛出异常

pinpoint中的线程池拒绝策略

public class RejectedExecutionHandlerChain implements RejectedExecutionHandler {      private final RejectedExecutionHandler[] handlerChain;      public static RejectedExecutionHandler build(List<rejectedexecutionhandler> chain) {          Objects.requireNonNull(chain, "handlerChain must not be null");          RejectedExecutionHandler[] handlerChain = chain.toArray(new RejectedExecutionHandler[0]);          return new RejectedExecutionHandlerChain(handlerChain);      }      private RejectedExecutionHandlerChain(RejectedExecutionHandler[] handlerChain) {          this.handlerChain = Objects.requireNonNull(handlerChain, "handlerChain must not be null");      }      @Override      public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {          for (RejectedExecutionHandler rejectedExecutionHandler : handlerChain) {              rejectedExecutionHandler.rejectedExecution(r, executor);          }      }  }</rejectedexecutionhandler>

pinpoint的拒绝策略实现很有特点,和其他的实现都不同。他定义了一个拒绝策略链,包装了一个拒绝策略列表,当触发拒绝策略时,会将策略链中的rejectedExecution依次执行一遍。

Atas ialah kandungan terperinci Apakah dasar penolakan kumpulan benang Java. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:yisu.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam