我使用的是由多个线程填充的LinkedBlockingQueue,项目的数量很大(数千万个对象)。
LinkedBlockingQueue.take()需要花费很多时间(通过分析器检查)-- 56%的时间。
队列从不为空!!
什么会影响take()方法的性能?
更新:我对处理take()结果的代码做了一些修改,我还将take()放到了另一个线程中,性能几乎提高了50%。
我不明白这怎么可能,因为我没有改变推杆的任何逻辑……
更新:
在调用take()之前,我已经计算了队列已满的次数:
使用原始代码时,90%的呼叫队列已满。
使用改进的代码,13%的呼叫队列已满。
发布于 2013-06-19 22:29:48
如果我们查看代码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来通知队列中现在有空间的事实。
发布于 2013-06-19 22:29:24
take()是相当轻量级的,但是如果你足够调用它,它将消耗大量的CPU。这听起来像是你在传递大量的对象,而这些对象对于消费者来说只需要很少的工作。我建议尝试重组你的问题,这样做会更有效率。
例如,您可以:
也有可能你的个人资料并不完全准确。当你测量一小段时间时,它可能会给出混合的结果。
顺便说一下: take()是单线程的。如果有许多线程试图同时调用take(),它们将会相互阻塞。
https://stackoverflow.com/questions/17193840
复制相似问题