什么时候调用Java的thread.run()而不是thread.start()?


109

什么时候用Java thread.run()代替thread.start()


47
当我是thread.start()方法时?:)
比尔蜥蜴,

3
@blank,答案很简单:t.run()t在当前线程上运行的任务,以及t.start()t在线程t本身上运行的任务时。还是您要询问实际用例?
Pacerier 2014年

2
当您是个白痴,并且想花一个小时调试多线程代码时,才意识到以后您应该已经调用过start()!像我一样...此方法不应公开!
皮埃尔·亨利

Answers:



95

决不。就像常规方法调用一样,直接调用run()只是在同一线程中同步执行代码。


25
“从不”有点太绝对了。也许不总是想要一个新线程,仍然执行代码?
Tomalak

4
也许可以,但是在那种情况下,仅调用run()方法创建新的Thread会不必要地浪费。最好创建一个Runnable impl并在线程中运行或构造并使用它启动一个新线程。
Scott Bale,

1
只是回顾一下……如果永远不会,为什么这种方法是公开的?
空白

4
这是公开的,因为Thread实现了Runnable。您可以继承Thread的子类,并覆盖run(),其效果与将代码放入Runnable并将其传递给Thread构造函数具有相同的效果。但是,最好使用单独的Runnable对象,因为这样可以给您带来更大的灵活性(例如,将其传递给Executor等)。
亚当·克鲁姆,

2
让我举一个当前正在使用的具体示例:我有一个可以作为GUI或从命令行运行的程序。在GUI情况下,我希望执行繁重工作的对象在单独的线程上运行并将更新发送到gui。在命令行模式下,我不需要那个单独的线程。
Edward Falk

27

取自代码样式Java线程常见问题解答

问:线程的start()和run()方法有什么区别?

答:Thread类中单独的start()和run()方法提供了两种创建线程程序的方法。start()方法开始执行新线程并调用run()方法。start()方法立即返回,并且新线程通常继续运行,直到run()方法返回。

Thread类的run()方法不执行任何操作,因此子类应使用在第二个线程中执行的代码覆盖该方法。如果使用Runnable参数实例化Thread,则该线程的run()方法将在新线程中执行Runnable对象的run()方法。

根据线程程序的性质,直接调用Thread run()方法可以提供与通过start()方法进行调用相同的输出,但是在后一种情况下,代码实际上是在新线程中执行的。


thread's run() method executes the run() method of the Runnable object in the new thread instead.这是不正确的(或者至少我的Java 8源代码另有说明),但是不幸的是链接似乎断开了,所以我在这里报告了错误。
kajacx

1
@Tomalak,这不能回答所问的问题。问题不是要问有什么区别,而是要问用例,我们将用它们thread.run()代替thread.start()
Pacerier 2014年

24

执行thread.run()不会创建Thread执行代码的新方法。它只是在当前线程中执行代码,从中thread.run()调用代码。

执行将thread.start()创建一个新的OS级别线程,其中run()将调用该方法。

在本质上:

单线程编程→直接调用run()方法

多线程编程→调用start()方法

此外,正如其他人提到的那样,“测试”似乎是唯一可以run()直接从代码中调用的情况。


13

这已经暗示过了,但要明确一点:创建一个仅用于调用它的run()方法的新Thread对象不必要地昂贵,并且应该是一个主要的危险信号。创建一个Runnable impl是一个更好,更分离的设计,并且(a)如果这是所需的行为,则直接调用它的 run()方法,或者(b)使用该Runnable构造一个新的Thread并启动Thread。

更好的是,要进行更多的去耦,请查看ExecutorJDK 5和更高版本中的接口和框架。这使您,简单地说,解耦任务执行(Runnable的实例)从如何执行它(的Executor实现,这可能会在当前线程从池中执行的Runnable,在一个新的线程,使用现有的线程,等等)。


9

呼叫thread.start(),它将依次呼叫thread.run()。想不到您想绕过thread.start()而直接进入的情况thread.run()


3
在测试期间,是我能想到的唯一合法的情况。否则,run()的内容应该在单独的方法中,该方法可以通过run或其他方式进行调用。
比尔蜥蜴

