Thread start()和Runnable run()有什么区别


224

假设我们有以下两个Runnable:

class R1 implements Runnable {
    public void run() {  }
    
}

class R2 implements Runnable {
    public void run() {  }
    
}

那么这有什么区别:

public static void main() {
    R1 r1 = new R1();
    R2 r2 = new R2();

    r1.run();
    r2.run();
}

还有这个:

public static void main() {
    R1 r1 = new R1();
    R2 r2 = new R2();
    Thread t1 = new Thread(r1);
    Thread t2 = new Thread(r2);

    t1.start();
    t2.start();
}

Answers:


309

第一个示例:没有多个线程。两者都在单个(现有)线程中执行。没有线程创建。

R1 r1 = new R1();
R2 r2 = new R2();

r1r2只是实现Runnable接口并因此实现run()方法的类的两个不同对象。调用时,r1.run()您正在当前线程中执行它。

第二个示例:两个单独的线程。

Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);

t1并且t2是类的对象Thread。当您调用时t1.start(),它将启动一个新线程并在内部调用该run()方法r1以在该新线程中执行该方法。


5
我可以考虑一下,在调用Thread#start()之前,没有真正相对于os线程发生的事情吗?它只是一个Java对象。
Jaskey 2014年

4
根据文档,这是正确的。检查符合文档的线程对象初始化代码。同样在源代码中,它是start(),它正在调用natvie方法,该方法必须使os线程相关的事情发生。
Bhesh Gurung

3
线程构造器文档在这里。线程对象的初始化源在这里start()方法源在这里
Bhesh Gurung

92

如果您只是run()直接调用,它将像其他方法调用一样在调用线程上执行。Thread.start()需要实际创建一个新线程,以便run并行运行runnable的方法。


2
在Hotspot JVM中,java线程和本机线程之间存在直接映射。Thread.start()从化妆调用线程状态移动新的状态可运行状态。可运行并不意味着线程正在运行。初始化本机线程后,本机线程将调用run()Java线程中的方法,这会使线程状态从Runnable更改为Running。当线程终止时,将释放本机线程和Java线程的所有资源。
overexchange's

@overexchange在哪里可以找到有关状态更改的材料。
twlkyao

73

区别在于Thread.start()启动一个线程调用该run()方法,而Runnable.run()run()在当前线程上调用该方法。


35

区别是,当程序调用start()方法,一个新的被创建的线程和代码中run()被执行的新的,而如果你调用线程run()方法直接没有新的线程将被创建和代码里面run()将在当前线程直接执行。

与Java线程之间的另一个区别是您不能调用两次。一旦开始,第二次调用将抛出Java,而您可以多次调用方法,因为它只是一个普通方法。start()run()start()start()IllegalStateExceptionrun()


21

实际上Thread.start()创建一个新线程并具有自己的执行方案。

Thread.start()run()异步调用该方法,该方法将新Thread的状态更改为Runnable。

但是Thread.run()不会创建任何新线程。相反,它在当前正在运行的线程中同步执行run方法。

如果您正在使用,Thread.run()则根本不使用多线程功能。



7

如果run()使用main方法,则main方法的线程将调用该run方法,而不是您需要运行的线程。

start()方法创建新线程,并且必须为此执行该run()方法


“主要方法”与它无关。
2013年

3
@EJP,由main作者表示调用方法。他的回答很好。+1 ;-)
dom_beau 2014年

1
@dom_beau如果那是他的意思,他应该这么说。他说的话是不正确的。这个答案没有什么“非常好的”。这只是一个混乱的混乱。
罗恩侯爵

5

t.start() 是库提供您想要新线程时调用的代码的方法。

r.run()提供的新线程中调用的方法。


这些答案中的大多数都错过了全局,这是就Java语言而言,两者之间没有什么区别,t.start()r.run()其他两种方法之间没有什么区别。

