The*_*ist 4 java concurrency java.util.concurrent
你能发现这个bug吗?这将抛出一个java.lang.OutOfMemoryError
.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestTheads {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(1);
while(true) {
executorService.submit(new Runnable() {
public void run() {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
}
});
}
}
}
Run Code Online (Sandbox Code Playgroud)
错误是我调用executorService.submit()
而不是executorService.execute()
,因为submit()
返回一个Future
我忽略的对象.有了execute()
,这个程序实际上将永远运行.
然而,人们并不总是拥有一种execute()
方法,例如使用时ScheduledExecutorService
:
public static void main(String[] args) {
// this will FAIL because I ignore the ScheduledFuture object
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2);
while(true) {
executorService.scheduleWithFixedDelay(new Runnable() {
public void run() {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
}
}, 1, 1, TimeUnit.SECONDS);
}
}
Run Code Online (Sandbox Code Playgroud)
对于不返回任何东西的任务应该做什么,只计算?
任何想法将不胜感激!
编辑:ThreadPoolExecutor
小号purge()
看起来前途无量,但它只能清洗取消的任务.
Future
返回的对象ExecutorService
仅在执行之前被强烈引用.(它实际上是一个FutureTask
委托给你的实例Runnable
.)一旦执行,它将被垃圾收集,因为调用者没有引用它.换句话说,记忆问题与治疗无关Future
.
如果内存不足,那是因为工作队列有数百万个排队的任务.与任何队列一样,除非平均消耗率超过平均生产率,否则队列将填满.队列的内容消耗内存.
使用有界队列,这将有效地限制任务排队,或获得更多内存.
此代码将"永远"运行:
ExecutorService executorService = Executors.newFixedThreadPool(1);
while(true) {
executorService.submit(new Runnable() {
public void run() {
try {
Thread.sleep(10);
} catch (InterruptedException e) { }
}
});
Thread.sleep(12);
}
Run Code Online (Sandbox Code Playgroud)
差异不在于处理结果Future
实例,而是以可以处理它们的速率对任务进行排队.
并不是返回的Futures就是你的问题.问题是,对于您提交的每个Runnable,ExecutorService将存储它们以便以后能够处理.每次使用Runnable(或Future)调用submit方法时,ExecutorService都会将该runnable推送到工作队列.Runnable将坐在那里,直到一个Thread可以从队列中选择Runnable(稍后的时间).如果所有工作线程都忙,则ExecutorService将简单地将runnable放入所述队列.
所以你的问题是你只有一个线程试图拉出另一个线程无限增加的队列.它的添加速度要快得多,然后工作线程可以处理每个Runnable.
编辑:我给出的代码示例实际上抛出了RejectedExecutionException,因此如果您选择,限制机制必须略有不同.
至于一个更好的解决方案,就像我在评论中提到的那样; 如果您希望以工作线程无法跟上队列的方式填充ExecutorService,您可以在请求进入时对其进行序列化和反序列化(构建您自己的ThreadPoolExecutor),但我会确保需要这样的案件是绝对必要的.
完成工作后请记住,Future将被摒弃并收集垃圾.因此,如果您每秒执行一次Future,并且它会在一秒钟内执行,则Future本身将被删除,您将不会遇到内存问题.但是如果你每隔一秒做一个Future,并且线程每隔3秒做一次Future,那将会绘制并发布.
编辑:我描述了您正在运行的程序的堆,问题正是如此.由ExecutorService创建的FutureTask位于工作队列中,直到工作线程将其关闭
Class Name | Shallow Heap | Retained Heap | Percentage
------------------------------------------------------------------------------------------------------------
java.util.concurrent.ThreadPoolExecutor @ 0x78513c5a0 | 104 | 2,051,298,872 | 99.99%
|- java.util.concurrent.LinkedBlockingQueue @ 0x785140598 | 80 | 2,051,298,216 | 99.99%
| |- java.util.concurrent.LinkedBlockingQueue$Node @ 0x785142dd8| 32 | 2,051,297,696 | 99.99%
------------------------------------------------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)
堆分析还有一点,你可以想象有很多LinkedBlockingQueue $ Node
归档时间: |
|
查看次数: |
2261 次 |
最近记录: |