美文网首页
静态内部类方法构建单例模式创建ThreadPoolExecuto

静态内部类方法构建单例模式创建ThreadPoolExecuto

作者: haiyong6 | 来源:发表于2022-01-11 16:15 被阅读0次

之前写过一篇java线程池ThreadPoolExecutor使用无界队列LinkedBlockingQueue实现多线程简单记录了下ThreadPoolExecutor使用无界队列LinkedBlockingQueue实现多线程的用法。但是在实际应用中,有些并发量大的请求场景,直接如此用会被同时创建多个线程池,会有内存不够用的风险,所以可以考虑用单例模式来管理线程池的调用。

最简单的办法可以是把初始化的ThreadPoolExecutor用@Bean直接注入到springboot中,这样是单例的,不过这样就变成了公用线程池,用完不能shutdown(),会一直存在应用中占用一点内存,当然springboot也自带了线程池可以直接调用,但是因为是公用的所以配置不能根据不同业务灵活改变,所以必要时候还是自己写一个比较好。

对单例模式不太熟的话可以看下面两篇博文,讲的很详细了,一般实现方式有饿汉式、懒汉式、双重检测和静态内部类的方法实现单例,综合使用场景,我觉得静态内部类的方法最适合。
单例模式参考博文链接:https://www.cnblogs.com/jingpeipei/p/5771716.html
https://www.cnblogs.com/damsoft/p/6105122.html

下面就用静态内部类的方法创建一个单例来管理ThreadPoolExecutor的创建:

新建ExcutorServiceSingleton类

package com.ly.mp.project.config;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ExcutorServiceSingleton {
    private int corePoolSize = 50;
    private int maximumPoolSize = 500;
    private TimeUnit unit = TimeUnit.MILLISECONDS;
    private int capacity = 2000;
    private ExecutorService executorPool;
    
    public ExcutorServiceSingleton() {
        super();
    }

    private static class SingletonContainer{
        private static ExcutorServiceSingleton instance = new ExcutorServiceSingleton();
    }
    
    public static ExcutorServiceSingleton getInstance() {
        return SingletonContainer.instance;
    }
    
    public ExecutorService getThreadPoolExecutor() {
        if(null == executorPool || executorPool.isShutdown()) {
            executorPool = new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
                    0L, unit,
                    new LinkedBlockingQueue<Runnable>(capacity));
        }
        return executorPool;
    }
    
}

业务测试方法:

    @SuppressWarnings("rawtypes")
    @Override
    public ResponseVO test(Map<String, Integer> params) {
        Integer size = params.get("size");
        Map<String, Object> resultMap = new HashMap<String, Object>();
        ExecutorService executorPool = ExcutorServiceSingleton.getInstance().getThreadPoolExecutor();
        for(int i = 0; i < size; i++) {
            executorPool = ExcutorServiceSingleton.getInstance().getThreadPoolExecutor();
            @SuppressWarnings("unchecked")
            Future future = executorPool.submit(new Callable(){
                @Override
                public Object call(){
                    try {
                        System.out.println(Thread.currentThread().getId() + " " + Thread.currentThread().getName());
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    return true;
                }
            });
            
            System.out.println(i + "===");
            resultMap.put(i+"", future);
            
        }
        executorPool.shutdown();
      Map<String, Object> responseMap= new HashMap<String, Object>();
        for(String key : resultMap.keySet()){
              try {
                responseMap.put(key, ((Future)resultMap.get(key)).get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
//      System.out.println(JSON.toJSONString(responseMap));
        return new ResponseVO<>();
    }

注意,这种自己创建的线程池用完之后要及时关闭,考虑到并发的情况,当线程池存在且没有被关闭时也可以同时处理其他并发的调用,shutdown之后再调用时会重新生成一个新的线程池继续接收处理请求。这样兼顾了占用内存和性能。测试时第一个请求size赋值1000,同时第二个请求size赋值为1,当size为1的请求处理完毕,线程池被关闭之后,第一个请求还没有处理完,剩余的请求会创建一个新的线程池继续处理剩余的请求,处理完之后会关闭线程池,这样用起来不同业务场景可以新建不同配置,比较灵活,用完即关也比较节省内存。

相关文章

网友评论

      本文标题:静态内部类方法构建单例模式创建ThreadPoolExecuto

      本文链接:https://www.haomeiwen.com/subject/cqibcrtx.html