线程池拒绝策略:优雅处理过载请求

当线程池达到最大容量时,会出现任务无法提交的情况,这时需要处理这种情况的机制称为“拒绝策略”(Rejection Policy)。本文将详细讲述 Java 中的线程池拒绝策略,帮助读者理解其原理和应用场景。
首页 新闻资讯 行业资讯 线程池拒绝策略:优雅处理过载请求

什么是线程池拒绝策略?

线程池拒绝策略是指当线程池中的任务数量达到上限时,新提交的任务如何处理的一种策略。Java 提供了几种内置的拒绝策略,开发者也可以自定义策略。

b5da99d2212692e389a012224e9ba6ff498e9f.jpg

内置的拒绝策略

Java 提供了以下几种内置的拒绝策略:

  • AbortPolicy:默认策略,直接抛出 RejectedExecutionException 异常,阻止系统正常运行。

  • CallerRunsPolicy:由调用线程处理该任务,既不抛弃任务,也不抛出异常。

  • DiscardPolicy:直接丢弃任务,不予处理。

  • DiscardOldestPolicy:丢弃最旧的任务,然后尝试重新提交被拒绝的任务。

下面,我们通过代码示例来详细讲述这些策略的实现和应用。

代码示例

创建一个简单的线程池:

importjava.util.concurrent.*;publicclassThreadPoolExample{privatestaticfinal intCORE_POOL_SIZE=2;privatestaticfinal intMAX_POOL_SIZE=4;privatestaticfinal longKEEP_ALIVE_TIME=10L;publicstaticvoidmain(String[]args){// 使用 ArrayBlockingQueue 作为任务队列,容量为 2BlockingQueue<Runnable>queue=newArrayBlockingQueue<>(2);// 创建线程池ThreadPoolExecutor executor=newThreadPoolExecutor(CORE_POOL_SIZE,MAX_POOL_SIZE,KEEP_ALIVE_TIME,TimeUnit.SECONDS,queue);// 提交任务for(int i=0;i<10;i++){final int taskNumber=i+1;executor.submit(()->{try{System.out.println("Executing task "+taskNumber);Thread.sleep(2000);}catch(InterruptedException e){Thread.currentThread().interrupt();}});}// 关闭线程池executor.shutdown();}}

使用 AbortPolicy:

importjava.util.concurrent.*;publicclassAbortPolicyExample{publicstaticvoidmain(String[]args){BlockingQueue<Runnable>queue=newArrayBlockingQueue<>(2);ThreadPoolExecutor executor=newThreadPoolExecutor(2,4,10L,TimeUnit.SECONDS,queue,newThreadPoolExecutor.AbortPolicy()// 使用 AbortPolicy);for(int i=0;i<10;i++){final int taskNumber=i+1;try{executor.submit(()->{try{System.out.println("Executing task "+taskNumber);Thread.sleep(2000);}catch(InterruptedException e){Thread.currentThread().interrupt();}});}catch(RejectedExecutionException e){System.err.println("Task "+taskNumber+" was rejected");}}executor.shutdown();}}

使用 CallerRunsPolicy:

importjava.util.concurrent.*;publicclassCallerRunsPolicyExample{publicstaticvoidmain(String[]args){BlockingQueue<Runnable>queue=newArrayBlockingQueue<>(2);ThreadPoolExecutor executor=newThreadPoolExecutor(2,4,10L,TimeUnit.SECONDS,queue,newThreadPoolExecutor.CallerRunsPolicy()// 使用 CallerRunsPolicy);for(int i=0;i<10;i++){final int taskNumber=i+1;executor.submit(()->{System.out.println("Executing task "+taskNumber);try{Thread.sleep(2000);}catch(InterruptedException e){Thread.currentThread().interrupt();}});}executor.shutdown();}}

使用 DiscardPolicy:

importjava.util.concurrent.*;publicclassDiscardPolicyExample{publicstaticvoidmain(String[]args){BlockingQueue<Runnable>queue=newArrayBlockingQueue<>(2);ThreadPoolExecutor executor=newThreadPoolExecutor(2,4,10L,TimeUnit.SECONDS,queue,newThreadPoolExecutor.DiscardPolicy()// 使用 DiscardPolicy);for(int i=0;i<10;i++){final int taskNumber=i+1;executor.submit(()->{System.out.println("Executing task "+taskNumber);try{Thread.sleep(2000);}catch(InterruptedException e){Thread.currentThread().interrupt();}});}executor.shutdown();}}

使用 DiscardOldestPolicy:

importjava.util.concurrent.*;publicclassDiscardOldestPolicyExample{publicstaticvoidmain(String[]args){BlockingQueue<Runnable>queue=newArrayBlockingQueue<>(2);ThreadPoolExecutor executor=newThreadPoolExecutor(2,4,10L,TimeUnit.SECONDS,queue,newThreadPoolExecutor.DiscardOldestPolicy()// 使用 DiscardOldestPolicy);for(int i=0;i<10;i++){final int taskNumber=i+1;executor.submit(()->{System.out.println("Executing task "+taskNumber);try{Thread.sleep(2000);}catch(InterruptedException e){Thread.currentThread().interrupt();}});}executor.shutdown();}}

来点通俗易懂的

为了更好地理解这些拒绝策略,我们可以将其类比于生活中的场景:

  • AbortPolicy:就像餐厅已满员,不再接待新客人,并告知客人“已经客满,请去别处”。

  • CallerRunsPolicy:就像餐厅忙不过来时,老板自己上阵服务客人,保证所有客人都能被服务到。

  • DiscardPolicy:就像餐厅已满员,直接不理会新来的客人,不告知任何信息。

  • DiscardOldestPolicy:就像餐厅已满员,把最早来但还没点菜的客人请走,以便接待新来的客人。

自定义拒绝策略

除了内置的拒绝策略,开发者还可以根据实际需求自定义拒绝策略。例如,记录日志、发送通知等。

importjava.util.concurrent.*;publicclassCustomRejectionPolicyExample{publicstaticvoidmain(String[]args){BlockingQueue<Runnable>queue=newArrayBlockingQueue<>(2);ThreadPoolExecutor executor=newThreadPoolExecutor(2,4,10L,TimeUnit.SECONDS,queue,newRejectedExecutionHandler(){@OverridepublicvoidrejectedExecution(Runnable r,ThreadPoolExecutor executor){System.err.println("Task "+r.toString()+" was rejected");// 这里可以添加更多处理逻辑,比如记录日志、发送通知等}});for(int i=0;i<10;i++){final int taskNumber=i+1;executor.submit(()->{System.out.println("Executing task "+taskNumber);try{Thread.sleep(2000);}catch(InterruptedException e){Thread.currentThread().interrupt();}});}executor.shutdown();}}

结语

通过本文的介绍和代码示例,相信大家对 Java 线程池的拒绝策略有了更深入的理解。在实际开发中,选择合适的拒绝策略能有效提升系统的稳定性和用户体验。

18    2024-10-09 15:58:02    线程池 开发