package sleep;
import dream.Dream;
public class Main {
public static void main(String[] args) {
if (new Sleeper().enter(new Dream()) != 0) {
// The goal is to reach this line
System.out.println("Am I still dreaming?");
}
}
}

Solution

The synchronized on the dream method means that it takes the monitor (lock) of the Sleeper object when we enter it, and it releases it again when we leave it. No other thread can enter the method while the monitor is held.

But here’s the catch: the monitor isn’t necessarily held all the time while the method is running. With Object.wait you can release a monitor in the middle of a synchronized method.

How do we apply that to solve this puzzle? When we enter the outer dream, we use wait to release the monitor. But first we launch a separate thread, that will also enter a dream. Entering that inner dream makes the second thread take the monitor. So in the inner dream, we use wait a second time to release the monitor. That allows the main thread stop waiting, take the monitor back, and leave the outer dream. And there we are: we have woken up from the outer dream, back where we started in main, but the dream within the dream goes on in the second thread.

And the winner is…

I got more answers than I expected. The first one came from David Shay. Congrats!

It’s a bit repetitive, but as promised, you can see and compare all dreams as comments below this post.

Conclusion

The moral of the story: synchronized on a method doesn’t mean two different threads can’t be in it at the same time. It only ensures that such threads cannot execute concurrently; at least one of them must be waiting.

You can prevent this kind of abuse and other problems, by using a private object as monitor:

Here is my solution. It consists in using a wait on the sleeper to allow the first dream to finish before the second one. This is an illustration of why it is better to use a private monitor rather than “this”.

The Java Specialists’ Newsletter brought my attention to this puzzles. The idea of my solution is to start another thread within Dream.dream which calls enter on the sleeper. The first thread is suspended within a wait and released, after the new thread has incremented the dream value and is suspended itself.

Yes, it’s possible using another thread.
1. Once user increases level counter inside Dream.dream() method,
2. Trigger another thread
3. Release the synchronize lock (using object.wait() with timeout)
4. meanwhile another thread will acquire synchronize lock and will also increase level.
5. Now, inovke object.wait() from second thread, with some sufficient long timeout.
6. Main thread will come out of wait(), will reaquire the lock, decrement the level.

Here we go. Now level is 1 (since second thread has not yet finished it’s synchronized block.

Hi, mobile and I wont write java using an onscreen kbd, but: I would launch a thread, let main thread wait() on sleeper, let other thread dream a dream which does notify() on sleeper then waits itself. Main thread wakes up and returns with other thread still blocked.