Java Puzzle 2: Dreams - Solution
Feb 26, 2012Time to dream the solution to the dreams puzzle. As a reminder, here's the challenge:
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:
But that still leaves me unsure if I actually woke up this morning.
136 comments
At work now so I can’t try, but you can just start a large amount of dreams so level will overflow. After that each Dream exits its dream() method.
Here is my solution: two Dreams combining their forces…
This is more cleaner version.
Here is mine solution, it took me about 10-15 minutes to solve:
Hi Wouter, here is my solution. Nice puzzle!
This seems to work – the flaw in the reasoning being the guarantees of the synchronized blocks don’t hold if you use wait().
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”.
Start a thread which calls sleeper.dream(this) then call sleeper.wait(100) to release the synchronization lock temporarily.
I came up with something like this:
Solution for the dream puzzle:
Not too bad - it’s all down to wait()/notify() - here is a (slightly untidy) solution.
Very nice puzzle! Here is the source for my solution: http://pastebin.com/d2Sa2yKG
A bit trickier this puzzle, but the provided Sleeper parameter makes it possible to release the monitor and give access to it for another thread.
Oh, I love this. Can’t wait for the next riddle!
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.
That was not easy, but I got it ;)
Quick and dirty solution:
There, did it :) (but not in 15 minutes)
And the sleeper dreams forever ;)
Ok I’ve clean-ed up my source a bit, there were a lot of useless lines due to some experimentations ;) Here is a simpler version :
Ho god, Your comment system did break all indentation :/
Here’s my solution to this:
Hi, please find a working version below.
Not the best formatted code, but works :)
You can relinquish the synchronization lock with wait(). Just use two threads:
Not the neatest of code, but should suffice:
Nice puzzle. Here is my solution.
Make ‘em harder. :-)
My version (not the most readable one, but short):
Yes, it’s possible using another thread.
Here we go. Now level is 1 (since second thread has not yet finished it’s synchronized block. [code] Timeline T1 T2 level sleeper.enter 0 level++ 1 start T2 1 sleeper.wait(100) 1 sleeper.enter 1 level++ 2 sleeper.wait(1000) level– 1 return level = 1 1 enter into if level– 0 [/code]
Very good puzzlers, thx!
Use wait / notify to break the synchronisation.
Here is my solution:
Great puzzle by the way! :)
Great puzzles, look forward to seeing more! Heres my solution. Look forward to seeing other peoples.
Thx for interesting puzzle,
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.
This one wasn’t that hard…
(slightly more succinct than previous entry)
Another solution :D I hope this one is valid.
My solution uses the fact that Object.wait releases the sleeper’s monitor, allowing another Thread to call the enter method and wait as well allowing the main Thread to continue:
This will result in an infinite loop until Sleeper.java:11 throws java.lang.IllegalArgumentException. By then, level should have a value of Integer.MAX_VALUE, decrement it will return value of Integer.MAX_VALUE-1
Alternatively, it would have recursed so such that Sleeper.java:11 actually throws java.lang.StackOverflowError. When this happens the value of level is likely to be a value more than 2. Decrementing it will return a value more than 0
This doesn’t work. See also comment from Usman a little lower. Does it work for you, or did you not even try to run it?
This is some nice brain teaser. It took me quite a while.
The key idea is to release the lock obtained when entering the synchronized dream method.
Recursively overflow int value.
However had to increase stack size -Xss. However, this makes my machine extremely slow to respond :-). Will try to come up with some alternate mechanism.
Doesn’t work for me. I don’t see how it can work; because even in case of an overflow, counter– undoes what counter++ did.
Please find my solution below:
In the Dream, recursively enter the same dream again in a second thread, using wait and notify on the Sleeper to work around it’s synchronized block. Then release the master dream before the recursive dream is done.
I found this one much easier to solve than the clowns puzzle, but once I did I was ably to apply a similar multi-threaded solution for that one.
Here is my proposed solution, taking advantage that Sleeper synchronizes on himself.
The trick is that s.wait() will release the monitor that Java uses to synchronize the Sleeper.enter() call.
The idea is that
wait
releases the current monitor, thus we can enter a new dream on a new thread.too eager to make proper formatting - here we go again: There, did it (but not in 15 minutes)
Release the lock with wait()!
Hi, last night I posted an idea. Here’s code too:
Sleeper is actually exposing an undocumented API: synchronization on itself. Sleeper could fix this by using an internal Object for synchronization.
The bug is that the class is synchronizing on an object reference that is passes to untrusted code. The Dream implementation can release the lock, enter the enter(Dream) method on another thread, and then wake up the initial thread. At this point, the Sleeper class will have entered the enter(Dream) method twice, and exited it once.
Here’s an implementation:
This code seems to work, creates an inner dream that never ends in another thread:
Rough and unpolished (and probably creates extra unneeded thread, but who cares :)).
Hello,
it indeed took me a while to get this done, but here is my solution:
The Trick is to have a second that will increase the level but will not end, i therefore chose the name EndlessDream (we’ll see the code later). The first dream howewer needs to end, so the sleeper method will return and the required line will be printed.
At first sight, this seems imposisble with the synchronized method, but i then remembered, that you can temporarily leave a monitor using wait.
First we start our second endless dream in a new thread. The endless dream will however block because its synchronized on the sleeper object and our first dream has the lock.
We therefore need to give the endless dream a chance to start, which we do by using s.wait() in our first dream after starting the thread. The endless dream will then wake up and increase the level. We then use notify inside the endless dream to wake up our first dream. Here we need do consider that the notify will not give control to our first dream but continue our endless dream. Therefore a call to s.wait() is also needed in our endless dream.
Lots of explanations but i hope that made it clear. Finally, here is the code:
I forgot to mention, that this code will indeed make the second dream an endless one, as no one ever wakes the thread up again.
Here’s my solution:
It can be done by two simple threads.
This is really a cool puzzle. Thanks for it!
My solution uses a separate thread which lets the sleeper enter a second dream which endures while the first dream ends. The trick is to let the threads yield the lock, so that the synchronized method can be entered twice. Object.wait() does allow that.
I guess a counter-measure would be for the Sleeper to use a private lock object instead of synchronizing on the instance itself.
Regards, Andreas
The key seems to be to make sure that the DreamForever thread gets access to the monitor and then never exits.
Thanks for these puzzles, really enjoyed the first one, and this was also fun. I’m with Heinz - more hard ones please, don’t bother with the easy ones!
My solution for the Sleeper:
That was cool - tried various options on killing the other thread, while eventually it appeared not necessary procedure :)
Probably (almost definitely) not the best solution but seems to work. Spent ages trying to get the second thread to exit/interrupt so that it wouldn’t execute the finally block in Sleeper but didn’t seem to work.
Welcome any feedback.
Cheers, Nick.
Correction - should have pasted in the whole class:
Thanks for these great puzzles!
Here’s a commented solution. As always with concurrency, I find it hard to prove whether the solution is safe, but I think it is. I’m not sure though, whether “volatile” is necessary.
That was fun - hadn’t really thought of the relationship between synchronized methods and wait and notify before!
My version.
http://pastebin.com/7E5Prbgd
Great puzzle!! Thanks.
Oh, I guess that you don’t really need separate Dream classes (especially if you don’t mind infinite loops & threads, though you could implement a static counter to limit them)
Hi,
I’m a bit late with my entry but here it comes: it’s a dream that spawns another dream and waits for the second dream to start which will then cause the first dream to finish and then the night is over before the second dream came to its end. Don’t we all know this strange feeling when waking up and having some unfinished matters still on our minds?
Actually I found this puzzle a lot easier than the one with the clowns. Maybe because it is closer to what I have to deal with (i.e. debug) during my daily work.
BTW, I love this kind of puzzles, thank you!
Kind regards, Thomas
You can fool the Sleeper by doing a ping-pong with another thread, stealing Sleeper’s lock to insert an extra dream:
I should probably add a Thread.sleep() after the wait in StrangeDream.dream(Sleeper) - I think there’s a race as it stands.
Dream of unlimited depth can be created. The limit depends on your resources only, i.e. on how many threads can your JVM create under you OS with its default RAM. In this example it is set to 100. You can see the level, if you add one logging line to the Main class.
If smb wants to check the real level, logging can be added as follows:
… and to get the better feeling about what is going on, a single logging line can be added to the Sleeper:
synchronized does indeed keep multiple threads from running at once inside a given method - but it doesn’t stop one thread from running while others are waiting. This code works on my machine:
https://github.com/dlikhten/dreams
That contains the solution. You can’t use the security manager via intellij (it’s all set to go) but you can see that it is unnecessary as I don’t need the features of setAccessible. And it runs from command line :) Pretty simple actually, especially when you use drugs when you go sleep.
This seems to work.
Hi, I used a supplementary thread in order to increment the level counter and wait 2 seconds meanwhile the primary calling thread is waiting only 1 second. In this way the check on the level variable will be done while the supplementary thread is still waiting on a wait condition: A a result we will have the level counter with a value of 2.
actually lower synchronized block is not needed…
Sleeping other this problem was a good idea. I found a solution:
@Ludo : t’es un grand malade!
@Wouter : thank you for sharing thoses puzzles! Had a nice time burning some neurons on them, will have another nice time bashing some colleagues and friends tomorrow :-)
======================================================= Any comments above these line were made before the solution came out. Anything below comes after. If there is anything between the lines, clean your monitor.
If you make this change to the Sleeper class, none of the posted solutions will work anymore…
I wonder if it is still possible to break it like this?
I don’t expect it’s possible to break that. But I’d love to be surprised.
If you use Project Lombok, you can write:
The @Synchronized will create the lock field for you and wraps the entire method content in a synchronized block.
See http://projectlombok.org/features/Synchronized.html for more information.
Disclaimer, I’m one of the Project Lombok developers.
Simply awesome! I wish we could do this daily not weekly!!!
Concurrency devils are disturbing your dreams ;-)
The “official” solution is not guaranteed to reach the goal line. Just set a breakpoint on line 16 at
s.enter(new Dream() {
and debug.You’ll always wake up in the cold reality.
If you remove the timeout from
s.wait(200);
and inserts.notify();
beforedoWait(s);
in the inner dream and afterdoWait(s);
in Dream#dream(..), then you get the sweet dream in many more cases.But to be completely safe, every invocation of wait(..) needs to be performed inside a loop (see the Javadoc).
You’re right.
I was being lazy, and something that works 99.99% of the time unless you intentionally make it not work (by setting a breakpoint) seems good enough for this puzzle. I also didn’t want to make the sequence diagram any more complicated than it already is.
It needs an extra “Kids, don’t write code like this for real” disclaimer.
I can only agree with this comment ;P
Guys,
It seems that almost all of you forget to wrap wait calls in a cycle. It seems to be wrong.
It has many more things wrong with it. It relies on an implementation detail of the locking of the Sleeper; it does a frick’n
.wait()
on someone else’s lock. It also does complicated things without commenting why, it’s lacking javadoc and unit tests. Solutions to previous and next puzzles have done and will do things that make my wrongness-meter go much more into the red then any of that.The whole point of these puzzles is to break the conventional rules. The usual wrong or correct don’t apply here. All that matters is that it’s fun, it seems to work when you run it, and that others can understand why it works. And in my opinion, it also leads to a whole different kind of code beauty.
Thanks for the exercise for concurrency programming in Java.
I think the original task is a bit confusing because of the “// TODO implement me” in the dream method. I thought this is the only location you may modify but in your solution you added a method to the class.
It doesn’t really change anything to the puzzle; you can just as easily do it without that extra method.
I’m happy ! I found the solution ! Not easy but It was interesting. Thanks.