java LinkedBlockingQueue。take似乎一直很忙
我正在尝试在OSGi中实现一个服务,OSGi应该等待来自另一个bundle的传入数据,并在接收数据时处理数据。
我使用的是LinkedBlockingQueue
,因为我不知道将接收多少数据包。
我的代码如下所示:
public class MyClass {
protected static LinkedBlockingQueue<JSONObject> inputQueue = new LinkedBlockingQueue<JSONObject>();
private ExecutorService workerpool = Executors.newFixedThreadPool(4);
public void startMyBundle() {
start();
}
protected void start() {
new Thread(new Runnable() {
public void run() {
while(true){
workerpool.execute(new Runnable() {
public void run() {
try {
process(inputQueue.take());
} catch (InterruptedException e) {
System.out.println("thread was interrupted.");
}
}
});
}
}
}).start();
}
public void transmitIn(JSONObject packet) {
try {
inputQueue.put(packet);
} catch (InterruptedException e) {
}
}
protected void process(JSONObject packet) {
//Some processing
}
当我运行这个程序,并且只向服务发送一个数据包时,数据包首先被处理,但是我的处理器使用了所有的容量,大多数时候我得到一个OutOfMemoryError
如下所示:
java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "[Timer] - Periodical Task (Bundle 46) (Bundle 46)"
这可能是什么原因
# 1 楼答案
由于以下代码行,您将出现内存不足异常:
这将永远旋转创建新的
Runnable
实例,并将它们添加到线程池的任务队列中。它们进入一个无限的队列并迅速填满内存我想你需要一个在
while (true)
循环中调用inputQueue.take()
的4个线程此外,将任务提交到线程池中不需要
Thread
。这是一个非阻塞操作,因此可以由调用方直接完成# 2 楼答案
这段代码就是罪魁祸首:
它所做的是创建一个后台任务,将无限多的
Runnable
添加到ExecutorService
工作队列中。这最终导致了一个OOME我想你想做的是:
例如,在
ExecutorService
上运行4个等待输入的工作进程# 3 楼答案
好吧,有点迂腐,但既然这是一个OSGi标记的问题
还有一件事,Boris给出了一个正确的解决方案,但它不是很有效,因为它总是占用4个线程和一个无限的LinkedQueue。更糟糕的是,代码像服务一样运行,像服务一样说话,但似乎没有被用作服务。我认为我们可以做得更好,因为队列+执行器是双重的,在OSGi中,这应该是一种服务
假设
process(...)
总是“很快”结束,则无需清理。在这个模型中,流量不会像您使用(任意?)时那样被限制池中有4个工作线程。执行器的内部队列用于缓冲。您可以将其限制如下:您甚至可以通过Configuration Admin轻松配置:
这段代码的美妙之处在于,大多数错误情况都会被记录下来,前后并发关系是正确的,因为在OSGi中得到的保证是正确的。这段代码实际上可以按原样工作(不保证某些拼写错误,实际上还没有运行)