我正在读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");
(在“Synchronized”之前使用字符串“World”调用构造函数) 它会打印
[Hello]
[Synchronized]
[World]
正如我原先预料的那样。
我没有在这里找到这样的问题,所以我希望我做得对...谢谢!
答案 0 :(得分:4)
简短的回答是,synchronized
阻止唯一保证的是你对Callme.call
的3次呼叫将是互斥的 - 你不会(例如)最终得到你的所有3个Thread.sleep
中的线程同时调用。它不能保证三次调用发生的顺序,事实上,有可能(尽管不太可能)多次运行未修改的代码可能导致在任何特定运行中以任何顺序输出3个单词
答案 1 :(得分:1)
当你启动多个线程时,他们都需要一些时间来启动,java不保证这完成的顺序。到达call()方法的第一个线程将执行它,然后执行下一个。您的代码中没有任何内容强制执行此序列。
答案 2 :(得分:1)
当多个线程正在等待锁定时,无法保证锁定在释放后将被赋予哪个线程。文档没有指定如何处理此订单,但它也不是随机的。我肯定不能肯定地说,但似乎默认实现以LIFO风格(后进先出)锁定,这就是为什么世界首先输出。尝试使用更多的对象。