线程池拒绝策略是指当线程池中的任务数量达到上限时,新提交的任务如何处理的一种策略。Java 提供了几种内置的拒绝策略,开发者也可以自定义策略。
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 线程池的拒绝策略有了更深入的理解。在实际开发中,选择合适的拒绝策略能有效提升系统的稳定性和用户体验。