我有一个带有run方法的类,并且该类的main方法中的计时器使用以下代码调用该类:

Timer timer = new Timer();
timer.scheduleAtFixedRate(new LegacySmsSender(), 0, 2*1000);


在run方法中,我声明一个ThreadExecutorPool:

ThreadPoolExecutor packetProcessorThreadPool =
        new ThreadPoolExecutor(4,
                                4,
                                Long.MAX_VALUE,
                                TimeUnit.DAYS,
                                new LinkedBlockingQueue<Runnable>(),
                                new MyThreadFactory("packetProcessorThreadPool")
                                );


我用new PacketProcessor()创建4个PacketProcessor并执行packetProcessorThreadPool.submit并将它们的Future返回保存在列表中。然后,我等待它们全部循环完成:

for(Future<?> f:packetProcessorList)
{
   System.out.println("before f.get() "+new Date());
   f.get();
}


在这些PacketProcessor类的run方法中,它们声明一个ThreadPoolExecutor并创建并提交数量在1-5000之间的线程(通常创建6-7个线程),而PacketProcessor中的threadPoolExecutor代码如下所示:

ThreadPoolExecutor commonThreadPool =
        new ThreadPoolExecutor(
                        20,
                        20,
                        Long.MAX_VALUE,
                        TimeUnit.DAYS,
                        new LinkedBlockingQueue<Runnable>(),
                        new MyThreadFactory("commonThreadPool"));


最后,我运行了大约20分钟,检查了VisualVM,我的内存使用率和活动线程数一直在增加。问题是什么 ?

注意:请随时询问我更多信息或问题

这是一些信息的屏幕截图:



编辑1:

我花了270 MB的堆转储。我发现了160mb的char []。我发现像1000-2000万查询字符串。我用StringBuilder建立查询字符串。为什么他们不被GC?

最佳答案

执行器应在应用程序启动时声明一次并重新使用。否则,您不妨按需创建单个线程。如果在应用程序执行期间继续创建新的执行程序,则它们的线程将保持运行状态,因此线程数将不断增加。

因此,只需使用DI框架创建执行程序,然后将它们注入您的代码即可。或者,如果这是一个小项目,请将其放在静态字段中。

10-04 12:20