线程池的创建方法推荐
使用Executors创建线程池的四种方法:
Executors类,提供了一系列工厂方法用于创建线程池,返回的线程池都实现了ExecutorService接口。
1.public static ExecutorService newFixedThreadPool(int nThreads)
创建固定数目线程的线程池。
2.public static ExecutorService newCachedThreadPool()
创建一个可缓存的线程池,调用execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。
3.public static ExecutorService newSingleThreadExecutor()
创建一个单线程化的Executor。
4.public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类。
ExecutoreService提供了submit()方法,传递一个Callable,或Runnable,返回Future。如果Executor后台线程池还没有完成Callable的计算,这调用返回Future对象的get()方法,会阻塞直到计算完成。
以上四种创建线程池实则并不推荐,并避免使用。
推荐:使用ThreadPoolExecutor的方式创建线程池
线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
说明:Executors返回的线程池对象的弊端如下:
1)FixedThreadPool和SingleThreadPool:
允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM。
2)CachedThreadPool:
允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM。
Positive example 1:
//org.apache.commons.lang3.concurrent.BasicThreadFactory ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1, new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d").daemon(true).build());
Positive example 2:
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder() .setNameFormat("demo-pool-%d").build(); //Common Thread Pool ExecutorService pool = new ThreadPoolExecutor(5, 200,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy()); pool.execute(()-> System.out.println(Thread.currentThread().getName())); pool.shutdown();//gracefully shutdown
Positive example 3:
<bean id="userThreadPool" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"> <property name="corePoolSize" value="10" /> <property name="maxPoolSize" value="100" /> <property name="queueCapacity" value="2000" /> <property name="threadFactory" value= threadFactory /> <property name="rejectedExecutionHandler"> <ref local="rejectedExecutionHandler" /> </property> </bean> //in code userThreadPool.execute(thread);
以上为阿里巴巴推荐的方式。
结合阿里巴巴代码规范的推荐方式,以下为我公司现使用的方式:
// 成员变量 private volatile ExecutorService executor; //单例模式创建 private ExecutorService getExecutorService(){ if(executor == null){ synchronized (this){ if(executor == null){ int availableProcessors = Runtime.getRuntime().availableProcessors(); int maximumPoolSize = availableProcessors * 4; int queueCapacity = availableProcessors * 100; long keepAliveTime = 60L; BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(queueCapacity); executor = new ThreadPoolExecutor( availableProcessors, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, workQueue, new ThreadPoolExecutor.DiscardPolicy()); // 关闭客户端(关闭后台线程) Runtime.getRuntime().addShutdownHook(new Thread(() -> { if(Objects.nonNull(executor)){ executor.shutdown(); } })); } } } return executor; }