理解Java中的MultiThreading概念

时间:2010-06-16 07:09:00

标签: java multithreading

最近我经历了一个简单的线程程序,这导致我对相关概念的一些问题...我的示例程序代码如下:

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.

有时候它会在两种情况下给我相同的输出。所以,我没有在这两种情况下得到确切的改变。

我想知道你输出的变化是来了吗?

提前致谢...

5 个答案:

答案 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检查一下,只是为了确保代码中的差异是可能的原因。)

一般情况下,如果你有两个并行处理的线程,除非你以某种方式同步它们,否则你无法确定它们的组合输出的顺序。