为什么java线程在独立代码之后执行?

Why does java Thread execute after the independent code?

我是 java 的新手,正在学习多线程。我写了下面的代码。

class BackgroundTask implements Runnable {
    private int counter = 0;

    public int getCounter() {
        return counter;
    }

    public void setCounter(int counter) {
        this.counter = counter;
    }

    @Override
    public void run() {
        System.out.println("Thread started");
        while (true) {
            this.setCounter(this.getCounter() + 1);
        }
    }

}

public class Main {

    public static void main(String[] args) {

        BackgroundTask bgTask = new BackgroundTask();

        Thread bgCount = new Thread(bgTask);

        try {
            
            bgCount.start();
            System.out.println("counter in background is running");
            
            bgCount.interrupt();
            System.out.println(bgTask.getCounter());

        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

    }
}

代码输出:

counter in background is running
0
Thread started

Q.1 为什么bgCount.start()写在打印语句之前,却在它之后执行?

Q.2 为什么调用getCounter()方法后线程启动了?

编辑:感谢大家的精彩回答,现在我明白了线程的概念。

当你在两个不同的线程中做事时,除非你强制某种同步,否则它们是不同步的。一个线程可能首先执行,或者另一个线程可能或它们可能以不可预测的方式交错。这就是线程的意义所在。

说明

Q.1 why is bgCount.start() executing after the print statement when it is written before it?

不是,这是一个错误的结论。 start() 恰好在您编写时执行。它并不一定意味着线程立即启动。 OS 调度程序确定何时启动线程。您得到的唯一保证是它将 最终 开始,所以也许现在,也许一小时后,也许明年。显然,在实践中,它通常几乎是即时的。但这并不意味着它会作为下一件事执行。

Q.2 Why did the thread start after calling the getCounter() method? As explained before, the OS scheduler decides. You just had bad luck. Seriously, you have no control over this and should not do any assumptions on this.


多线程

如果您有多个线程并且它们有一系列操作要执行,OS 调度程序完全可以自由决定如何交错操作。这也意味着不交错任何东西也是有效的。

让我们看一个示例,线程 AB 每个都有 2 个操作要执行。以下执行顺序都是调度程序的有效结果:

A.1
A.2
B.1
B.2

A.1
B.1
A.2
B.2

A.1
B.1
B.2
A.2

B.1
B.2
A.1
A.2

B.1
A.1
B.2
A.2

B.1
A.1
A.2
B.2

所以你不能对什么时候一个线程开始做任何假设,尤其是不要对order操作执行关于其他线程。它可能是完全交错的,可能是顺序的,可能是部分交错的,一切都可能发生。

如果您想控制机制,正确的工具是同步。有了它,您就可以知道在继续之前,您想要等待某个事情首先在另一个线程中发生。上述代码的一个非常简单的示例是等到 bgCount 完成后再继续打印计数。您可以使用 join():

bgCount.start();
System.out.println("counter in background is running");
        
bgCount.join(); // waiting until down
System.out.println(bgTask.getCounter());

但是,如果你那样做,你首先违背了拥有线程的目的。如果您完全阻塞另一个线程并等待,那么计算 并行 的东西没有任何好处。然后它基本上就像以普通的顺序方式执行某些东西。