Concurrent Stack with blocking and non-blocking methods I wrote it this just for learning. Is there holes at this code?

public interface ConcurrentStack&lt;T&gt; {
    //blocking
    void put(T t) throws InterruptedException;

    //blocking
    T poll() throws InterruptedException;

    //non-blocking put
    boolean offer(T t);

    //non-blocking get
    T take();
}

class ConcurrentStackImpl&lt;T&gt; implements ConcurrentStack&lt;T&gt; {
    private volatile AtomicBoolean locked = new AtomicBoolean(false);
    private List&lt;T&gt; internalList = new ArrayList&lt;T&gt;();
    private final int maxSize; // this final mandatory? I am afraid about visibility

    public ConcurrentStackImpl(int maxSize) {
        if (maxSize &lt;= 0) {
            throw new IllegalArgumentException();
        }
        this.maxSize = maxSize;
    }

    @Override //blocking
    public void put(T t) throws InterruptedException {
        while (!locked.compareAndSet(false, true)) ;//busy waiting
        internalList.add(t);
        locked.set(false);
    }

    @Override // non-blocking
    public T poll() throws InterruptedException {
        while (!locked.compareAndSet(false, true)) ;//busy waiting
        T value = internalList.get(internalList.size() - 1);
        locked.set(false);
        return value;
    }

    @Override
    public boolean offer(T t) {
        if (locked.compareAndSet(false, true)) {

            if (internalList.size() &gt;= maxSize) {
                return false;
            }
            boolean addResult = internalList.add(t);
            locked.set(false);
            return addResult;
        }
        return false;
    }

    @Override
    public T take() {
        if (locked.compareAndSet(false, true)) {
            T t = internalList.get(internalList.size() - 1);
            locked.set(false);
            return t;
        }
        return null;
    }

}
I see that you made improvements to your code since here.

Synchronizing

You decided to use internal locking what is technically ok. The way you did it is a variant that I never used. I prefer to use following pattern:

Define an object local Lock-Object:

Object lock = new Object();


And synchronize with the synchronized-block construct:

public void anyMethod() {
    synchronized (this.lock) {
        // do stuff in monitor here
    }
}


Even if your approach is comparable to this you should go with less statements as you are always have aquire the lock with locked.compareAndSet(false, true) and release the lock with locked.set(false). You have no compiler and language support for this locking mechanism. You can easily forget to release the lock or you may find yourself in situations that will compromise your locking like: If your list is empty and you call the poll-method, it aquires the lock, failing afterwards with an ArrayIndexOutOfBoundsException that causes the lock never to be released. That is also true for the take-method().

Missing maxSize constraint (?)

I do not know if there should be any other assertion in the put-method. But there you do not check for maxSize.

Handle empty list

Your take()-method and your poll-method are vulnerable if the internalList is empty. They both fail with an ArrayIndexOutOfBoundsException. Either you return null or what I think is the better way to check for emptyness and throw an "EmptyStackException". This is the standard behaviour from the Java Stack implementation:

java.util.Stack&lt;Object&gt; stack = new java.util.Stack&lt;&gt;();
stack.pop(); // throws EmptyStackException


Avoiding the ArrayIndexOutOfBoundsException has semantical reasons. This Exception is published from different abstraction layer. So using an EmptyStackException is an interpretation of the underlying state of the internalList from the stack'S point of view.

You may say that you catch the ArrayOutOfBoundsException and map it to the EmptyStackException which would be the correct semantic. But you should avoid it to be thrown as throwing exceptions is very expensive.

Busy waiting

Currently you use a while-loop to wait for new elements if no element is present.

Busy waiting should be replaced by a non cpu killing concept. I doubt that in your case busy waiting or equivalent functionality should be done as mentioned in the comments there is a possibility never to recover from it. Providing a timeout mechanism would be an approach. Your busy waiting solution could easily extended to evaluate a given timout but it keeps very cpu expensive.

On the other side a non cpu killing way is complicated. The only chance to do so is to instantiate a Timeout-thread sleeping n seconds, before put the current thread to wait and notify it if the timout is reached with a timout marker. You have to consider that a notification should also be made when new elements become available. Furthermore your timeout thread has to be killed. You have to decide what to do if a timeout happens (returning null oor throwing an exception). Equivalent Java classes return null.

A personal note: In productive environments I would not implement such a timeout mechanism by myself if there is a chance to use existing well tested solutions. For the sake of education this is something where you certainly learn a lot but it also can be very frustrating as this goal is miles away in contrast to centimeters to the implementation so far. But I encourage you at least to go some meters to experience the burden you put on your shoulders.