Java synchronous queue implementation I just want to make sure there aren't any deadlocks or inconsistencies (the code is also available on GitHub). 

Disclaimer - In real life, I would not implement a queue myself, but use an existing implementation. This is just preparations for job interviews.

package org.basic.concurrent;

import java.util.ArrayList;
import java.util.List;

public class SynchedQueue&lt;T&gt; {
    private final Object lock = new Object();
    private final Object full = new Object();
    private final Object free = new Object();

    private final List&lt;T&gt; buffer;
    private int head;
    private int tail;
    private int size;
    private final int capacity;

    public SynchedQueue(int capacity) {
        // http://stackoverflow.com/questions/4912088/how-to-create-a-fixed-size-generic-buffer-in-java
        buffer = new ArrayList&lt;T&gt;(capacity);
        for (int i = 0; i &lt; capacity; ++i)
            buffer.add(null);
        this.capacity = capacity;
    }

    public void enqueue(T x) {
        if (x == null)
            throw new RuntimeException("Doesn't allow storing nulls");

        synchronized (lock) {
            while (!tryEnqueue(x)) {
                try {
                    free.wait();
                } catch (InterruptedException ignored) {
                }
            }
            full.notify();
        }
    }

    public T dequeue() {
        synchronized (lock) {
            while (true) {
                T item = tryDequeue();
                if (item != null)
                {
                    free.notify();
                    return item;
                }
                try {
                    full.wait();
                }
                catch (InterruptedException ignored) {}
            }
        }
    }

    private boolean tryEnqueue(T x) {
        assert size &lt;= capacity;
        if (size &gt;= capacity) {
            return false;
        }

        buffer.set(tail, x);
        tail = (tail + 1) % capacity;
        ++size;
        return true;
    }

    private T tryDequeue() {
        assert size &gt;= 0;
        if (size == 0)
            return null;
        T item = buffer.get(head);
        head = (head + 1) % capacity;
        --size;
        return item;
    }
}
I have not coded in Java for a few years so it might be good to get another opinion, though some points did stand out while reading your code.


It seems odd to me that you would use an ArrayList with a fixed size, personally I would just use an array for the buffer.
when you dequeue, you do not overwrite the value until you enqueue over the top of it. This might not seem like an issue (and if you only queue primative types like int, its not) but if you use reference types and the queue cycles slowly then it means you hold a reference to the object for longer than needed and it cannot be collected.
I'm a bit worried about catching the InterruptedException inside a while(true) loops without breaking out of the loop. The most common reason I have seen for one thread to interrupt another is when the interrupting thread wants to give the interrupted thread the opportunity to terminate gratefully, but this will prevent that option. I thought about what can be returned in such a case and eventually decided it might be best to let this exception flow through and be handled by the caller.