java - main 方法中的同步块(synchronized block)

标签 java multithreading synchronized thread-synchronization

在下面关于线程间同步的代码中,根据生成的输出,尽管在 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()线程再次运行,可以在DemonThreadrun()方法中反转, 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/

相关文章:

java - 使用 try 和 finally 的同步方法的行为

java - java线程中如何判断同步哪个对象?

java - 如何清除设备内存缓存

java - 使用字符串列表动态创建对象?

python - python 中的锁创建

wpf - WPF在一定程度上延迟了UI的更新

java - MapWritable 的 MapWritable 上的迭代器

java - 如何在java中使用ecc加密图像

database - 在ring网站中使用atom作为内存数据库

java - 迭代 LinkedHashSet 时跳过同步并且未完成删除?