主方法中的同步块

在下面关于线程之间同步的代码中,根据生成的输出,为什么控制被转移到执行新线程,尽管在主方法中为同一对象“dt”获取了锁?

public class DemoThread extends Thread { public DemoThread() { } public void run() { int i=0; synchronized(this) { while(++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.主线程进入主方法的同步块。

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

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

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

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

6.新主线程完成执行

如果我错了,请纠正我

你很近:

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

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

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

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

5.通知通话但是没有唤醒主线程(?)

6.新主线程完成执行

直到第4步,它是正确的。

以下是步骤5中发生的情况:

调用notify()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语句中反转。
你还应该使这个线程稍微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上循环时离开锁,然后hibernate100 ms,main()线程可以再次运行。

这是输出:

主要在这里

从睡梦中醒来

从睡梦中醒来

再次主要在这里

sum = 2

从睡梦中醒来

从睡梦中醒来

从睡梦中醒来

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

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

在您的示例中,同步中没有争用,如果您从示例中引入一些对象并尝试从此对象读取和读取多个线程,您将获得更好的理解。