线程池的代码使用

今天主要是看下别人代码的使用,看到了别人这么一段代码

LinkedBlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<>();
            ExecutorService executorService = new ThreadPoolExecutor(MAX_THREAD_NUM, MAX_THREAD_NUM,
                    0, TimeUnit.SECONDS, taskQueue);

            for (ItoUserDto userDto : userDtoList) {
               ...
                executorService.submit(emailTread);
        
            }
        }

这个代码我主要考虑的是,线程池在方法中使用,合不合适。

线程池的使用

线程的参数的使用,这个日常用的话,各个参数,大家八股文背的也比较多了,基本使用也懂的。我们日常使用的话,基本使用都是spring声明一个

线程池使用或者弄个类,声明一个静态属性。

这里我比较奇怪的是线程池的使用,在方法中使用,这样有没有问题。

我当时考虑的是,这个线程池没关闭操作,这个又是一个方法,那会不会出现,你线程池比如说声明8个,然后提交了1000个任务,然后这个8个核心线程还在执行,然后你方法给我关了,那gc一次,那任务队列的东西不全丢了。

但是我想想不对啊,应该不会,线程池的线程应该也是一个gcroot,应该不会被gc掉的。那就写个例子看看。

线程池工具类demo_线程池工具类demo

本意是主线程结束了以后,线程池声明的线程应该也不会结束,结果确实是这样。会等待都执行完的。

那基本就是因为新声明的线程,执行完以后才会销毁,然后才会被gc回收掉这个对象。

那我们看看线程

线程池工具类demo_线程池_02

emm,不对啊,该道理,没关闭,应该不会被销毁的啊。

哦,原来是懒加载申请的,忘记了。

那么在看看。

线程池工具类demo_线程池_03

可以看出,一旦使用,如果你没shutdown,线程没有被回收的。

那么我们基本可以看出在接口方法里使用线程池中的问题了。

如果忘记使用shutdown,那么任务执行完的话,线程不会被回收,导致多来几次,基本爆炸。

如果使用了shutdown就对吗?也不对,你接口如果并发比较高,比如一秒并发来个1000,那每个方法不是一下子申请了1000*核心线程数的线程了。

如果这个任务执行的方法时间比较长的话,那是不是一下子回收不掉,直接也爆炸。

那么基本在接口方法里声明一个线程池是比较不靠谱的方法了。

那在容器或者类的静态属性里声明一个线程池是否可靠。

我们可以理解的是,在容器或者类的静态属性里声明一个线程池,不会被gc掉的。

那么基本有两种使用,一种是一个容器里用一个线程池,大家都用这个线程池。要么是一个业务用一个线程池。

这两个方法的区别。

1.一个容器用一个线程池,那么所有业务都用这个线程池,主要问题是如果有一批长时间的任务,那么基本在这后面的任务,都得乖乖在任务队列里等。

那如果这个任务很长,后面的任务是比较短的时间。那么就会有种很奇怪的现象。为什么我这么一个短时间的异步任务。会耗费这么长的时间。

2,那一个业务一个线程池,线程池业务隔离,那么基本不会出现上面的一个短时间的异步任务,耗费太长时间的问题。因为大家用的池子是不同的。

但是这个问题是,因为线程池不会被回收,业务多的话,是不是声明了很多的线程池,线程也会比较多的。虽然不太可能有太多,估计也就是几十个池子而已。

其实我推荐的是一个项目用两个池子,一个是长时间的任务池,一个是短时间的池子,这样短时间的任务就用短时间的池子,长时间的任务就用长时间的池子。

这个思路其实和数据库的连接池一样道理,短查询用短查询的连接池,长查询用长查询的池子。