它们都是方法。它们都在调用它们的线程中运行。他们俩都按照自己的编码去做,然后都回到同一个线程中,返回给调用者。

最大的区别是,的大多数代码t.start()本机代码,而在大多数情况下,的代码r.run()将是纯Java。但这并没有太大的区别。代码就是代码。很难找到本机代码,发现时也很难理解,但是它仍然只是告诉计算机做什么的代码。

那么,该怎么t.start()办?

它创建一个新的本机线程,安排该线程调用t.run(),然后告诉OS让新线程运行。然后返回。

怎么r.run()办?

有趣的是,问这个问题的人是写它的人。 r.run()(即编写它的开发人员)设计要做的任何事情。


4

Thread.start()代码向调度程序注册线程,然后调度程序调用该run()方法。另外,Threadis class while Runnable是接口。


3

成员提出的观点是正确的,所以我只想添加一些内容。事实是,JAVA不支持多继承。但是,如果您想从另一个类A派生一个类B,却只能从一个类派生,那该怎么办。现在的问题是如何从两个类(A和Thread)“派生”。因此,您可以使用可运行接口。

public class ThreadTest{
   public void method(){
      Thread myThread = new Thread(new B());
      myThread.start;
   }
}

public class B extends A implements Runnable{...

借助有关Runnable的示例(一个接口和一个线程)的一个类,很好地解释了run()方法
Pinky Walve

1

如果直接调用run()方法,则由于run()方法是作为调用者线程的一部分执行的,因此您没有使用多线程功能。

如果start()在线程上调用方法,则Java虚拟机将调用run()方法,并且两个线程将同时运行-当前线程(main()在您的示例中)和其他线程(r1在您的示例中为Runnable )。

看一下Thread类start()方法的源代码

 /**
     * 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执行此本机方法。


0

在第一种情况下,您只是调用和对象的run()方法。r1r2

在第二种情况下,您实际上是在创建2个新线程!

start()run()在某个时候打电话!


7
实际上,start()不会调用run():如果这样做,则run()方法将由调用start()的同一线程执行。start()要做的是创建一个线程,该线程将调用run()方法。
布鲁诺·雷斯

0

run方法: -是最初在Runnable接口中创建的抽象方法,并且在Thread类以及Thread子类(由于Thread在其源代码中实现Runnable)和任何其他Runnable接口的实现类中被覆盖。-用于将要执行的任务加载到线程(可运行对象)中,因此您可以重写该线程以编写该任务。

start方法: -在Thread类中定义。在Thread对象1上调用start方法时, 它会调用内部称为start0()的本地(nonjava)方法;方法。

start0(); 方法: 负责低处理(此时为线程创建堆栈并在处理器队列中分配线程),此时我们的线程处于Ready / Runnable状态。

2-在线程调度程序确定线程进入处理器核心时(在此期间,线程优先级以及OS调度算法),对Runnable对象(无论是当前的Runnable线程对象还是通过的Runnable对象)调用run方法到线程构造函数),这里的线程进入运行状态并开始执行其任务(运行方法)


-2

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

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

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


2
调用“ run()”不是创建线程程序的方法。只有一种方法。
罗恩侯爵,

-2

Thread扩展类和Runnable实现接口的Start()方法调用运行重写方法。

但是通过调用run()会搜索run方法,但是如果类实现Runnable接口,则它将调用Run()覆盖Runnable的方法。

例如:

`

public class Main1
{
A a=new A();
B b=new B();
a.run();//This call run() of Thread because run() of Thread only call when class 
        //implements with Runnable not when class extends Thread.
b.run();//This not run anything because no run method found in class B but it 
        //didn't show any error.

a.start();//this call run() of Thread
b.start();//this call run() of Thread
}

class A implements Runnable{
@Override
    public void run() {
            System.out.println("A ");
    }
}

class B extends Thread {

    @Override
    public void run() {
            System.out.println("B ");
    }
}

`

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.