我正在使用被多个线程填充的LinkedBlockingQueue
,项目数量很大(数千万个对象)。
LinkedBlockingQueue.take()
需要花费大量时间(通过分析器检查) - 56%的时间
队列永远不会是空的!!
什么会影响take()
方法的效果?
更新: 我在处理take()结果的代码中做了一些更改,我还将take()放到另一个线程中,性能几乎提高了50%。
我不明白这是怎么可能的,因为我没有改变推杆的任何逻辑......
更新:
我在调用take()之前计算了队列已满的次数:
使用原始代码,90%的呼叫队列已满
通过改进的代码,13%的呼叫队列已满。
答案 0 :(得分:5)
take()的重量相当轻,但是如果你调用它就会消耗大量的CPU。听起来你传递了大量的物品,这些物品对于消费者来说需要的工作量非常小。我建议尝试重构你的问题,以便更有效地完成。
例如,您可以
您的个人资料也可能不完全准确。当你测量很小的时间段时,它会产生混合的结果。
BTW:take()是单线程的。如果你有许多线程试图同时调用take(),它们将互相阻塞。
答案 1 :(得分:5)
如果我们查看代码here,我们可以看到在获取元素之前必须进行锁定。如果有很多线程正在进行,那么这个锁就会存在争用 - 线程不会等待出现的东西,而是让其他线程可以处理。
public E take() throws InterruptedException {
E x;
int c = -1;
final AtomicInteger count = this.count;
final ReentrantLock takeLock = this.takeLock;
takeLock.lockInterruptibly();
try {
try {
while (count.get() == 0)
notEmpty.await();
} catch (InterruptedException ie) {
notEmpty.signal(); // propagate to a non-interrupted thread
throw ie;
}
x = extract();
c = count.getAndDecrement();
if (c > 1)
notEmpty.signal();
} finally {
takeLock.unlock();
}
if (c == capacity)
signalNotFull();
return x;
}
修改强>
如果您有一个接受者和许多推杆并且队列不断变满,则此代码将给出signalNotFull()
瓶颈
private void signalNotFull() {
final ReentrantLock putLock = this.putLock;
putLock.lock();
try {
notFull.signal();
} finally {
putLock.unlock();
}
}
这需要putLock
表示队列中现在有空间这一事实。