哪个线程先运行?

时间:2019-07-19 09:30:20

标签: java multithreading

在以下代码中,

public class Callme {

    public Callme() {
        // TODO Auto-generated constructor stub
    }

    void callA(String msg) throws InterruptedException
    {
        synchronized (this) {
             System.out.print("["+msg);
             Thread.sleep(1000);
        }
        System.out.println("]");
    }

    void callB(String msg) throws InterruptedException
    {
        synchronized (this) {
            System.out.print("{"+msg);
            Thread.sleep(1000);
        }
        System.out.println("}");
    }

    void callC(String msg) throws InterruptedException
    {
        synchronized (this) {
            System.out.print("("+msg);
            Thread.sleep(1000);
        }
        System.out.println(")");
    }

}

其他地方:

public class Caller implements Runnable {

    public char msg;
    public Callme target;
    public Thread t;
    public Caller(char msg, Callme target) {
        this.msg = msg;
        this.target = target;
        t= new Thread(this);
    }
    @Override
    public void run() {

        try {
            switch (msg) {
            case '[':
                target.callA("Hello");
                break;
            case '{':
                target.callB("Hello");
                break;
            case '(':
                target.callC("Hello");
                break;

            default:
                break;
            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

其他地方:

        Callme target = new Callme();
        Caller ob1 = new Caller('[', target);
        Caller ob2 = new Caller('{', target);
        Caller ob3 = new Caller('(', target);

        ob1.t.start();
        ob2.t.start();
        ob3.t.start();

假设callA首先执行,在执行synchronized语句后,在我的试用中,总是ob1下一步执行。
我认为有时ob2同步步骤应在此之前执行(至少有时)。

实际输出:

[Hello]
{Hello}
(Hello)

预期输出:

[Hello(Hello]
)
{Hello}

当然{,[(的顺序可能会有所不同,并且无法预测。

2 个答案:

答案 0 :(得分:1)

任何工作都不得征求

synchronized (this) {
    <<job>>
}
<<after>>

任何作业必须在<<job>>之前运行<<after>>

要被多个<<after>>交错(不可能<<job>>),必须至少阻止一个<<after>>,直到后面的其他<<job>><<after>>被阻止为止被执行。使用代码的可能性很小(<<after>>花时间打印一个字符,而<<job>>花一秒钟)。

无论调用方法是多少,多少以及何时使用。

要产生所需的行为,必须在同步代码之后和blocking代码之前添加<<after>>

class Call {
    public Call() {}

    private static void delay(int ms) {
        try {
            Thread.sleep(ms);
        } catch (InterruptedException e) {
            // keep out!
        }
    }

    private void call(char a, String msg, char b) {
        synchronized (this) {
            System.out.print(a);
            System.out.print(msg);
            delay(100);
        }
        delay(ThreadLocalRandom.current().nextInt(10) * 10); // probability
        System.out.println(b);
    }

    void callA(String msg) { call('[', msg, ']'); }
    void callB(String msg) { call('{', msg, '}'); }
    void callC(String msg) { call('(', msg, ')'); }
}

public class Callme {
    static Call call = new Call();
    static List<Consumer<String>> calls = asList(call::callA, call::callB, call::callC);

    static void randomCall() {
        calls.get(ThreadLocalRandom.current().nextInt(calls.size())).accept("Hello!");
    }
    public static void main(String... args) {
        IntStream.range(0, 50).forEach(ignore -> new Thread(Callme::randomCall).start());
    }
}

全无:

(Hello!)
(Hello!)
)
{Hello!{Hello!}
{Hello!}
}
[Hello!(Hello!]
)
(Hello![Hello!)
{Hello!]
(Hello!}
[Hello!)
[Hello!]
]
(Hello![Hello!)
(Hello!]
[Hello!)
...

答案 1 :(得分:0)

我会说预期的输出是

[Hello]
{Hello}
(Hello)
  1. 完整的消息是可以预期的,因为当离开同步块时,代码会继续执行并立即打印结束符。其他线程的运行速度并没有那么快,首先必须对其进行调度,然后获取synchronized块的锁,这些步骤需要时间
  2. Thread.start()启动操作系统级别的线程(https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/java/lang/Thread.java#L673https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/java/lang/Thread.java#L705https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/native/java/lang/Thread.c#L44https://github.com/openjdk-mirror/jdk7u-hotspot/blob/master/src/share/vm/prims/jvm.cpp#L2634https://github.com/openjdk-mirror/jdk7u-hotspot/blob/master/src/share/vm/runtime/thread.cpp#L420,链结尾为取决于系统的os::start_thread(thread);行),因此最终取决于操作系统的是线程运行的速度和顺序,但是通常它们很快就会开始运行,并按照请求启动的顺序开始运行
  3. synchronized使用对象监视器,它们建立了一个正在等待它们的线程的列表(https://github.com/openjdk-mirror/jdk7u-hotspot/blob/master/src/share/vm/runtime/objectMonitor.cpp#L186是文件,并且代码有点过时,但是列表本身是一个链表-好吧,是一个循环的,双向链接的链表-_waitSet,通过从https://github.com/openjdk-mirror/jdk7u-hotspot/blob/master/src/share/vm/runtime/objectMonitor.cpp#L2251开始的添加/出队方法进行管理。因此notify()notifyAll()遍历该列表并以确定的顺序唤醒其他线程。