• Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

JVM over-prioritising synchronized code containing wait() over code containing notify() ?

 
John Mulholland
Ranch Hand
Posts: 40
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
In the code below I expected that, at least once-in-a-while, the synchronized code containing notify() would grab the lock before the synchronized code containing wait() - which would result in the call to wait() waiting forever. I know the correct idiom is to use a loop to avoid this behaviour but here it behaves consistently (up to a point - see next paragraph) without a loop. I don't understand why.

I played around a little and found that if thread with the wait() call is put to sleep for around 2.5 to 3 seconds before calling the synchronized code containing wait(), it behaves as I expect i.e. the lock is grabbed by the synchronized code containing notify(), and when this code releases the lock, the subsequent call to wait() waits forever ...

Surely a sleep of say 2000ms or even 500ms is enough time for the second thread to grab the lock ? I know that thread scheduling is JVM and OS dependent but I suspect there is something else going on here that I don't realise. Could the JVM see the calls to wait() and notify() and decide to give the lock to the code containing wait() every time (at least up to a certain point of delay like my 3 second example) ?

Any help would be appreciated.

 
Junilu Lacar
Bartender
Pie
Posts: 8779
81
Android Eclipse IDE IntelliJ IDE Java Linux Mac Scala Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
There's something that doesn't seem right about a Thread object synchronizing on itself and another class synchronizing on that same Thread object. As it it is now, your synchronization code has a kind of Inception-like quality to it -- referring to the Leonardo DeCaprio movie about multi-level dreams, where you can be dreaming that you're dreaming that you're dreaming... And you somehow get trapped forever in that labyrinth of nested dreams. That's what trying to wrap my head around your threads and lockskind of feels like.

Go back to the drawing board and reorganize your code so that Thread objects are separate from the objects that have state for which access needs to be synchronized
 
Tim Holloway
Saloon Keeper
Posts: 18359
56
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
What you have here is a race condition. And results are actually unpredictable, although they favor certain outcomes on a purely statistical basis - which is the most aggravating type of race to debug!

You spawn a new thread. It begins to run(). First thing run() does is acquire the built-in semaphore (lock).

But.

When you spawn a thread, the parent thread is continuing its own execution. If that parent thread itself attempts to acquire the semaphore, statistically it can sometimes succeed and thereby block the synchronized code in run().

Because both threads are executing simultaneously.

And they both have very short paths from the forking point to the synchronization point. So depending on how the task/interrupt scheduler of the VM happens to be operating at that instant, how much optimization the compiler did to the logic and the weather forecast for Omicron Persei 8, either one of the synchronizations has a statistical chance of being the first to grab the semaphore.

Now, if you'd defined run itself as synchronized, chances are that it would lock itself before the spawn method returned to the parent thread, thereby ensuring that the parent would be blocked forever. But because you synchronize within the run method, there's a tiny window of uncertaintly.

Very tiny, but nevertheless still there.
 
John Mulholland
Ranch Hand
Posts: 40
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks guys. I did what Junilu advised and used an external sync lock for both threads. Now the results are that the notify() and wait() blocks will race for the lock. Initial results seemed to show that outcome depended on which thread started first but I realise that is not guaranteed.

 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic