最近我经历了一个简单的线程程序,这导致我对相关概念的一些问题...我的示例程序代码如下:
class NewThread implements Runnable {
Thread t;
NewThread() {
t = new Thread(this, "Demo Thread");
System.out.println("Child thread: " + t);
t.start(); // Start the thread
}
public void run() {
try {
for (int i = 5; i > 0; i--) {
System.out.println("Child Thread: " + i);
Thread.sleep(500);
}
} catch (InterruptedException e) {
System.out.println("Child interrupted.");
}
System.out.println("Exiting child thread.");
}
}
class ThreadDemo {
public static void main(String args[]) {
new NewThread(); // create a new thread
try {
for (int i = 5; i > 0; i--) {
System.out.println("Main Thread: " + i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
System.out.println("Main thread interrupted.");
}
System.out.println("Main thread exiting.");
}
}
现在这个程序给我输出如下:
Child thread: Thread[Demo Thread,5,main]
Main Thread: 5
Child Thread: 5
Child Thread: 4
Main Thread: 4
Child Thread: 3
Child Thread: 2
Main Thread: 3
Child Thread: 1
Exiting child thread.
Main Thread: 2
Main Thread: 1
Main thread exiting.
所以,这对我来说非常清楚。但是,只要我将对象创建代码(调用NewThread类构造函数)替换为如下所示:
NewThread nt = new NewThread(); // create a new thread
输出变得有点变化,如下所示:
Child thread: Thread[Demo Thread,5,main]
Main Thread: 5
Child Thread: 5
Child Thread: 4
Child Thread: 3
Main Thread: 4
Child Thread: 2
Child Thread: 1
Main Thread: 3
Exiting child thread.
Main Thread: 2
Main Thread: 1
Main thread exiting.
有时候它会在两种情况下给我相同的输出。所以,我没有在这两种情况下得到确切的改变。
我想知道你输出的变化是来了吗?
提前致谢...
答案 0 :(得分:5)
更改的输出是由于OS进程调度和JVM线程调度的性质。即使您取出第二个线程,也无法保证您的线程在500ms后完全唤醒。
答案 1 :(得分:2)
我不确定我是否理解您提及的更改,但调度是非确定性的,即它可能会在不同的运行中以不同方式调度线程申请。
另一件事;在构造函数中创建和启动新线程并不是最佳实践。您是否考虑过让NewThread扩展Thread?像这样:
class NewThread extends Thread {
NewThread(String str) {
super(str);
System.out.println("Child thread: " + this);
}
public void run() {
try {
for (int i = 5; i > 0; i--) {
System.out.println("Child Thread: " + i);
Thread.sleep(500);
}
} catch (InterruptedException e) {
System.out.println("Child interrupted.");
}
System.out.println("Exiting child thread.");
}
}
public class ThreadDemo {
public static void main(String args[]) {
new NewThread("Demo Thread").start();
try {
for (int i = 5; i > 0; i--) {
System.out.println("Main Thread: " + i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
System.out.println("Main thread interrupted.");
}
System.out.println("Main thread exiting.");
}
}
答案 2 :(得分:0)
你有两个线程,一个每半秒做一次,一个每秒做一些事情。
JVM和OS无法保证可用于调度的哪些线程在给定时间运行。或者,如果你有多个核心,那么两个线程可以同时运行,并在System.out上竞争锁定,同时停止两个线程打印 - 如果你一次发送一个字符而不是使用println,两个线程输出中的字符可能会混合在一起。
您的输出显示,在一秒钟和两秒钟内,两个线程中的哪一个打印其输出,这是不可预测的。这是预期的。
在这种情况下,无论是否将NewThread对象分配给局部变量都没有区别。当运行它的线程正在运行时,该对象不符合垃圾收集的条件(假设Threads持有对其runnable的引用),并且没有其他任何东西使用该局部变量。因此,代码中的更改后的差异只是调度中的随机性,而不是更改的影响。
答案 3 :(得分:0)
如上所述,这是正常行为。如果您需要在特定时间和/或固定时间间隔启动某些任务,那么Timer的scheduleAtFixedRate()可能会给您带来更好的结果。
答案 4 :(得分:-1)
两个程序的输出都是正确的吗?是。
答案是输出未定义。您每次获得的特定(正确)输出可能取决于任何事情,包括编译的字节码中的微小变化。 (可能值得用javap -c
检查一下,只是为了确保代码中的差异是可能的原因。)
一般情况下,如果你有两个并行处理的线程,除非你以某种方式同步它们,否则你无法确定它们的组合输出的顺序。