Java – Syncronized Thread – 以错误的顺序输出

在使用Java愚弄一年之后,我正在阅读Java The Complete Reference(第9版)。 到目前为止对本书很满意,但我现在对同步线程有一个非常奇怪的问题:

package syncro; class Callme { void call(String msg) { System.out.print("[" + msg); try { Thread.sleep(1000); } catch (InterruptedException e) { System.out.println("Interrupted"); } System.out.println("]"); } } class Caller1 implements Runnable { String msg; Callme target; Thread t; public Caller1(Callme targ, String s) { target = targ; msg = s; t = new Thread(this); t.start(); } @Override public void run() { synchronized (target) { // SYNC BLOCK target.call(msg); } } } public class Syncronized { public static void main(String[] args) { Callme target = new Callme(); Caller1 ob1 = new Caller1(target, "Hello"); Caller1 ob2 = new Caller1(target, "Synchronized"); Caller1 ob3 = new Caller1(target, "World"); try { ob1.t.join(); ob2.t.join(); ob3.t.join(); } catch (InterruptedException e) { System.out.println("Interrupted"); } } } 

打印出来:

 [Hello] [World] [Synchronized] 

而且我不明白这是怎么回事。 另外值得一提的是,如果换掉线路

  Caller1 ob2 = new Caller1(target, "Synchronized"); Caller1 ob3 = new Caller1(target, "World"); 

(构造函数在“已同步”之前使用字符串“World”调用)将打印

 [Hello] [Synchronized] [World] 

正如我本来期望的那样。

我没有在这里找到这样的问题,所以我希望我做得对…谢谢!

简短的回答是,您的synchronized块唯一保证的是您对Callme.call的3次调用将是互斥的 – 您不会(例如)同时在Thread.sleep调用中结束所有3个线程。 它不能保证三个调用发生的顺序,事实上,有可能(尽管不太可能)多次运行未修改的代码可能导致在任何特定运行中以任何顺序输出3个单词。

当你启动多个线程时,他们都需要一些时间来启动,java不保证这完成了哪个顺序。 到达call()方法的第一个线程将执行它,然后执行下一个。 您的代码中没有任何内容强制执行该序列。

当多个线程正在等待锁定时,无法保证锁定在释放后将被赋予哪个线程。 文档没有指定如何处理此订单,但它也不是随机的。 我肯定不能肯定地说,但似乎默认的实现以LIFO风格(后进先出)锁定,这就是为什么世界首先被输出。 尝试使用更多对象。