简体   繁体   English

了解Java中的多线程概念

[英]Understand the concept of MultiThreading in Java

Recently I have gone through with one simple threading program, which leads me some issues for the related concepts... My sample program code looks like : 最近,我完成了一个简单的线程程序,这给我带来了相关概念的一些问题...我的示例程序代码如下:

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.");
    }
}

Now this program giving me the output as follows : 现在这个程序给我的输出如下:

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.

So, that's very much clear to me. 所以,这对我来说非常清楚。 But as soon as I am replacing the object creation code (calling of a NewThread class constructor) to as follows : 但是,一旦我将对象创建代码(调用NewThread类构造函数)替换如下:

NewThread nt = new NewThread(); // create a new thread

the output becomes a bit varied like as follows : 输出变得有些变化,如下所示:

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.

And some times it's giving me same output in both the cases. 有时在两种情况下它都给我相同的输出。 So, i am not getting the exact change in both the scenario. 因此,在两种情况下我都没有得到确切的改变。

I would like to know that you the variation in the output is coming here ? 我想知道您输出的变化即将到来吗?

Thanks in advance... 提前致谢...

The changed output is due to nature of both OS process scheduling and JVM thread scheduling. 更改的输出归因于OS进程调度和JVM线程调度的性质。 Even if you take out the second thread there is no guarantee that your thread will wake-up exactly after 500ms. 即使您取出第二个线程,也无法保证您的线程会在500ms之后准确唤醒。

I'm not sure I understand the change that you mention, but the scheduling is non-deterministic , ie, it may schedule the threads differently in different runs of the application. 我不确定我是否理解您提到的更改 ,但是调度是不确定的 ,即它可能在应用程序的不同运行中对线程进行不同的调度。

Another thing; 另一件事; creating and starting a new thread in the constructor isn't really best practice. 在构造函数中创建和启动新线程并不是真正的最佳实践。 Have you considered letting NewThread extend Thread? 您是否考虑过让NewThread扩展Thread? Like this: 像这样:

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.");
    }
}

You have two threads, one which does something about every half second, one which does something about every second. 您有两个线程,一个线程每半秒钟执行一次操作,一个线程每秒钟执行一次操作。

The JVM and OS makes no guarantee which of the threads available for scheduling gets run at a given time. JVM和OS无法保证在给定的时间运行哪些可用于调度的线程。 Alternatively, if you have multiple cores then both threads could be running at the same time, and competing for a lock on the System.out that stops two threads printing at the same time - if you send the output one character at a time instead of using println, then the characters from both thread's output might be mixed together. 或者,如果您有多个内核,则两个线程可以同时运行,并争夺对System.out的锁定,该锁定将停止同时打印两个线程-如果您一次发送一个字符而不是发送输出,使用println,则来自两个线程输出的字符可能会混合在一起。

Your output shows that at one second and at two seconds, which of the two threads prints its output it is not predictable. 您的输出显示,在一秒钟和两秒钟时,两个线程中的哪一个打印其输出是不可预测的。 This is as expected. 这是预期的。

It makes no difference in this case whether or not you assign the NewThread object to a local variable. 在这种情况下,是否将NewThread对象分配给局部变量都没有区别。 The object is not eligible for garbage collection while the thread it is running in is running (assuming Threads hold a reference to their runnable), and nothing else uses the local variable. 在运行对象的线程正在运行时,该对象不符合垃圾回收的条件(假设线程持有对其可运行对象的引用),并且其他任何对象都不使用局部变量。 So the difference after that change in the code is just the randomness in the scheduling, not the effect of the change. 因此,代码更改之后的差异只是调度中的随机性,而不是更改的效果。

As mentioned above, this is normal behaviour. 如上所述,这是正常行为。 If you need some tasks started at a specific time and/or at a fixed interval, then the Timer 's scheduleAtFixedRate() may give you a better result. 如果您需要在特定时间和/或以固定间隔启动某些任务,则Timer的scheduleAtFixedRate()可能会给您带来更好的结果。

Are both outputs correct for both programs? 两个程序的输出都正确吗? Yes. 是。

The answer is the output is undefined. 答案是输出未定义。 The particular (correct) output you get each time could depend on just about anything, including minor variations in the compiled bytecode. 您每次获得的特定(正确)输出可能几乎取决于任何东西,包括编译后的字节码中的微小变化。 (It might be worth checking this with javap -c , just to be sure the difference in code is a possible cause.) (可能需要使用javap -c进行检查,以确保代码中的差异是可能的原因。)

In general if you have two threads doing things in parallel, you can't be sure of the ordering of their combined output unless you synchronise them somehow. 通常,如果有两个线程并行处理事务,则除非确定以某种方式同步它们,否则不能确定它们的组合输出的顺序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM