I decided to use drainTo
because I had to get the status of the temporary point from LinkedBlockingQueue
in my business.
drainTo
is
Removes all available elements from this queue and adds them to the specified collection.
It is a method called.
However, if you look at the help,
The behavior of this operation is undefined if the specified collection is modified while the operation is in progress.
There was an uneasy sentence, and I investigated whether there was a problem.
2017/11/30 postscript
LinkedBlockingQueue.java
/**
* @throws UnsupportedOperationException {@inheritDoc}
* @throws ClassCastException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
*/
public int drainTo(Collection<? super E> c, int maxElements) {
if (c == null)
throw new NullPointerException();
if (c == this)
throw new IllegalArgumentException();
if (maxElements <= 0)
return 0;
boolean signalNotFull = false;
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
int n = Math.min(maxElements, count.get());
// count.get provides visibility to first n Nodes
Node<E> h = head;
int i = 0;
try {
while (i < n) {
Node<E> p = h.next;
c.add(p.item);
p.item = null;
h.next = h;
h = p;
++i;
}
return n;
} finally {
// Restore invariants even if c.add() threw
if (i > 0) {
// assert h.item == null;
head = h;
signalNotFull = (count.getAndAdd(-i) == capacity);
}
}
} finally {
takeLock.unlock();
if (signalNotFull)
signalNotFull();
}
}
In addition, what is actually used is drainTo
with one argument,
LinkedBlockingQueue.java
return drainTo(c, Integer.MAX_VALUE);
And, since it is just calling the same method that is overloaded, there is no problem if you check here.
takeLock A lock object for locking the ** retrieval ** of data.
putLock Although it does not appear in the above source, it is a lock object for locking the ** addition ** of data.
count
ʻAtomicIntegertype field. Every time I change the data, it seems that I change it manually in the class. (It seems that it is not just returning
Queue.size`)
We will look at only the necessary parts in order from the top.
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
Acquire the acquisition lock before starting the data acquisition.
Do you need an additional lock? * I thought, but it is no longer needed due to the following processing.
Get the number
int n = Math.min(maxElements, count.get());
Before starting data acquisition, ** decide how many items to acquire from the beginning **. This allows you to ** ignore data added during the process of drainTo **.
drainTo
.drainTo
because the number of acquired data is calculated first.LinkedBlockingQueue.drainTo
can be safely executed even in a multithreaded environment.It seems that it can be said.
personally,
** If you want to get data all at once, you should lock the additions in the meantime! ** **
I will think.
I was wondering if there was an approach of "deciding the number of data first". It was a very good study.
Recommended Posts