0

I am implementing a producer and consumer pattern using ArrayDeque and running into a strange problem.

Consumer.java
Class Consumer {
    public final Queue<Msg> my_queue = new ArrayDeque<Msg>();

    public void begin() { 
        new Thread() {
            new Runnable() {
                public void run() {
                    while(true) {
                        while(my_queue.isEmpty()) {
                           // do nothing
                        }

                        Msg msg = my_queue.remove();
                        msg.doSomething(); 
                    }
                }
            }
        }.start();
    }
}

Since my_queue is public, I may have > 1 threads performing my_queue.add(msg). However, the strangeness occurs because doSomething is never called when running in production. However, when i am in debug mode and use a break point, doSomething() will be called! Can anyone explain this?

delita
  • 1,571
  • 1
  • 19
  • 25

1 Answers1

1

ArrayDeque is not thread safe. You'll have to guard it with a lock (synchronized keyword or read/write lock) in order to access it safely from different threads.

Another option is to use a thread safe deque implementation, preferably a blocking one (e.g. LinkedBlockingDeque), which will also allow you to avoid your busy wait for the queue to become non-empty.

Eyal Schneider
  • 22,166
  • 5
  • 47
  • 78
  • Can u explain the busy wait? I thought that thread safety indicates the integrity of a shared data might be compromised. – delita Dec 31 '14 at 10:01
  • @delita: There are two issues with your code. The first one is thread safety - ArrayDeque doesn't guarantee to keep its contract when accessed by multiple threads, because its internal structure may become inconsistent. The second issue is related to resource usage rather than correctness. Your while loop is keeping the cpu busy, instead of using a wait/notify mechanism (used internally by LinkedBlockingQueue), which suspends the thread until a condition is met. – Eyal Schneider Dec 31 '14 at 10:21
  • tks for ur explaination. But suppose data inconsistencies are not my concern at the moment. I understand the the thread is super busy, but wouldn't at some point my_queue.add() be called from another thread? – delita Dec 31 '14 at 10:47
  • 1
    @delita: Yes, but that doesn't mean that the consumer thread will see the new value. Unless you use thread synchronization in your code, the compiler and hardware can assume that data isn't shared between threads, and apply optimizations that prevent one thread from seeing changes performed by other threads (See Thread Visibility articles). – Eyal Schneider Dec 31 '14 at 11:35