In your constructor you should validate your limit. Limits less than 1 are probably an error.
I mentioned in another answer that you should avoid synchronized methods because that leaves you vulnerable to uncontrolled locking. In this case, you have the private queue instance. You should make that final, and then use that as the monitor-lock for synchronization (the limit should be final too). Hmmm... your queue is not even private. In your current code, it is possible for another class in your package to change the contents of the queue without locking on the controls at all...:
private final List<T> queue = new LinkedList<T>();
private final int limit;
Note how the limit is not initialized here, but in the constructor.
Hmm, why use List<T>
when you can use the Deque<T>
personality of LinkedList
? It should be:
private final Deque<T> queue = new LinkedList<T>();
then use the addLast
and removeFirst
methods....
You should, if you can, make the whole class final as well, to prevent people from making sub-classes of your queue.
Then, in your methods, synchronize on the queue:
public void enqueue(T item) throws InterruptedException {
synchronized(queue) {
while (queue.size() == limit) {
queue.wait();
}
if (queue.isEmpty()) {
queue.notify();
}
queue.addLast(item);
}
}
There I use the better isEmpty()
method. Additionally, you only need to notify a single waiting thread that there's data (you can do this now because nobody other than you can lock on the queue).
The matching dequeue method would be:
public T dequeue() throws InterruptedException {
synchronized(queue) {
while (queue.isEmpty()) {
queue.wait();
}
if (queue.size() == limit) {
queue.notify();
}
return queue.removeFirst();
}
}