-2

I was web searching on a producer consumer problem and i got this link. The programmer used a Vector here for the sharedqueue.

I thought why would i need a synchronized block as Vector is already threadsafe. It must handle the threads by itself.

But when i tried to do it by removing the synchronized blocks. it gives me a IllegalMonitorStateException. Here is the code snippet for produce method

private void produce(int i) throws InterruptedException {

    //wait if queue is full
    while (sharedQueue.size() == SIZE) {
      //  synchronized (sharedQueue) {
            System.out.println("Queue is full " + Thread.currentThread().getName()
                                + " is waiting , size: " + sharedQueue.size());

            sharedQueue.wait();
      //  }
    }

    //producing element and notify consumers
   // synchronized (sharedQueue) {
        sharedQueue.add(i);
        sharedQueue.notifyAll();
   // }
}

My question is why we need to synchronized or take a lock on an already threadsafe object?

gusainhimanshu
  • 157
  • 1
  • 11
  • Read the documentation of wait() and notify(): it clearly says that you need to have the lock in order to call these methods. – JB Nizet Sep 27 '14 at 14:39

1 Answers1

2

Wihtout synchronization you could have this:

Producer Thread              Consumer Thread                  
                             if (sharedQueue.isEmpty) {
sharedQueue.add(i);
sharedQueue.notifyAll();
                                  sharedQueue.wait()
                             }

So, even though there is data in the queue, consumer thread would wait potentially forever, because stuff got added between it testing for data, and it starting wait for notification about added data.

Of course there are workarounds, such as timeout on wait, but these all have polling overhead, latency due to polling interval, ugly code, and so on. No reason to resort to such things when you can just use synchronization.


So why is it not enough, that the queue class is thread safe? Well, a thread safe class is not magic! Being thread safe just means, individual method calls to an instance of that class are thread safe. So for example if two threads do add at the same time to same instance, it will not corrupt anything, erase one operation with the other, or anything like that.

But if you have multiple threads doing multiple operations, then they can be interleaved, that's the whole point of many threads and pre-emptive multitasking after all! So what happens with interleaved operations, that depends on the operations. For example, many threads doing just add would add things at some unspecified order, but that's probably ok. But when you don't want operations to happen in "random" order, you need to use synchronization.

As shown by above example, in this case "random" order can result to consumer waiting indefinitely even with data in queue. As a matter of fact, if you ever have sequence "do modification, notify waiters", and waiters doing "see if there's something to do, otherwise wait", you have this same problem, and must use synchronization around both modification-notify and check-wait.


And you get error, because Java requires you to have the lock when notifying, because as explained above, it makes no sense without lock, it would always be an error, a bug. And this is not Java specific, this is fundamental to this type of mechanism, they always require lock, read more at this Wikipedia article section.

hyde
  • 60,639
  • 21
  • 115
  • 176
  • i know i can tweak the code and all, but all i wanted to know why we ever need to take a lock on a thread-safe object ? and as your edit says. **notify/wait makes no sense without lock,** sharedqueue is a threadsafe object. there must be already a lock on it internally – gusainhimanshu Sep 27 '14 at 14:52
  • Added a bit more text about why having a thread-safe container doesn't help here. – hyde Sep 27 '14 at 15:06
  • thanks for the explanation hyde. thank you hyde – gusainhimanshu Sep 28 '14 at 20:44