Yes, this deadlock is expected. It occurs when consumer() is called with the empty queue. In this case consumer() holds lock on "this" and waits for an object from myQueue. Same time any producer() can't take lock on "this" (held by consumer) and thus can't put any object to myQueue, which prevents consumer from taking an object.
To resolve deadlock, you may make only part of methods synchronized or use simple queue and implements your own waiting for a data.
Example of partial synchronization:
public class mytest {
private BlockedLinkedQueue myQueue;
public void consumer() {
synchronized(this) {
...
}
myQueue.take();
synchronized (this) {
...
}
}
public void producer() {
synchronized(this) {
...
}
myQueue.put()
synchronized(this) {
...
}
}
}
In this case, lock on "this" is released during myQueue operation. And it will allow producer() to procede it's way and put an object to the queue.
Second example:
public class mytest {
private Queue myQueue;
public synchronized void consumer() {
...
while (myQueue.isEmpty()) {
this.wait();
}
myQueue.take()
...
}
public synchronized void producer() {
...
myQueue.put()
this.notify();
...
}
}
In this example lock on "this" is released during call to this.wait() (see Object.wait() for details) and it allows producer to put object to the queue. Also, producer wakes up one of consumers waiting for data.
Please, note, that in both cases producer method will be executed when only a "half" of consumer method is executed. I.e. consumer method is no more atomical at all, but only at it halfs. And if you need atomicity of the consumer, then you should think about better specification of the producer/consumer methods, because described deadlock is logical flaw in the "synchronization". You can't put object during execution of "atomic" consumer() method and at the same time consumer() requires object to be in the queue.