dallin_sh
dallin_sh

Reputation: 13

Concurrent-safe queue in Java

I'm trying to create thread safe queue with unique elements. I see no vulnerabilities but not sure still is this realisation thread safe or not? get(), add(), toArray() methods do everything under lock, toString() and equals() use toArray() in order to get main array copy and work independently with copy without locks.

public class SafeQueue<T> {
        private final Object[] queue;
        private final HashSet<T> content;
        private final Lock lock;
        private int size;
        
        public SafeQueue() {
            queue = new Object[100];
            content = new HashSet<>(100);
            lock = new ReentrantLock();
        }

        public boolean add(T el) {
            Objects.requireNonNull(el);
            final Lock lock = this.lock;
            lock.lock();
            try {
               //some logic
            } finally {
                lock.unlock();
            }
            return true;
        }

        public T get() {
            final Lock lock = this.lock;
            lock.lock();
            try {
                T el = (T) queue[0];
                if (el != null) {
                    //some shift logic
                    content.remove(el);
                }
                return el;
            } finally {
                lock.unlock();
            }
        }

        public Object[] toArray() {
            final Lock lock = this.lock;
            lock.lock();
            try {
                return Arrays.copyOf(this.queue, size);
            } finally {
                lock.unlock();
            }
        }

        @Override
        public boolean equals(Object o) {
            Object[] eqQueue = ((SafeQueue<?>) o).toArray();
            Object[] curQueue = toArray();

            //some comparison logic with eqQueue and curQueue
            return equal;
        }

        @Override
        public String toString() {
            Object[] curQueue = toArray();
            StringBuilder sb = new StringBuilder();
            sb.append('[');
            //some logic with curQueue
            return sb.toString();
        }
    }

Upvotes: 0

Views: 220

Answers (2)

Solomon Slow
Solomon Slow

Reputation: 27115

You might want to ask, what does it mean for the equals method to be thread safe? Consider this:

SafeQueue<T> qa = ...;
SafeQueue<T> qb = ...;
...
if (qa.equals(qb)) {
    handleEqualsCase();
}

If you had any reason to worry about the thread-safety of the equals() method, that could only be because other threads potentially could modify either queue when equals() is called.

But, by the time handleEqualsCase() is called, those other threads still could be running, and now, neither qa nor qb is locked. There is no guarantee that the two queues still will be equal when handleEqualsCase() is called. But, if they're not equal, that must be a Bad Thing, right? Otherwise, why would you have bothered to test for equality in the first place?

Here's one way around that problem. Instead of writing a traditional equals() method, write something like this instead:

private static
boolean unsynchronizedEqualityTest(SafeQueue<T> qa, SafeQueue<T> qb) {
    ...
}

public static
void doIfEqual(SafeQueue<T> qa, SafeQueue<T> qb, Runnable handler) {
    qa.lock.lock();
    qb.lock.lock();
    try {
        if (unsynchronizedEqualityTest(qa, qb)) {
            handler.run();
        }
    } finally {
        qb.lock.unlock();
        qa.lock.unlock();
    }
}

Now, when the client-supplied handler is invoked, it's guaranteed that the two queues still will be equal because they're both still locked.


But BEWARE! There's potential for a deadlock if one thread calls doIfEqual(qa,qb,...) and another thread calls doIfEqual(qb,qa,...). I'll leave it to you to figure out how to prevent that deadlock from happening.

Upvotes: 2

talex
talex

Reputation: 20455

Yes, your implementation is thread safe.

Upvotes: 1

Related Questions