Java - 同步线程 - 输出顺序错误

时间:2015-04-20 22:59:15

标签: java multithreading

我正在读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]
正如我原先预料的那样。

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

3 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:1)

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

答案 2 :(得分:1)

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