为啥不能直接调用run()方法呢?

Posted

技术标签:

【中文标题】为啥不能直接调用run()方法呢?【英文标题】:Why can't we directly call the run() method?为什么不能直接调用run()方法呢? 【发布时间】:2011-01-28 16:01:16 【问题描述】:

如果一个线程的start()方法在内部调用了run()方法,那为什么不在我们的代码中直接调用run()方法呢?这样做会涉及哪些问题?

【问题讨论】:

***.com/questions/262816/… 这是一个非常基本的问题,可以通过非常基本的互联网搜索来回答...@birryree:这是一个非常不同的问题。 没关系,HB。如果它与编程相关并且之前没有被 here 询问过,那么它属于这里。这样,与编程相关的内容的互联网搜索将被定向到此处,而不是那些狡猾的 AskJeeves/ExpertSexChange 网站。 @H.B. - 我链接的问题不同,但答案提供了对start()run() 之间差异的相同见解,就像在这个答案中一样:***.com/questions/262816/… @paxdiablo:猜猜这是一个公平的观点。 @birryree:你再次链接到这个问题,但我明白你的意思,还有其他几个问题也有答案可以回答这个问题。 【参考方案1】:

start 方法确保代码在新的线程上下文中运行。如果你直接调用run,那么它就像一个普通的方法调用,它会在当前线程的上下文中运行,而不是在新的线程中。 start 方法包含触发新线程的特殊代码; run 显然没有这种能力,因为在你编写run 方法时没有包含它。

【讨论】:

对不起,我看不懂最后一行的意思。我在写 run 方法的时候没有在哪里包含它? @Newcomer,你没有在任何地方包含它——这就是重点。 你不是编写代码让事情在新线程中运行的人。这就是Thread 类的工作,它的JVM 本机代码可以直接处理线程并与底层操作系统交互。由于you 没有在run 中编写特殊代码,因此很明显your 代码不会执行任何这些特殊操作。 start 方法实现了这一点。它会为您拨打run;您只需要担心线程在 JVM 开始为您运行它之后应该做什么。【参考方案2】:

当我们在线程对象上调用 start() 方法时,start() 方法通过为该线程创建一个新的调用堆栈来启动一个新的执行线程。 start() 使该线程开始执行,Java虚拟机调用该线程的 run() 方法。 如果我们调用 run() 而不是 start() 会怎样:

虽然这是合法的,但是 run() 方法会进入当前调用堆栈,而不是创建一个新的调用堆栈。

例如,如果当前正在执行的方法是 main,那么创建的调用堆栈是:

class MyThread extends Thread
 
    public void run()
     
    System.out.println("running");
     
 
public class ThreadDemo 
 
 public static void main (String[] args ) 
   
    MyThread thread=new MyThread();
    thread.start();       
   
  

新线程的调用栈(start() 方法创建了一个新的调用栈) 调用堆栈 - 主线程

class MyThread extends Thread
  
    public void run()
    
    System.out.println("running");
    
 
 public class ThreadDemo 
 
   public static void main (String[] args ) 
    
    MyThread thread=new MyThread();
    thread.run();     
    

run() 方法不会为线程创建新的调用堆栈。 run() 方法进入当前调用栈

【讨论】:

【参考方案3】:

调用run同步执行代码;而允许 JVM 通过start 调用run 将允许代码异步执行。

直接调用run 在可能希望避免线程的测试情况下通常是有益的。

【讨论】:

【参考方案4】:

因为start() 会将其作为一个单独的线程来执行。如果你只是调用run(),那将是你的线程的一部分(即一个函数调用)。

而且,鉴于您的线程可能是一个等待工作的无限循环,这将是一件坏事。

【讨论】:

【参考方案5】:
class A implements Runnable

    public void run()
    
        for( int i=0; i<5; i++)
        
            System.out.println("Thread-A " +i + " Thread Name: "  +Thread.currentThread().getName());
        
    

class B implements Runnable

    public void run()
    
        for( int i=0; i<5; i++)
        

            System.out.println("Thread-B " +i + " Thread Name: "  +Thread.currentThread().getName() );
        
    


class MyThread 

    public static void main(String [] args)
    
        Thread t1 = new Thread(new A());
        Thread t2 = new Thread(new B());

        t1.run();
        t2.run();
        System.out.println("**********************************************************");
        t1.start();
        t2.start();
    

复制并粘贴上面的代码...然后运行它,然后查看输出的差异..

基本上 run() 只会在当前线程的上下文中执行它的主体(这里是主要的) 但, start() 调用操作系统来创建一个新线程。 start() 将在新创建的线程的上下文中调用 run() 方法。

【讨论】:

漂亮而简单的例子。【参考方案6】:

直接调用 run 方法将在主线程中运行该代码。 那么就好像你的程序只有一个线程(即操作系统给出的主线程)。

如果你调用 start 方法,它将调用驱动层线程管理器为你创建一个线程,然后你的 run 函数将被调用。因此,您的 run 方法将在单独的线程中执行。不在主线程中。

【讨论】:

【参考方案7】:

线程背后的想法是在每次新线程开始运行时创建新堆栈。

从主线程调用 run() 方法,run() 方法进入当前调用堆栈而不是新调用堆栈的开头。

直接调用run()方法的问题举例:

class TestCallRun2 extends Thread  
 public void run()  
  for(int i=1;i<5;i++)  
    tryThread.sleep(500);catch(InterruptedException e)System.out.println(e);  
    System.out.print(i+" ");  
    
   
 public static void main(String args[])  
  TestCallRun2 t1=new TestCallRun2();  
  TestCallRun2 t2=new TestCallRun2();  

  t1.run();  
  t2.run();  
   

输出:

1 2 3 4 5 1 2 3 4 5

【讨论】:

【参考方案8】:

虽然直接调用run()是合法的,但是会破坏多线程的目的。线程通过拥有自己的调用堆栈独立工作,如果我们不使用start() 方法,那么该语句的执行堆栈将是该语句正在运行的当前堆栈(在大多数情况下为main() 方法)。这将破坏在我们的 main() 方法或换句话说主堆栈运行时同时运行作业的目的。

【讨论】:

以上是关于为啥不能直接调用run()方法呢?的主要内容,如果未能解决你的问题,请参考以下文章

为什么我们调用 start()方法时会执行 run()方法,为什么 我们不能直接调用 run()方法?

为什么我们调用start()方法时会执行run()方法,为什么我们不能直接调用run()方法?

为什么我们调用start()方法时会执行run()方法,为什么我们不能直接调用run()方法?

在JAVA中,子类继承父类,父类可以调用子类继承父类的方法,父类为啥不能调用子类自己定义的方法呢

子类为啥不能直接调用父类的属性

为啥我不能“直接”从 HTML 调用 Servlet? [复制]