Reputation: 105
I am using LinkedBlockingQueue
that is getting filled by multiple threads, the number of items is big (tens of millions objects).
LinkedBlockingQueue.take()
takes a lot of time (checked via profiler) - 56% of time.
The queue is never empty!!
What can affect the performance of the take()
method?
UPDATE: I did some changes in code that handles the result of the take(), I also placed the take() into another thread, the performance was improved almost by 50%.
I don't understand how this is possible because I didn't change any logic of putters...
UPDATE:
I've counted the number of times queues is full before calling take():
With original code 90% of calls queue was full.
With improved code 13% of calls queue was full.
Upvotes: 0
Views: 2217
Reputation: 4844
If we look at the code here we can see that a lock must be taken before taking an element. If lots of threads are taking then there will be contention on this lock - the threads aren't waiting for something to appear but for other threads to take things.
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;
}
EDIT
In the case where you have one taker and lots of putters and the queue keeps getting full the bottleneck will become signalNotFull()
given by this code
private void signalNotFull() {
final ReentrantLock putLock = this.putLock;
putLock.lock();
try {
notFull.signal();
} finally {
putLock.unlock();
}
}
This needs to take the putLock
to signal the fact that there is now space in the queue.
Upvotes: 5
Reputation: 533442
take() is fairly light weight but if you call it enough it will consume lots of CPU. It sounds like you are passing large numbers of objects which require very little work for the consumer(s). I suggest trying to restructure you problem so this is done more efficiently.
You can for example,
It is also possible your profile is not completely accurate. When you measure small periods of time it can give mixed results.
BTW: the take() is single threaded. If you have many threads trying to call take() at the same time, they will be blocking each other.
Upvotes: 5