化妆品品牌推广方案,南宁网站优化公司电话,湖南营销型网站建设 要上磐石网络,界面十分好看的网站背景
在我们的日常开发中肯定会遇到线程池的使用#xff0c;那么随着jdk8的使用发现#xff0c;future.get#xff08;#xff09;这个API的使用也很普及了#xff0c;当然重点不是这个api而是我们在设置线程池参数的时候如果使用自带的四种拒绝策略#xff0c;那没什么…背景
在我们的日常开发中肯定会遇到线程池的使用那么随着jdk8的使用发现future.get这个API的使用也很普及了当然重点不是这个api而是我们在设置线程池参数的时候如果使用自带的四种拒绝策略那没什么问题因为人家都给你处理好了那如果想自定义拒绝策略呢那么这就是本篇博文说的重点那就是自定义拒绝策略时需要注意那么坑
创建一个线程池
我们来模拟下这个问题首先创建如下的线程池配置核心线程数是1最大线程数也是1阻塞队列的长度也是1那也就是说如果我们有5个任务进来一个任务会立刻处理一个会在队列中等待其他三个会走拒绝策略逻辑
public class ThreadLocalTest {static ThreadPoolExecutor productThreadPoolExecutor new ThreadPoolExecutor(corePoolSize: 1maximumPoolSize: 1keepAliveTime: 1TimeUnit.SECONDSnew LinkedBlockingQueue( capacity: 1)new MyThreadFactory(threadStartName:product)MyRejectedPolicy()
)自定义拒绝策略
这个自定义拒绝策略里面其实就打印个日志没有抛出异常也就是说不管你处理什么逻辑但是如果不抛出异常的话呢那么这个任务其实是没有结束的
public static class MyRejectedPolicy implements RejectedExecutionHanddier{overridepublic void rejectedExecution(Runnable r, ThreadPopolExecutor e)if(e.getThreadFactory() instanceof MyThreadFactory){MyThreadFactory myThreadFactory (MyThreadFactorye.getThreaif(product.equals(myThreadFactory.getThreadFactoryNameSystem.out.println(线程池有任务被拒绝了,请关注);))
) 模拟
我们模拟五个任务然后去触发我们的自定义拒绝策略并且会返回一个结果把这些结果否放在一个list集合里面然后不断去get到结果然后观察下是否会阻塞主线程呢答案其实是回一直阻塞的随着任务量变大会导致00M具体大家可以本地做个模拟
public static void main(String[] args) throws Exception(while (true){TimeUnit.SECONDS.sleep(timeout:1);new Thread(() -{ArrayListFutureInteger futurelist new ArrayLisst()int productNum 5;for(inti0;iproductNum;i){try{int finalIi;FutureInteger future productThreadPoolExecutor.submit(() -{System.out.println(Thread.currentThread().getName() Thred)return final * 10});futureList.add(future)} catch (Exception e){e.printStackTrace();}}
}for (FutureIntegerfuture:futurelist){try{Integer integerfuture get();System.out.println(integer);System.out.println(future.get() integer);} catch (Exception e){e.printStackTrace();}).start();分析原因
其实导致上面的原因其实也不难如果大家看过线程池源码的网友就很好理解了
首先我看下submit方法 我们会把每个task都会包装成一个futureTask任务然后我们会执行execute方法然后返回这个futureTask 那导致OOM原因是因为这个futureTask实例不断飙升没有释放继续
future get()方法内部 这个方法内部有这样一个判断逻辑如果s小于等于这个状态值也就是1的时候会执行awaiDone方法这个方法就是阻塞逻辑 总结 上面两个方法就是核心了也就是说在刚开始把task任务包装成FutureTask任务的时候也就是new FutureTask()初始化的状态值是0所以调用get方法的时候状态值还是0并没有把状态值改变成1所以对于线程池而已这个任务并没有完成就会一直阻塞那如何处理呢有两种方式 1、首先我们可以在自定义拒绝策略里面可以抛出异常因为如果抛出异常了之后会在execute方法里面走到自定义拒绝策略这个方法一个是run方法的入口一个就是拒绝策略的入口然后在业务代码外部有个try。。catch捕获到就不会走到把任务放到集合这行代码 2、还有一种方式就是在get的时候加个超时时间 for (FutureIntegerfuture:futurelist){try{Integer integer future.get(timeout: 10,TimeUnit.SECONDS);System.out.println(integer);System.out.println(future.get() : integer);} catch (Exception e){e.printStackTrace();}
} 3、顺便说一点为什么默认的拒绝策略没有这些问题呢是因为默认的拒绝策略也会抛出异常的人家帮你处理好了所以如果你自定义的话就需要按照这样的逻辑去抛出异常