WHCSRL 技术网

用静态常量实现一个单例模式的线程池

1.使用场景

在做项目的时候,遇到以下场景:有求解器,进行多并发求解,但又不想用redis,因此写了一个单例模型的线程池对结果进行接收,然后慢慢一个一个写入数据库中。需要注意的是,方法被调用后会立即返执行成功给主线程。这种方式属于饿汉式,可能会造成内存浪费问题。

import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPool {

    //创建具体的单例变量,这里你想要什么就创建什么,这里我需要线程池就创建线程池
    private static final ExecutorService EXECUTOR_SERVICE= Executors.newFixedThreadPool(2);

    // 将构造器私有化,这样从外部就没办法创建了
    private ThreadPool(){}

    //提供一个返回实例对象的公共方法,这样保证每次用的都是同一个线程池,这就是为什么他被称为单例的原因
    //每次都用的都是这个
    public static ExecutorService getInsatance(){
        return EXECUTOR_SERVICE;
    }

    public static void main(String[] args) {
        //测试线程效果以及查看到底是不是每次都用的是同一个线程池
        for (int i = 0; i < 10; i++) {
            int finalI = i;
            Runnable runnable=new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println("这是第"+ finalI +"个线程,线程池的内存地址为,"+ThreadPool.getInsatance().hashCode()+" 时间是:"+new Date());
                        Thread.sleep(3000);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            };
            ThreadPool.getInsatance().submit(runnable);
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

2.结果

当线程数为2

这是第1个线程,线程池的内存地址为,1712400905 时间是:Sun Oct 31 23:53:24 CST 2021
这是第0个线程,线程池的内存地址为,1712400905 时间是:Sun Oct 31 23:53:24 CST 2021
这是第2个线程,线程池的内存地址为,1712400905 时间是:Sun Oct 31 23:53:27 CST 2021
这是第3个线程,线程池的内存地址为,1712400905 时间是:Sun Oct 31 23:53:27 CST 2021
这是第4个线程,线程池的内存地址为,1712400905 时间是:Sun Oct 31 23:53:30 CST 2021
这是第5个线程,线程池的内存地址为,1712400905 时间是:Sun Oct 31 23:53:30 CST 2021
这是第7个线程,线程池的内存地址为,1712400905 时间是:Sun Oct 31 23:53:33 CST 2021
这是第6个线程,线程池的内存地址为,1712400905 时间是:Sun Oct 31 23:53:33 CST 2021
这是第8个线程,线程池的内存地址为,1712400905 时间是:Sun Oct 31 23:53:36 CST 2021
这是第9个线程,线程池的内存地址为,1712400905 时间是:Sun Oct 31 23:53:36 CST 2021
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

当线程数为1

这是第0个线程,线程池的内存地址为,1648378190 时间是:Sun Oct 31 23:57:31 CST 2021
这是第1个线程,线程池的内存地址为,1648378190 时间是:Sun Oct 31 23:57:34 CST 2021
这是第2个线程,线程池的内存地址为,1648378190 时间是:Sun Oct 31 23:57:37 CST 2021
这是第3个线程,线程池的内存地址为,1648378190 时间是:Sun Oct 31 23:57:40 CST 2021
这是第4个线程,线程池的内存地址为,1648378190 时间是:Sun Oct 31 23:57:43 CST 2021
这是第5个线程,线程池的内存地址为,1648378190 时间是:Sun Oct 31 23:57:46 CST 2021
这是第6个线程,线程池的内存地址为,1648378190 时间是:Sun Oct 31 23:57:49 CST 2021
这是第7个线程,线程池的内存地址为,1648378190 时间是:Sun Oct 31 23:57:52 CST 2021
这是第8个线程,线程池的内存地址为,1648378190 时间是:Sun Oct 31 23:57:55 CST 2021
这是第9个线程,线程池的内存地址为,1648378190 时间是:Sun Oct 31 23:57:58 CST 2021
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

3.程序执行完后主程序不会结束?idea显示在运行?

虽然我们从肉眼上看到的是程序打印完了字符,但是单例线程池没有销毁,所以是因为线程池一直在等待的原因。如果需要在线程执行完任务后,结束整个程序,使用ThreadPool.getInstance().shutdown()即可(在本例中,shutdown在for循环使用)。

推荐阅读