我有一个具有run方法的类,该类的主方法中的计时器使用以下代码调用这个类:
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个new 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的堆转储。我发现了一亿六千万的char[]。我发现了大约1000到2000的查询字符串。我用StringBuilder构建查询字符串。为什么他们没有得到GCed?
发布于 2012-09-18 08:17:01
执行器应在应用程序启动和重用时声明一次。否则,您还可以根据需要创建单独的线程。如果在应用程序执行期间继续创建新的执行器,则它们的线程将继续运行,因此线程数将不断增加。
因此,只需使用DI框架创建执行器并将它们注入代码中即可。或者,如果这是一个小项目,把他们放在一个静态的领域。
发布于 2012-09-18 08:20:21
在run方法中,我声明一个ThreadExecutorPool
如果您在run方法中声明ThreadExecutorPool,该方法每2秒执行一次,那么在几分钟内就会得到许多线程。
发布于 2012-09-18 08:30:27
问题是,您已经告诉所有的ExecutorService,您创建这些线程是为了创建线程,然后让它们永远存活。这在代码中非常明显:
new ThreadPoolExecutor(
20,
20,
Long.MAX_VALUE,
TimeUnit.DAYS,
new LinkedBlockingQueue<Runnable>(),
new MyThreadFactory("commonThreadPool"));第三个和第四个参数基本上是“让空闲线程(实际上)无限天保持存活”。
你可以用几种方法解决这个问题:
ExecutorService.shutdown。ScheduledExecutorService和更合理的任务分发逻辑来限制线程数量,并通过防止线程上下文切换来提高性能。https://stackoverflow.com/questions/12472857
复制相似问题