主方法中的同步块

时间:2018-01-13 13:05:31

标签: java multithreading synchronized thread-synchronization

在下面关于线程之间同步的代码中,根据生成的输出,为什么控件被转移到执行新线程,尽管为同一个对象获取了锁定" 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.主线程中的主线程进入同步块。

2.等待等待。锁定在dt对象上释放

3.新线程进入while循环,因为它锁定了对象dt

4.Thread.Sleep被执行,它没有释放锁

5.通知已发出但不会破坏主线程(?)

6.新主线程完成执行

如果我错了,请纠正我

2 个答案:

答案 0 :(得分:3)

你很近:

  

1.主线程中的主线程进入同步块。

     

2.等待等待。锁定在dt对象上释放

     

3.新线程进入while循环,因为它锁定了对象dt

     

4.Thread.Sleep被执行,它没有释放锁

     

5.通知已发出呼叫但未唤醒主线程(?)

     

6.新主线程完成执行

直到第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:

  

唤醒的线程将无法继续直到当前   线程放弃对此对象的锁定。被唤醒的线程会   以通常的方式与任何其他可能的线程竞争   积极竞争同步这个对象;例如,   被唤醒的线程没有可靠的特权或劣势   下一个锁定此对象的线程。

因此main()线程只能在run()方法DemoThread终止时运行。

要让main()主题再次运行,您可以在DemonThread run()方法,synchronized语句和while语句中反转。<登记/> 你还应该让这个线程稍微休眠一下,让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上循环然后再睡眠100 ms时,线程会离开锁,main()线程可以再次运行。

这是输出:

  

主要在这里

     

从睡梦中醒来

     

从睡梦中醒来

     

主要在这里再次

     

sum = 2

     

从睡梦中醒来

     

从睡梦中醒来

     

从睡梦中醒来

答案 1 :(得分:0)

synchronized关键字不用于控制线程的执行,它用于确保任何时候只有一个线程可以输入一个代码块。 通常,整个方法可以在{}之间进行同步或编码。

您还可以同步将在两个或多个线程之间共享的对象,通常是一些将由线程更新的数据结构,您需要确保状态是一致的而不是部分更新的。

在你的例子中,同步没有争用,如果你从示例中引入一些对象,多个线程试图从这个对象写入和读取,你将会更好地理解。