9

单独start()run()在Thread类方法提供了两种方法来创建线程程序。该start()方法开始执行新线程并调用该run()方法。该start()方法将立即返回,并且新线程通常会继续运行,直到该run()方法返回为止。

Thread类的run()方法不执行任何操作,因此子类应使用在第二个线程中执行的代码覆盖该方法。如果使用Runnable参数实例化了Thread,则该线程的run()方法将run()在新线程中执行Runnable对象的方法。

根据线程程序的性质,run()直接调用Thread 方法可以提供与通过start()方法调用相同的输出,但是在后一种情况下,代码实际上是在新线程中执行的。

参考


与Tomalak答案相同!如果您从某个地方引用过,请提及!
巴里

The start() method returns immediately and the new thread normally continues until the run() method returns.如果start()立即返回怎么来的run()继续运行,因为它是从称呼自己start()
克伦民族联盟

7

如果问题是-“为什么调用线程启动方法而不是直接运行方法”,那么我已经用下面的示例代码回答了。希望能澄清。在下面的示例中:

/*
By calling t1.start(), 
we are getting the main calling thread returned immediately 
after the t1.start() called and is ready to proceed for other 
operations.And the thread t1 starts executing the run method of the object r. 
Hence the the output will be:

      I am the main thread , i created thread t1 and had it execute run method, which is currently looping from 0 to 1000000

      I am done executing run method of testThread

*/


/* If we call t1.run() instead of t1.start(), (just replace t1.start() with t1.run() in the code for testing)
 its like a regular method call and the main thread will not return until the run method completes, 
 hence the output will be:

         I am done executing run method of testThread

         I am the main thread , i created thread t1 and had it execute run method, which is currently looping for i to 1000000

*/


class testThread implements Runnable{

 public void run()
 {
     for(int i=0;i<1000000;i++){} //a simple delay block to clarify.

     System.out.println("I am done executing run method of testThread");

 }  
}

public class mainClass{

   public static void main(String [] args)
    {
          testThread r = new testThread();
          Thread t1 = new Thread(r);
          t1.start();  /* Question is: can we call instead t1.run() */  
          System.out.println("I am the main thread , i created thread t1 and had it execute run method, which is currently looping for i to 1000000");

    }
}

5

当您希望它同步运行时。调用run方法实际上不会为您提供多线程。start方法创建一个新线程,该线程调用run方法。


3

如果要像其他任何方法一样执行run()的内容。当然,不启动线程。


3

假设您知道启动和运行方法的用法,即同步与异步;run方法只能用于测试功能。

加上在某些情况下,可以通过在两个不同的对象中调用一个人的run方法和另一个人的start方法来在具有同步和异步功能要求的两个不同的地方使用同一线程类。


2

至少在JVM 1.6中,有一些检查和运行是本地调用的:

 public synchronized void start() {
        /**
     * This method is not invoked for the main method thread or "system"
     * group threads created/set up by the VM. Any new functionality added 
     * to this method in the future may have to also be added to the VM.
     *
     * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
        group.add(this);
        start0();
        if (stopBeforeStart) {
        stop0(throwableFromStop);
    }
    }

    private native void start0();

2

只是上述注释的注释:有时您编写了一个多线程代码,该代码使用“开始”方法运行不同的线程。如果使用“运行”(而不是“启动”)进行调试,则会发现它容易得多,因为它可以使代码同步运行,并使调试更加容易。


-1
public class TestClass implements Runnable {
    public static void main(String[] args) {
        TestClass tc = new TestClass();

        Thread t1 = new Thread(tc);
        System.out.println("Before Starting Thread " + Thread.currentThread().hashCode());
        t1.start();
        System.out.println("After Starting Thread " + Thread.currentThread().hashCode());
    }

    @Override
    public void run() {
        System.out.println("TestClass Run method is  Running with thread " + Thread.currentThread().hashCode());        
    }
}

嗨,Frnz,请签出并运行上面的示例,以清楚地理解第一次使用t1.start()运行并查看哈希码,以及下次使用t1.run()和chk哈希码运行
Avatar Girase 2015年

你的问题在哪里?
阿门·吉利
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.