问题
I am trying to understand the concept of synchronized blocks in java. As of the documents that I have read, I understood that if we acquire a lock ( synchronized block using an instance variable ) then we cannot acquire a synchronized lock on same object in that class. But when I tried practically using the following snippet I found that my understanding is going wrong.
I.e I am able to acquire lock (synchronized block on same instance variable) in two different methods at the same time. When the thread is started it will go to run method and wait indefinitely and will not come out of the synchronized block. At the same time if I call the stop method using the same thread it goes into the synchronized block and executes notify statement. I searched in the Java doc but I couldn't find any.
This is the code snippet:
public class MyClass extends Thread
{
private Object lock = new Object();
public void run()
{
synchronized(lock)
{
lock.wait()
}
//other code
}
public void stop()
{
synchronized(lock)
{
lock.notify()
}
//other code
}
}
Here is the code snippet of how i am managing the MyClass thread:
public class MyClassAdmin
{
MyClass _myclass;
public MyClassAdmin()
{
_myclass=new MyClass();
_myclass.start();
}
public void stop()
{
_myclass.stop();
}
public static void main(String args[])
{
MyClassAdmin _myclassAdmin=new MyClassAdmin();
_myclassAdmin.stop();
}
}
According to my understanding when the thread is started it will acquire lock on 'lock' object (synchronized block in run method of MyClass). When i call the stop method it should wait indefinitely until the run method comes out of the synchronized block (which will never happen in this case). But when i executed, call to stop method acquired lock on the 'lock' object and notified the object which resulted in shutdown of the thread.
回答1:
Both of your methods use the same lock. If your MyClass thread happens to start waiting before the main thread can call the stop method, your stop method can still proceed, because the waiting thread lets go of the lock. Once a thread enters the wait method it releases the lock before it goes dormant, and doesn't re-acquire the lock until it exits the wait method.
This is the relevant API doc for Object#wait, the second paragraph covers what I described above about how wait releases the lock. Pay attention to the part where it says you have to call this method in a loop, otherwise you have an order-dependency bug that can cause the waiting thread to hang when the notification arrives in the main thread before the other thread can start waiting.
public final void wait() throws InterruptedException
Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object. In other words, this method behaves exactly as if it simply performs the call wait(0).
The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.
As in the one argument version, interrupts and spurious wakeups are possible, and this method should always be used in a loop:
synchronized (obj) { while (<condition does not hold>) obj.wait(); ... // Perform action appropriate to condition }
This method should only be called by a thread that is the owner of this object's monitor. See the notify method for a description of the ways in which a thread can become the owner of a monitor.
Understood this is a toy example, but subclassing Thread and overriding Thread methods is confusing. One of the reasons for using Runnable instead of Thread is that there's no opportunity to cause problems by mistakenly overriding Thread methods.
回答2:
This is multithreaded and it may wait forever may not. In your case you were lucky that _myclassAdmin.stop(); were executed after MyClass has started executing and executed wait();
I ran the program after changing the method stop() name to stop1() it were waiting forever.
To get consistent behavior do one thing, put a 1 sec sleep between two method call in main like:
MyClassAdmin _myclassAdmin=new MyClassAdmin();
Thread.sleep(1)
_myclassAdmin.stop();
Now, the execution will always halt.
Also, when a thread calls wait() it releases the monitor associated with it, so any other thread can aquire that lock and issue a notify() / notifyAll() to wake up waiting threads. This is expect
来源:https://stackoverflow.com/questions/35745160/java-synchronize-block-on-same-object-in-different-methods