在下面关于线程间同步的代码中,根据生成的输出,尽管在 main 方法中为同一个对象“dt”获取了锁,但为什么控制被转移到新线程的执行?
public class DemoThread extends Thread {
public DemoThread() {
}
public void run() {
int i=0;
synchronized(this) {
while(++i<=5) {
sum=i;
try{
sleep(1000);
System.out.println("Woke up from sleep");
if(i>=2) this.notify();
}catch(InterruptedException ie) {
ie.printStackTrace();
System.exit(1);
}
}
}
}
private static int sum;
public static void main(String... args) {
DemoThread dt = new DemoThread();
dt.start();
synchronized(dt) {
try{
System.out.println("main here");
dt.wait();
System.out.println("main here again");
System.out.println("sum = " + sum);
}catch(InterruptedException ie){
ie.printStackTrace();
System.exit(1);
}
}
}
}
输出:
main here
Woke up from sleep
Woke up from sleep
Woke up from sleep
Woke up from sleep
Woke up from sleep
main here again
sum = 5
编辑:我想我能够找到一种可能的代码流程来解释输出:
1.Main线程进入main方法中的Sync block 。
2.调用wait。在 dt 对象上释放锁
3.新线程进入while循环,因为它已经锁定了对象dt
4.Thread.Sleep 执行完毕,并没有释放锁
5.notify 已调用但未启动主线程(?)
6.New和主线程完成执行
如有错误请指正
最佳答案
你很接近:
1.Main thread enters in the Sync block in the main method.
2.call to the wait is made. Lock released on the dt object
3.New thread enters the while loop as it has the lock on the object dt
4.Thread.Sleep is executed and it doesn't release the lock
5.notify call is made but doesnot wake the main thread(?)
6.New and the main thread finish the execution
到第4步,都是正确的。
这是第 5 步发生的情况:
notify()
被调用并通知 main()
线程。
但它现在没有机会再次运行。
为什么 ?因为 DemoThread
线程没有释放锁。
notify()
方法确实在 synchronized
语句中循环执行。
synchronized (this) {
while (++i <= 5) {
sum = i;
try {
sleep(1000);
System.out.println("Woke up from sleep");
if (i >= 2) {
notify();
}
} catch (InterruptedException ie) {
ie.printStackTrace();
System.exit(1);
}
}
并且根据 Object.notify()
javadoc :
The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object. The awakened thread will compete in the usual manner with any other threads that might be actively competing to synchronize on this object; for example, the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.
因此 main()
线程只能在 run()
方法 DemoThread
终止时运行。
要让main()
线程再次运行,可以在DemonThread
run()
方法中反转, synchronized
语句和 while
语句。
您还应该让这个线程稍微 hibernate ,让 main()
线程再次运行。
public void run() {
int i = 0;
while (++i <= 5) {
// let a chance for other threads
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (this) {
sum = i;
try {
sleep(1000);
System.out.println("Woke up from sleep");
if (i >= 2) {
notify();
}
} catch (InterruptedException ie) {
ie.printStackTrace();
System.exit(1);
}
}
}
}
现在 i >= 2
,和以前一样,其他线程会收到通知,但是当线程在 while
循环时离开锁,然后 hibernate 100 毫秒, main() 线程可以再次运行。
这是输出:
main here
Woke up from sleep
Woke up from sleep
main here again
sum = 2
Woke up from sleep
Woke up from sleep
Woke up from sleep
关于java - main 方法中的同步块(synchronized block),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48240147/