【问题标题】:java threads execution orderjava线程执行顺序
【发布时间】:2017-08-17 23:47:33
【问题描述】:
public class SousThread implements Runnable {
    private int i;

    public SousThread() {
        this.i = 0;
    }

    @Override
    public void run() {
        while(true) {
            System.out.println("I'm sousthread " + i++);
            try {
                Thread.sleep(1500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class TestThread implements Runnable {

    @Override
    public void run() {
        System.out.println("I'm thread");
        SousThread st = new SousThread();
        Thread td = new Thread(st);
        td.start();
        System.out.println("thread finished");
    }

    public static void main(String[] args) {
        TestThread tt = new TestThread();
        Thread td = new Thread(tt);
        td.start();
        System.out.println("main finished");
    }
}

我正在尝试在线程 TestThread 中创建线程 SousThreadSousThread 是无限的。

令我惊讶的是,我得到以下结果:

I'm thread
main finished
thread finished
I'm sousthread 0
I'm sousthread 1
I'm sousthread 2
I'm sousthread 3
I'm sousthread 4
I'm sousthread 5
...
...

这是否意味着main 方法已完成而线程尚未完成?这可能吗?这安全吗?如果没有,有什么更好的方法?

更新

因为这样的代码在 C++ 中不起作用。所以我只想知道代码在 Java 中是否没有任何问题或任何风险。

【问题讨论】:

  • 更好的方法来做什么? “这可能吗?”嗯,很明显。 “这里安全吗?”以何种方式安全?
  • @Kayaman main 已经结束,但是属于main 的线程还没有结束。这对你来说不重要吗?
  • 不是特别清楚,但这可能是因为我了解线程在 Java 中的工作原理。
  • @Kayaman 所以我们能不能这样做?
  • 你刚刚做到了,不是吗?

标签: java multithreading


【解决方案1】:

您在代码中所做的解释如下:

  1. main线程首先由JVM发起
  2. TestThreadmain 线程发起
  3. SousThreadTestThread 发起

这是否意味着方法 main 已经完成,而线程 还没完?这可能吗?

是的,每个线程并行运行main 线程首先完成,然后 TestThread 完成,但 SousThread 线程仍在运行(因为无限 while 循环)。

另外,你需要记住的一点是你不能期望&保证哪个线程首先运行&完成(除非你正在运行无限循环),你可以看看here开始并了解有关线程的更多信息。

【讨论】:

    【解决方案2】:

    这是well documented,完全正常:

    当 Java 虚拟机启动时,通常有一个非守护线程(通常调用某个指定类的名为 main 的方法)。 Java 虚拟机继续执行线程,直到发生以下任一情况:

    • 已调用 Runtime 类的退出方法,并且安全管理器已允许执行退出操作。
    • 所有不是守护线程的线程都已经死亡,要么是从对 run 方法的调用返回,要么是抛出一个传播到 run 方法之外的异常。

    在您的情况下,虽然主线程已终止(隐式通过 main() 返回),但其他线程仍然存在。除非你在某处调用 System.exit() 或将其他线程设置为守护线程,否则 JVM 将继续运行,直到所有线程都加入。

    如果你想让所有线程在主线程存在之前终止,你需要Thread.join()他们。请注意,Runtime.exit() 会非常严厉地终止线程。线程是not interrupted nor are their finalizers called,所以这真的不安全。

    【讨论】:

    • 所以我的代码没有任何风险或任何问题(除了 JVM 会处理那个无限线程)?
    • @Yuhui 好吧,SousThread 根本没有可靠的终止方式,所以我不会这么说。但是这个问题不是从main()返回引起的。
    • 重要的是要意识到线程的守护进程状态是从产生它的父进程中获得的。由于 main 是非守护线程,因此 TestThread 线程和 SousThread 线程也是非守护线程。如果您是特定行为,则应在调用 start() 之前使用 thread.setDaemon(...)
    • 不,拥有守护线程是有充分理由的。在这里查看我的答案:*.com/a/10298353/179850
    【解决方案3】:

    是的,这是可能的。如果你想终止你的线程,你应该在线程上调用setDaemon方法。

    【讨论】: