【问题标题】:Why we call Thread.start() method which in turns calls run method?为什么我们调用 Thread.start() 方法,而后者又调用 run 方法?
【发布时间】:2011-11-08 15:06:35
【问题描述】:

为什么我们调用线程对象的start()方法,而后者又调用run()方法,为什么不直接调用run()方法呢?

【问题讨论】:

    标签: java multithreading


    【解决方案1】:

    [...] 为什么不直接调用 run() 方法呢?

    run() 方法只是一个普通方法(被 you 覆盖)。与任何其他普通方法一样,直接调用它会导致当前线程执行run()

    所有的魔法都发生在start() 内部。 start() 方法将导致 JVM 产生一个新线程,并使新产生的线程执行 run()

    【讨论】:

    • 但是start最终在同一个类中调用start0(),start0()是做什么的?
    • 类的契约(在javadoc中描述)说你通过调用公共start方法来获得分叉行为。基本上什么才是最重要的。魔术是直接在start 中发生还是委托给另一个方法取决于API 实现。如果您指的是 OpenJDK 中的 Thread.java,它看起来确实像是委托给了 start0。我敢打赌,这种方法也不包含“魔法”。我敢打赌它委托给一些fork() 系统调用。最后,这取决于操作系统。同样,这是一个 JDK/OS 实现细节。
    【解决方案2】:

    如果你直接调用 run() 方法,它的主体将在当前线程的上下文中执行。当您调用start() 方法时,会创建一个新线程,并在这个新线程中执行run() 方法。

    【讨论】:

      【解决方案3】:

      即使我们没有以编程方式创建任何线程,对于每个应用程序,操作系统都会创建一个默认线程来使用 CPU 执行其代码。

      直接调用run方法会让run方法在OS给定的那个主线程中执行

      但创建线程类的目的是确保 run 方法在不同的线程中执行。除非 OS 的线程管理器创建一个线程,否则您的 run 方法将不会在单独的线程中执行。要请求操作系统创建单独的线程,您必须调用 start() 方法,该方法将向操作系统发送请求以创建线程。一旦 OS 创建了一个线程,那么 OS 将在新创建的线程上下文中自动调用你的线程类的 run 方法。因此,您的目的是创建一个单独的线程并在单独的线程中执行您的 run 方法。

      如果你直接调用run方法,那么就像OS没有为你创建任何线程一样,默认主线程会执行你的run方法。 没有必要为此创建一个单独的线程类!

      希望我清楚。如果您需要更多解释来回答您的问题,请告诉我。

      注意:虽然书上说 JVM 创建线程,但内部 JVM 必须向 OS 层的线程管理器驱动程序发送请求,以在其线程池中创建一个新线程。这就是为什么我在这里比 JVM 更多地使用 OS 术语。

      【讨论】:

      • 这是迄今为止最好的答案!
      【解决方案4】:

      我们为什么要调用线程对象的 start() 方法,而后者又会调用 run() 方法

      不,它没有。 start() 调用操作系统,它启动一个新线程,(为了大大简化)调用run() 方法。同时start() 方法已经返回给它的调用者。它们不是等价的。

      【讨论】:

      • 这是最好的答案。 :)
      【解决方案5】:

      Runnable 只是一个接口。实现Runnable 的类没有什么特别之处,它只是有一个run 方法。

      Thread#start 是本机实现的方法,它创建一个单独的线程并调用Threadrun 方法,在新线程中执行代码。

      Thread 实现Runnablerun 的代码如下所示:

      @Override
      public void run() {
          if (target != null) {
              target.run();
          }
      }
      

      如果Thread 实例是通过将Runnable 传递给Thread 的构造函数来创建的,则将调用Runnablerun 方法。

      否则,扩展Thread 的类必须重写run 方法才能使start 工作。

      Thread 上调用run 不会创建新线程。

      【讨论】:

        【解决方案6】:

        如果线程已被实例化但尚未启动,则称其处于新状态
        除非在线程实例上调用 start() 方法,否则不会说它是存活的。
        如果你不在新创建的线程实例上调用 start() 方法,则不考虑线程
        如果 start() 方法没有被调用,而 run() 方法是直接在 Thread 实例上调用的,那么 run() 方法内的代码将不会在单独的新线程中运行,而是它将开始在现有线程中运行

        在示例中查看问题

        class Multi extends Thread{  
         public void run(){  
          for(int i=1;i<5;i++){  
            try{Thread.sleep(500);}catch(InterruptedException e){System.out.println(e);}  
            System.out.println(i);  
          }  
         }  
         public static void main(String args[]){  
          Multi t1=new Multi();  
          Multi t2=new Multi();  
        
          t1.run();  
          t2.run();  
         }  
        }  
        
        Output:1
               2
               3
               4
               5
               1
               2
               3
               4
               5
        

        正如您在上面的程序中看到的那样,没有上下文切换,因为这里 t1 和 t2 将被视为普通对象而不是线程对象。

        【讨论】:

          【解决方案7】:

          这是由于Java中的多线程设计。

          调用start ()会启动一个新线程,调用run()方法不会启动一个新线程。

          如果您在 Thread 上调用 start() 方法,Java 虚拟机将调用 run() 方法,两个线程现在将同时运行 - 当前线程和其他线程或 Runnable 实现。

          查看Thread classstart()方法的源代码

           /**
               * Causes this thread to begin execution; the Java Virtual Machine
               * calls the <code>run</code> method of this thread.
               * <p>
               * The result is that two threads are running concurrently: the
               * current thread (which returns from the call to the
               * <code>start</code> method) and the other thread (which executes its
               * <code>run</code> method).
               * <p>
               * It is never legal to start a thread more than once.
               * In particular, a thread may not be restarted once it has completed
               * execution.
               *
               * @exception  IllegalThreadStateException  if the thread was already
               *               started.
               * @see        #run()
               * @see        #stop()
               */
              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();
          

          在上面的代码中,您看不到对run() 方法的调用。

          private native void start0()负责调用run()方法。 JVM创建对应java线程的native线程并调用run()方法。

          native方法的源码参考这个问题:

          Where to find source code for java.lang native methods?

          【讨论】:

          • 不要对非代码文本使用代码格式。
          【解决方案8】:

          当我们使用 start 方法时,会创建一个新线程,然后会为每个新线程执行 run 方法中的代码。

          使用start方法为每个线程创建两个栈,栈和原生栈。

          但是Run方法调用只是executerun方法内部的代码顺序作为run方法调用不会创建不同的堆栈。

          例子

          import java.util.concurrent.TimeUnit;
          
          public class thread implements Runnable{
          
              /**
               * @param args
               */
              public static void main(String[] args) {
                  Thread gg=new Thread(new thread());
                  Thread gg1=new Thread(new thread());
                  gg.run();
                  gg1.start();
                  /*gg.start();
                  gg1.start();*/
          
              }
          
              @Override
              public void run() {
                  for(int i=0;i<5;i++)
                  {
                      try {
                          TimeUnit.SECONDS.sleep(2);
                      } catch (InterruptedException e) {
                          // TODO Auto-generated catch block
                          e.printStackTrace();
                      }
                  System.out.println("Hello..." + i);
                  }
          
              }
          
          }
          

          【讨论】:

            【解决方案9】:

            我想你是在谈论启动一个线程。如果是这种情况,您不直接调用 run 方法的原因是您将调用该方法,而不是启动线程。

            【讨论】:

              【解决方案10】:

              如果我们愿意,我们可以调用run() 方法,但是如果我们调用run 方法,它将像普通的Java 方法一样运行。而我们称之为start() 它,JVM 会创建一个新线程并在该线程上执行 run 方法。

              【讨论】:

                【解决方案11】:

                不同的是,如果我们通过start()方法执行run方法,它会创建一个新线程,我们可以在其中执行run方法,否则run()方法将在JVM创建的线程中执行public static void main()方法。这正是多线程的重点,在新线程上运行不同的操作。

                【讨论】:

                  【解决方案12】:

                  start()run() 方法用于运行一个线程。run() 方法只是一个普通方法,它被用户重写,它将在当前线程上调用。 start() 方法间接运行run() 方法并创建一个新线程。

                  【讨论】:

                    猜你喜欢
                    • 2017-01-19
                    • 1970-01-01
                    • 2013-03-31
                    • 1970-01-01
                    • 2022-09-26
                    • 1970-01-01
                    • 1970-01-01
                    • 2020-11-29
                    • 1970-01-01
                    相关资源
                    最近更新 更多