我有一个带有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框架创建执行程序,然后将它们注入您的代码即可。或者,如果这是一个小项目,请将其放在静态字段中。