在线程对象上直接调用Runnable的run()方法

6
我们不能直接在线程对象上调用Runnable的run()方法,但是根据下面的程序,我们可以在没有任何编译或运行时错误的情况下这样做。为什么会这样呢?
public class ThreadCheck implements Runnable {

    @Override
    public void run() {
        for (int i=0; i<10; ) {
            System.out.println(++i);
        }
    }

    public static void main(String[] args) {
        Thread mythread = new Thread(new ThreadCheck());
        mythread.run();
        mythread.run();
        mythread.start();
    }   
}

输出结果: 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10

4个回答

9

1
我们可以直接在线程对象上调用Runnable的run()方法。但是,当您从线程对象调用run()方法时,run()方法将作为普通方法工作。当您调用它时,它不会创建新线程。
在这种情况下,run()方法将被视为普通方法调用。但是当您在Thread对象上调用start()方法时,它会自动在JVM中的新线程上调用run()方法。

当您调用t.start()时,它也像普通方法一样工作。每个方法在调用它的线程中运行,并且每个方法都会执行其应该执行的操作。t.start()应该启动一个新线程。那么,r.run()应该做什么呢?别问我!去问写这段代码的人吧! - Solomon Slow
是的,每个方法都在调用它的线程中运行。每个线程都在一个单独的调用堆栈中启动。当从主线程调用run()方法时,run()方法会进入当前调用堆栈,而不是在新调用堆栈的开头。 - Puneet Chawla
您可以直接调用run()方法,但是两个线程之间不会进行上下文切换。例如,您有两个相同类的对象t1和t2,并且我们从这两个对象中都调用run()方法。我们在run()方法中指定Thread.sleep(500)并通过循环打印1到5。输出将是1 2 3 4 5 1 2 3 4 5。因为t1和t2将被视为普通对象而不是线程对象。根据我的理解,上述描述是正确的。如果我错了,请解释一下。 - Puneet Chawla
您的事实没有问题,但是您谈论它们的方式听起来像是神奇的想法。您说:"在这种情况下,run()方法将被视为普通方法调用。" 但这是因为在每种情况下,run()方法都被视为普通方法调用。Java中的所有方法调用都是"正常的"。您说:"…被视为普通对象,而不是线程对象…" 我认为,如果您对堆栈和线程以及方法调用的实际工作原理有更深入的了解,那么线程似乎就不是那么神奇了——一切都是"正常"的。 - Solomon Slow
好的。谢谢 James 大。 - Puneet Chawla

0

创建/生成自定义新线程需要两个步骤:

  • 使用自定义线程的对象引用(在此情况下是 myThread)作为参数创建新的 Thread 对象(称其为 thread)

  • 调用 thread.start();

run() 可以直接调用,但是 run 方法中的执行顺序不会在新线程中发生!而是在主方法的现有线程中发生。


0
我们不能直接在线程对象上调用Runnable的run()方法。
这并不是真的。您的示例证明了您确实可以调用它。但也许它并没有做你想象中的事情。
请参阅调用wait和notify的两个线程,以简单说明Thread类和Runnable接口之间的关系。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接