wait(n) is acting different each time I change the position of synchronized keyword

匿名 (未验证) 提交于 2019-12-03 02:38:01

问题:

Refer below code

     public void acquire(){         synchronized(a){             print("acquire()");             try{                 //Thread.sleep(5000);                 synchronized(this){                     wait(5000);                 }                 print("I have awoken");                 print("" + a);             }catch(Exception e){                 e.printStackTrace();             }         }         print("Leaving acquire()");     }       public void modify(int n){         print("Entered in modfy");         synchronized(a){             try{                 //Thread.sleep(5000);                 synchronized(this){                     wait(5000);                 }                 this.a=n;                 print("new value" + a);             }catch(Exception e){                 e.printStackTrace();             }         }     } 

And

        final SynchoTest ttObj = new SynchoTest();         Thread A = new Thread(new Runnable(){             public void run() {                 ttObj.acquire();                 }         },"A");          Thread B = new Thread(new Runnable(){             public void run() {                 ttObj.modify(97);                }         },"B");         A.start();         B.start(); 

As i know about wait(n), it pauses a thread until notify()/notifyAll() get called or the specified time n is over.

But...

  • In above methods if I directly use wait(n) as I used Thread.sleep(n), I get runtime exception.
  • If I synchronize both methods instead of surrounding wait(n) with synchronized block then I am not getting any exception but both threads get blocked forever.
  • But if I do like I attached ie wait(n) surrounding with synchronized block, it is working fine.

Please tell me why? Also tell me why is it not behaving different on positioning synchronized block if I use sleep(n) instead of wait(n)?

My question is about various result of wait(n) on various position of synchronized keyword.

@Gray

notify() or notifyAll(), and wait() must be in a synchronized block for the object you are waiting on

explained me why I was getting run time exception by positioning synchronized block on various position.

Now please explain me, why

public void method(){     synchronized(a){         synchronized(this){             wait(n);         }     } } 

is working fine. But

public synchronized void method(){     synchronized(a){         wait(n);     } } 

is blocking my thread forever.

回答1:

It is nothing about positioning synchronized keyword. You are facing problem since you locking other object and try to wait for another. Well @Gray has already been explained it, so not repeating it.

For your another problem, regarding why both threads are getting blocked;

Thread A: locks this [A: Runnable]

Thread A: locks a [A: Runnable]

Thread B: waiting for this [A: Runnable, B:BLOCKED]

Thread A: release this (meets wait) [A: TIMED WAITING, B:BLOCKED]

Thread B: lock this [A: TIMED WAITING, B: Runnable]

Thread B: waiting for a which is already locked by thread A [A: TIMED WAITING, B:BLOCKED]

Thread A: waiting for this which is locked by thread B [A: BLOCKED, B:BLOCKED]



回答2:

wait(n) and sleep(n) are completely different methods for pausing the execution of code:

wait(n) is called on an Object instance and will pause execution until the notify()/notifyAll() method is called on that instance or until the timer (the parameter) expires.

sleep(n) is called on a Thread object and essentially stops the world as far as that thread is concerned.

What your question comes down to is:

  • Do you want your object to act as a mutex, waiting for another piece of code to complete before continuing on it's own? Then use wait(n) with a corresponding notify()/notifyAll() in the other code.

  • Do you want to stop execution of the whole thread for a given timeframe? Then use Thread.sleep(n).



回答3:

Maybe your code is not working because you didn't call start() on your threads? After you instantiate your threads you need to:

A.start(); B.start(); 

Also, you cannot do something like the following pattern. You cannot synchronize on a and then change the object of a. Well you can do it but I doubt that's what you want. Basically the a would change and someone else locking on a would lock on another object so would be able to be in the synchronized block as well. Very bad pattern.

synchronized (a) {     ...     // not good     this.a = n; } 

Also, if you are not joining with the threads, then the main thread is going to continue on and not wait for A and B to finish. The JVM will wait for them to finish however since they are not daemon threads. And you have no guarantee that A will be called before B so the modify and acquire can happen in any order.

The difference between sleep(5000) and wait(5000) is that the wait can also be awoken by a call to notify() or notifyAll(), and wait() must be in a synchronized block for the object you are waiting on. synchronized also causes a memory barrier to be crossed which synchronizes the storage between multiple threads. It is more expensive because of that but in your case since you look to be sharing this.a then the memory barrier is required.



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!