I have a PriorityBlockingQueue as follows:
BlockingQueue<Robble> robbleListQueue = new PriorityBlockingQueue<Robble>();
Robble implements Comparable<Robble> and I am able to sort lists without issue, so I know my comparisons work.
I also have the following Runnable:
private class RobbleGeneratorRunnable implements Runnable {
private final BlockingQueue<Robble> robbleQueue;
public RobbleGeneratorRunnable(BlockingQueue<ResultList> robbleQueue) {
this.robbleQueue = robbleQueue;
}
#Override
public void run() {
try {
robbleQueue.put(generateRobble());
} catch (InterruptedException e) {
// ...
}
}
private Robble generateRobble() {
// ...
}
}
I push a few thousand of these runnables into an ExecutorService and then shutdown() and awaitTermination().
According to the BlockingQueue JavaDoc, put(...) is a blocking action. However, when I iterate over the items in the queue they are only mostly in order -- there are some that are out of order indicating to me that the queue is not blocking properly. Like I said before I can sort the Robbles just fine.
What could be causing robbleQueue.put(generateRobble()) to not block properly?
According to the javadoc,
The Iterator provided in method iterator() is not guaranteed to
traverse the elements of the priority queue in any particular order.
If you need ordered traversal, consider using
Arrays.sort(pq.toArray())
Add, peek, poll and remove are required to operate in priority sequence, but NOT the iterator.
PriorityBlockingQueue is an unbounded queue, and if you read the javadocs for put() it states:
Inserts the specified element into this priority queue. As the queue
is unbounded this method will never block.
Why would you expect put() to block?
Iterating a PriorityQueue or PriorityBlockingQueue is explicitly stated in the Javadoc not to be ordered. Only add(), peek(), poll(), and remove() are ordered. This has nothing to do with whether blocking is happening correctly.
Related
I am using an ArrayBlockingQueue but sometimes it gets to full and prevents other objects to be added to it.
What I would like to do is to remove the oldest object in the queue before adding another one when the ArrayBlockingQueue gets full. I need the ArrayBlockingQueue to be like the Guava EvictingQueue but thread safe. I intend to extend the ArrayBlockingQueue and override the offer(E e) method like below:
public class MyArrayBlockingQueue<E> extends ArrayBlockingQueue<E> {
// Size of the queue
private int size;
// Constructor
public MyArrayBlockingQueue(int queueSize) {
super(queueSize);
this.size = queueSize;
}
#Override
synchronized public boolean offer(E e) {
// Is queue full?
if (super.size() == this.size) {
// if queue is full remove element
this.remove();
}
return super.offer(e);
} }
Is the above approach OK? Or is there a better way of doing it?
Thanks
Your MyArrayBlockingQueue doesn't override BlockingQueue.offer(E, long, TimeUnit) or BlockingQueue.poll(long, TImeUnit). Do you actually need a queue with "blocking" features? If you do not then you can create a thread-safe queue backed by an EvictingQueue using Queues.synchronizedQueue(Queue):
Queues.synchronizedQueue(EvictingQueue.create(maxSize));
For an evicting blocking queue, I see a few issues with your proposed implementation:
remove() may throw an exception if the queue is empty. Your offer method is marked with synchronized but poll, remove, etc. are not so another thread could drain your queue in between calls to size() and remove(). I suggest using poll() instead which won't throw an exception.
Your call to offer may still return false (i.e. not "add" the element) because of another race condition where between checking the size and/or removing an element to reduce the size a different thread adds an element filling the queue. I recommend using a loop off of the result of offer until true is returned (see below).
Calling size(), remove() and offer(E) each require a lock so in the worse case scenario your code locks and unlocks 3 times (and even then it might fail to behave as desired due to the previous issues described).
I believe the following implementation will get you what you are after:
public class EvictingBlockingQueue<E> extends ArrayBlockingQueue<E> {
public EvictingBlockingQueue(int capacity) {
super(capacity);
}
#Override
public boolean offer(E e) {
while (!super.offer(e)) poll();
return true;
}
#Override
public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException {
while (!super.offer(e, timeout, unit)) poll();
return true;
}
}
Note that this implementation can unnecessarily remove an element if between two calls to super.offer(E) another thread removes an element. This seems acceptable to me and I don't really see a practical way around it (ArrayBlockingQueue.lock is package-private and java.util.concurrent is a prohibited package so we can't place an implementation there to access and use the lock, etc.).
When you say "it gets to full and prevents other objects to be added", does that mean it would be sufficient to ensure that objects can be added anytime? If that's true, you could simply switch to an unbounded queue such as LinkedBlockingQueue. But be aware of the differences compared with ArrayBlockingQueue:
Linked queues typically have higher throughput than array-based queues but less predictable performance in most concurrent applications.
You can find an overview of JDK queue implementations here.
Given following variation of queue:
interface AsyncQueue<T> {
//add new element to the queue
void add(T elem);
//request single element from the queue via callback
//callback will be called once for single polled element when it is available
//so, to request multiple elements, poll() must be called multiple times with (possibly) different callbacks
void poll(Consumer<T> callback);
}
I found out i do not know how to implement it using java.util.concurrent primitives! So questions are:
What is the right way to implement it using java.util.concurrent package?
Is it possible to do this w/o using additional thread pool?
Your AsyncQueue is very similar to a BlockingQueue such as ArrayBlockingQueue. The Future returned would simply delegate to the ArrayBlockingQueue methods. Future.get would call blockingQueue.poll for instance.
As for your update, I'm assuming the thread that calls add should invoke the callback if there's one waiting? If so it's a simple task of creating one queue for elements, and one queue for callbacks.
Upon add, check if there's a callback waiting, then call it, otherwise put the element on the element queue
Upon poll, check if there's an element waiting, then call the callback with that element, otherwise put the callback on the callback queue
Code outline:
class AsyncQueue<E> {
Queue<Consumer<E>> callbackQueue = new LinkedList<>();
Queue<E> elementQueue = new LinkedList<>();
public synchronized void add(E e) {
if (callbackQueue.size() > 0)
callbackQueue.remove().accept(e);
else
elementQueue.offer(e);
}
public synchronized void poll(Consumer<E> c) {
if (elementQueue.size() > 0)
c.accept(elementQueue.remove());
else
callbackQueue.offer(c);
}
}
Since c is already synchronzied collection, and it's thus thread safe. But why do we have to use synchronized(c) again for the iteration? Really confused. Thanks.
" It is imperative that the user manually synchronize on the returned
collection when iterating over it:
Collection c = Collections.synchronizedCollection(myCollection);
...
synchronized(c) {
Iterator i = c.iterator(); // Must be in the synchronized block
while (i.hasNext()) {
foo(i.next());
}
}
Failure to follow this advice may result in non-deterministic behavior. "
http://docs.oracle.com/javase/6/docs/api/java/util/Collections.
The most any synchronized collection implementation could possibly do is to guarantee that each individual method call is synchronized. But iteration necessarily involves multiple separate method calls, so you, the user of the synchronized collection, have to synchronize on the whole iteration yourself.
For example, if you didn't synchronize on c, the contents of the collection could change between i.hasNext() and i.next() -- it could even go from having elements to having no more elements, in which case i.next() would fail.
Making all the methods on a class individually synchronized doesn't make an aggregation ( calling them in a group ) of those methods thread safe. By wrapping the Iterator in a synchronized block you are protecting that particular instance of the iterator from having its individual method called interspersed with other calls by multiple threads.
If I call .add() once it is safe, if I need to call .add() multiple times to complete a logical statement, there is no guarantee that someone else hasn't added something else or removed something else between my .add() calls unless I block everything else from calling .add() ( or any other method ) by synchronizing on the variable that represents the collection.
The Iterator makes mutiple calls to the individual methods on the collection, they all have to be wrapped in a single synchronized block to make them execute as a single transaction of sorts. Examine the source code of the implemenation of Iterator you will see what I mean. Here is the source code for List it makes multiple individual calls to the underlying implementation, so they all need to be executed in uninterrupted order by the same thread to be deterministic.
#Override
public Iterator<A> iterator() {
if (tail == null)
return emptyIterator();
return new Iterator<A>() {
List<A> elems = List.this;
public boolean hasNext() {
return elems.tail != null;
}
public A next() {
if (elems.tail == null)
throw new NoSuchElementException();
A result = elems.head;
elems = elems.tail;
return result;
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
The source for AbstractList.iterator() shows even more complicated logic that makes multiple calls.
A better wrapper is wrapping them in Immutable collections, then you guarantee that nothing else can alter the underlying collection between calls.
In Java doc:
[...] Among the exceptions are priority queues, which order elements according to a supplied comparator, or the elements' natural ordering, and LIFO queues (or stacks) which order the elements LIFO (last-in-first-out)
How implementation of java.util.queue uses LIFO instead of FIFO?
You can use any Deque as a LIFO queue using Collections.asLifoQueue method:
Queue<Integer> arrayLifoQueue = Collections.asLifoQueue(new ArrayDeque<Integer>());
Queue<Integer> linkedListLifoQueue = Collections.asLifoQueue(new LinkedList<Integer>());
You can use a java.util.LinkedList and use the pop() and push() methods and use it like a stack, which is a LIFO queue.
Implementation of the Queue can base on FIFO, priorities and LIFO - that is what official documentation says.
When a programmer first sees "Queue" he automatically thinks "it must be FIFO order" (or eventually prioritized order). But as documentation says there must be possibility to use Queue interface for LIFO ordering. Let me explain you how it can be done.
// FIFO queue usage
Queue<Integer> queue = new LinkedList<>();
queue.add(1);
queue.add(2);
queue.remove(); // returns 1
queue.remove(); // returns 2
// LIFO queue usage
Queue<Integer> queue = Collections.asLifoQueue(new ArrayDeque<>());
queue.add(1);
queue.add(2);
queue.remove(); // returns 2
queue.remove(); // returns 1
As you can see depending on the implementation, Queue interface can be used also as a LIFO.
Stack and LinkedList offered here are just a collections. Queue is not a collection. It is a part of concurrency package and can be used with threadpools.
I have just verified again and read javadoc that you have quoted. I think that the only option to use LIFO queue is to use priority queue with custom comparator that compare elements according to the insertion time in reverse order.
Deque can be used as LIFO or FIFO
Queue is a data structure that uses a technique of First-In-First-Out.
Here's a useful link : magi.toolkit.util.queue Class LIFOQueue
An implementation of a "Last In, First Out" Queue. Basically, a LIFO
Queue is a Stack.
I made a LIFO queue with limited size. Limited size is maintained by replacing the oldest entries with the new ones. The implementation is based on LinkedList.
package XXXX;
import java.util.LinkedList;
public class LIFOQueueLimitedSize<E> extends LinkedList<E> {
/**
* generated serial number
*/
private static final long serialVersionUID = -7772085623838075506L;
// Size of the queue
private int size;
// Constructor
public LIFOQueueLimitedSize(int crunchifySize) {
// Creates an ArrayBlockingQueue with the given (fixed) capacity and default access policy
this.size = crunchifySize;
}
// If queue is full, it will remove oldest/first element from queue like FIFO
#Override
synchronized public boolean add(E e) {
// Check if queue full already?
if (super.size() == this.size) {
// remove element from queue if queue is full
this.remove();
}
return super.add(e);
}
}
public final class ClientGateway {
private static ClientGateway instance;
private static List<NetworkClientListener> listeners = Collections.synchronizedList(new ArrayList<NetworkClientListener>());
private static final Object listenersMutex = new Object();
protected EventHandler eventHandler;
private ClientGateway() {
eventHandler = new EventHandler();
}
public static synchronized ClientGateway getInstance() {
if (instance == null)
instance = new ClientGateway();
return instance;
}
public void addNetworkListener(NetworkClientListener listener) {
synchronized (listenersMutex) {
listeners.add(listener);
}
}
class EventHandler {
public void onLogin(final boolean isAdviceGiver) {
new Thread() {
public void run() {
synchronized (listenersMutex) {
for (NetworkClientListener nl : listeners)
nl.onLogin(isAdviceGiver);
}
}
}.start();
}
}
}
This code throws a ConcurrentModificationException
But I thought if they are both synchronized on the listenersMutex then they should be executed in serial? All code within functions that operate on the listeners list operate within syncrhonized blocks that are synchronized on the Mutex. The only code that modifies the list are addNetworkListener(...) and removeNetworkListener(...) but removeNetworkListener is never called at the moment.
What appears to be happening with the error is that a NetworkClientListener is still being added while the onLogin function/thread is iterating the listeners.
Thank you for your insight!
EDIT: NetworkClientListener is an interface and leaves the implementation of "onLogin" up to the coder implementing the function, but their implementation of the function does not have access to the listeners List.
Also, I just completely rechecked and there is no modification of the list outside of the addNetworkListener() and removeNetworkListener() functions, the other functions only iterate the list. Changing the code from:
for (NetworkClientListener nl : listeners)
nl.onLogin(isAdviceGiver);
To:
for(int i = 0; i < listeners.size(); i++)
nl.onLogin(isAdviceGiver);
Appears to solve the concurrency issue, but I already knew this and would like to know what's causing it in the first place.
Thanks again for your continuing help!
Exception:
Exception in thread "Thread-5" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:782)
at java.util.ArrayList$Itr.next(ArrayList.java:754)
at chapchat.client.networkcommunication.ClientGateway$EventHandler$5.run(ClientGateway.java:283)
EDIT Okay, I feel a little dumb. But thank you for all your help! Particularly MJB & jprete!
Answer: Someone's implementation of onLogin() added a new listener to the gateway. Therefore(since java's synchronization is based on Threads and is reentrant, so that a Thread may not lock on itself) when onLogin() was called we in his implementation, we were iterating through the listeners and in the middle of doing so, adding a new listener.
Solution: MJB's suggestion to use CopyOnWriteArrayList instead of synchronized lists
Mutexes only guard from access from multiple threads. If nl.onLogin() happens to have logic that adds a listener to the listeners list, then a ConcurrentModificationException may be thrown, because it's being accessed (by the iterator) and changed (by the add) simultaneously.
EDIT: Some more information would probably help. As I recall, Java collections check for concurrent modifications by keeping a modification count for each collection. Every time you do an operation that changes the collection, the count gets incremented. In order to check the integrity of operations, the count is checked at the beginning and end of the operation; if the count changed, then the collection throws a ConcurrentModificationException at the point of access, not at the point of modification. For iterators, it checks the counter after every call to next(), so on the next iteration of the loop through listeners, you should see the exception.
I must admit that I don't see it either - if indeed removeListeners is not called.
What is the logic of the nl.onLogin bit? If it modified stuff, it could cause the exception.
A tip btw if you expect listeners to be moderately rare in being added, you could make the list CopyOnWriteArrayList type -- in which case you don't need your mutexes at all - CopyOnWriteArrayList is totally thread safe, and returns a weakly consistent iterator that will never throw CME (except where I just said, in nl.onLogin).
Instead of ArrayList , use can use thread-safe class CopyOnWriteArrayList which does not throw ConcurrentModificationException even if it is modified while iterating. While iterating if it is attempted to modify(add,update) then it makes a copy of the list, but iterater will continue working on original one.
Its a bit slower than ArrayList . It is useful in cases where you do not want to syncronise the iterations.