Java多线程:线程池的使用

以下摘自阿里开发手册原话
线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。 说明:Executors各个方法的弊端:
1)newFixedThreadPool和newSingleThreadExecutor:
  主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至OOM。
2)newCachedThreadPool和newScheduledThreadPool:
  主要问题是线程数最大数是Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至OOM。

阿里推荐线程池

  • Positive example 1(commons.lang3):

      //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(guava):

    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(spring异步任务线程池):

    <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="rejectedExecutionHandler">
             <ref local="rejectedExecutionHandler" />
         </property>
     </bean>
    //in code
    userThreadPool.execute(thread);
    

自己开发使用

  • commons.lang3
    package com.staryea.invocate.util;
    
    import com.google.common.util.concurrent.ThreadFactoryBuilder;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.lang3.concurrent.BasicThreadFactory;
    
    
    import java.util.concurrent.*;
    
    
    /**
     * @author: hs
     * @Date: 2019/3/30 15:12
     * @Description:
     */
    @Slf4j
    public class ThreadPoolHelper {
        /**
         * 线程池大小
         */
        private static final int POOL_SIZE = 6;
    
        private static final String THREAD_NAME = "invocation-list-pool-%d";
    
        /**
         * 避免资源浪费的情况,懒加载。
         * private static ExecutorService pool = new ThreadPoolExecutor(5, 200,
         *             0L, TimeUnit.MILLISECONDS,
         *             new LinkedBlockingQueue<Runnable>(1024), threadFactory(),
         *             new ThreadPoolExecutor.AbortPolicy());
         */
        private static class ThreadPool{
            /**
             * lang3线程池配置类,配置线程池
             */
            private static ThreadPoolExecutor comitTaskPool = new ScheduledThreadPoolExecutor(POOL_SIZE,
                    new BasicThreadFactory.Builder().namingPattern(THREAD_NAME).daemon(true).build());
            /**
             * guava线程工厂
             */
            private static ThreadFactory threadFactory = new ThreadFactoryBuilder()
                    .setNameFormat(THREAD_NAME).build();
        }
    
        /**
         *
         * @return
         */
        public static ThreadFactory threadFactory(){
            return ThreadPool.threadFactory;
        }
    
        /**
         *
         * @return
         */
        private static ThreadPoolExecutor threadPool(){
            return ThreadPool.comitTaskPool;
        }
    
        /**
         * 执行任务
         * 默认5个线程池执行任务
         *
         * @param comitTask
         */
        public static void executeTask(Runnable comitTask) {
            threadPool().execute(comitTask);
            log.debug("【线程池任务】线程池中线程数:" + threadPool().getPoolSize());
            log.debug("【线程池任务】队列中等待执行的任务数:" + threadPool().getQueue().size());
            log.debug("【线程池任务】已执行完任务数:" + threadPool().getCompletedTaskCount());
        }
    
        /**
         * 指定线程池长度执行线程
         *
         * @param poolSize
         * @param comitTask
         */
        public static void executeTask(int poolSize, Runnable comitTask) {
            threadPool().setCorePoolSize(poolSize);
            executeTask(comitTask);
            log.debug("【线程池任务】线程池中线程数:" + threadPool().getPoolSize());
            log.debug("【线程池任务】队列中等待执行的任务数:" + threadPool().getQueue().size());
            log.debug("【线程池任务】已执行完任务数:" + threadPool().getCompletedTaskCount());
        }
    
    
        /**
         * 关闭线程池
         */
        public static void shutdown() {
            log.debug("shutdown comitTaskPool...");
            threadPool().shutdown();
            try {
                if (!threadPool().isTerminated()) {
                    log.debug("直接关闭失败[" + threadPool().toString() + "]");
                    threadPool().awaitTermination(3, TimeUnit.SECONDS);
                    if (threadPool().isTerminated()) {
                        log.debug("成功关闭[" + threadPool().toString() + "]");
                    } else {
                        log.debug("[" + threadPool().toString() + "]关闭失败,执行shutdownNow...");
                        if (threadPool().shutdownNow().size() > 0) {
                            log.debug("[" + threadPool().toString() + "]没有关闭成功");
                        } else {
                            log.debug("shutdownNow执行完毕,成功关闭[" + threadPool().toString() + "]");
                        }
                    }
                } else {
                    log.debug("成功关闭[" + threadPool().toString() + "]");
                }
            } catch (InterruptedException e) {
                log.warn("接收到中断请" + threadPool().toString() + "停止操作");
            }
        }
    }
    
  • spring异步任务
  1. 引入依赖开启yml文件自动提示功能

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <!--<optional>true</optional>-->
    </dependency>
    
  2. spring异步任务线程池配置

    import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
    /**
     * @author: hs
     * @Date: 2019/3/18 09:37
     * @Description:
     */
    @Configuration
    @EnableAsync
    @EnableConfigurationProperties(AsyncTaskConfig.AsyncTaskProperties.class)
    public class AsyncTaskConfig {
    
        @Bean
        public AsyncTaskExecutor asyncTaskExecutor(AsyncTaskProperties asyncTaskProperties) {
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            executor.setThreadNamePrefix(defaultIfBlank(asyncTaskProperties.threadNamePrefix,"invocation-list-"));
            executor.setMaxPoolSize(toInt(asyncTaskProperties.getMaxPoolSize(), 10));
            executor.setCorePoolSize(toInt(asyncTaskProperties.getCorePoolSize(), 5));
            executor.setQueueCapacity(toInt(asyncTaskProperties.getQueueCapacity(), 20));
            //若没有空闲的线程,则把任务抛给主线程去执行
            executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
            return executor;
        }
    
        @Data
        @ConfigurationProperties("spring.async")
        public static class AsyncTaskProperties {
            private Integer maxPoolSize;
            private Integer corePoolSize;
            private Integer queueCapacity;
            private String threadNamePrefix;
        }
    
        /**
         * @param num
         * @param defaultNum
         * @return
         */
        private int toInt(Integer num, int defaultNum) {
            return Objects.equal(num, null) ? defaultNum : num;
        }
    }
    
  3. yml文件配置(此配置文件也可以不配置,会自动使用配置类中默认配置)

    spring:
      async:
        core-pool-size: 6
        max-pool-size: 15
        queue-capacity: 50
    
  4. 使用

    @Slf4j
    @Service
    public class ServerCalculateServiceImpl extends JestBaseDao implements ServerCalculateService {
    
        @Async
        @Override
        public void asyncInsertServerCalculates(List<ServerCalculate> list) {
            LocalDate now = LocalDate.now();
            this.batchDocument(list,
                    JestConsts.Index.CALL_LIST.getIndexName().concat(now.toString()),
                    JestConsts.Index.CALL_LIST.getIndexType());
        }
    }
    

    多模块分离情况下,可在启动类上加入如下注解(可以用其他方式,仅供参考):

    /**
     * 异步任务
     * @author hs
     */
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @Import({AsyncTaskConfig.class})
    public @interface EnableAsyncTask {
    
    }
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值