-3

当我尝试多次执行以下多线程代码时,输​​出与前一个不同。是因为 JVM 行为还是可能是其他原因。请帮我一个。

program:


package example.thread.com;

class MyThread1 implements Runnable {
    Thread t;

    MyThread1(String s) {
        t = new Thread(this, s);
        t.start();
    }

    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("Thread Name  :"
                    + Thread.currentThread().getName());
            try {
                Thread.sleep(2000);
            } catch (Exception e) {
            }
        }
    }
}


public class RunnableThread1 {
    public static void main(String args[]) {
        System.out.println("Thread Name :" + Thread.currentThread().getName());
        MyThread1 m1 = new MyThread1("My Thread 1");
        MyThread1 m2 = new MyThread1("My Thread 2");
    }
}

输出:如果我第一次运行

Thread Name :main
Thread Name  :My Thread 1
Thread Name  :My Thread 2
Thread Name  :My Thread 1
Thread Name  :My Thread 2
Thread Name  :My Thread 2
Thread Name  :My Thread 1
Thread Name  :My Thread 1
Thread Name  :My Thread 2
Thread Name  :My Thread 1
Thread Name  :My Thread 2

输出:如果我第二次运行

Thread Name :main
Thread Name  :My Thread 2
Thread Name  :My Thread 1
Thread Name  :My Thread 2
Thread Name  :My Thread 1
Thread Name  :My Thread 2
Thread Name  :My Thread 1
Thread Name  :My Thread 1
Thread Name  :My Thread 2
Thread Name  :My Thread 1
Thread Name  :My Thread 2

输出:如果我第三次运行

Thread Name :main
Thread Name  :My Thread 1
Thread Name  :My Thread 2
Thread Name  :My Thread 2
Thread Name  :My Thread 1
Thread Name  :My Thread 1
Thread Name  :My Thread 2
Thread Name  :My Thread 2
Thread Name  :My Thread 1
Thread Name  :My Thread 2
Thread Name  :My Thread 1

像这样请建议.....

4

6 回答 6

3

这正是示例的重点。它表明线程是随心所欲地安排的,并且不能保证输出按顺序发生。

在其他编程语言和系统中,期望输出错误并非不合理,例如:

Thread Name :main
Thread Name  :My Thread 1
Thread NThread Name  :My Thread 2ame  :My Thread 2
Thread Name  :My Thread 1
Thread Name  :My Thread 2
Thread Name  :My Thread 1
ThreaThread Name  :My d Name  :My ThrThread 2ead 1
Thread Name  :My Thread 2
Thread Name  :My Thread 1
于 2013-02-06T11:42:22.837 回答
1

您有两个并行运行的线程并多次打印它们的名称。根据许多因素,线程 1 可能首先启动,也可能是线程 2。这或多或少是随机的。

然后睡眠没有非常精确的分辨率,因此一个线程可能会休眠 2001 毫秒,而另一个线程可能会休眠 1999 毫秒——这又是相当随机的。

注意:您不应该从构造函数启动线程,最好执行以下操作:

MyThread1 m1 = new MyThread1("My Thread 1");
new Thrad(m1).start();

并从 MyThread1 中删除对线程的所有引用 - 您可以顺便重命名 MyRunnable1 以保持一致。

于 2013-02-06T11:41:20.763 回答
0

我认为您应该阅读 JAVA 的多线程和并发概念。首先阅读概念然后动手使用代码始终是一个好习惯

于 2013-02-06T11:43:58.497 回答
0

那是因为 JVM 行为...

是的。Java 线程(以及其他语言中的线程)的许多方面都是不确定的。也就是说,它们无法预测,并且根据您无法控制的因素在一次运行中有所不同。

因此,当您编写多线程应用程序时,您需要确保它的正确性不依赖于这些非确定性点之一。

在这种情况下,非确定性源于许多来源。例如:

  • 当您调用thread.start()时,未指定在调用返回之前是否thread实际开始执行指令。

  • 当您调用thread.sleep(2000)时,线程休眠的实际时间长度至少为 2000 毫秒。

  • 当有许多活动线程可以运行时,您无法预测哪些(甚至有多少)运行。它取决于操作系统级别的线程调度程序。

于 2013-02-06T12:01:52.950 回答
0

您在 MyThread1 中的 run() 方法同时在 2 个不同的线程中运行。每个线程计数为 5,每次计数打印其名称。写入输出的操作是原子的,这意味着一次只有一个线程可以进行写入。因此,当线程准备好写入但另一个线程首先到达那里时,它必须等到另一个线程完成写入才能开始写入。没有办法知道哪个线程会先到达那里,所以每次都不同。

想象一下,有 2 个人被要求在一张纸上写下他们的名字 5 次。只有一张纸,他们必须分享。为了写下他们的名字,他们首先得到了那张纸。如果其他人有它,他们会等待。当他们写完他们的名字后,他们放开了那张纸。当两个人都准备好再次写下他们的名字并且没有人有纸时,谁先得到它是随机的机会。

所以每次结果都不一样...

于 2013-02-06T12:04:23.993 回答
0

您看到的效果只是 JVM 行为的部分结果。JVM 只是创建线程并启动它们。操作系统负责决定哪个线程何时在哪个处理器上运行。您的线程不仅会相互竞争处理器的使用,还会与您的计算机正在执行的所有工作竞争。

当一个线程休眠时,它不再是一个可以使用处理器的可运行线程。当它到达睡眠时间结束时,它又回到可运行状态,并争夺处理器的使用。在那之后的某个时间,操作系统会选择它作为线程在处理器上运行,它会继续计算。它保持处理器直到它终止、休眠、必须等待其他东西,或者操作系统决定轮到另一个线程了。

没有理由期望两个线程之间的顺序从运行到运行是相同的。编写能够提供一致结果的多线程程序需要一些努力。

我建议从一些关于多线程编程的基本教程开始。当您准备好更深入地了解该主题时,我推荐Java Concurrency in Practice

于 2013-02-06T12:26:16.600 回答