【发布时间】:2011-11-08 15:06:35
【问题描述】:
为什么我们调用线程对象的start()方法,而后者又调用run()方法,为什么不直接调用run()方法呢?
【问题讨论】:
标签: java multithreading
为什么我们调用线程对象的start()方法,而后者又调用run()方法,为什么不直接调用run()方法呢?
【问题讨论】:
标签: java multithreading
[...] 为什么不直接调用 run() 方法呢?
run() 方法只是一个普通方法(被 you 覆盖)。与任何其他普通方法一样,直接调用它会导致当前线程执行run()。
所有的魔法都发生在start() 内部。 start() 方法将导致 JVM 产生一个新线程,并使新产生的线程执行 run()。
【讨论】:
start方法来获得分叉行为。基本上什么才是最重要的。魔术是直接在start 中发生还是委托给另一个方法取决于API 实现。如果您指的是 OpenJDK 中的 Thread.java,它看起来确实像是委托给了 start0。我敢打赌,这种方法也不包含“魔法”。我敢打赌它委托给一些fork() 系统调用。最后,这取决于操作系统。同样,这是一个 JDK/OS 实现细节。
如果你直接调用 run() 方法,它的主体将在当前线程的上下文中执行。当您调用start() 方法时,会创建一个新线程,并在这个新线程中执行run() 方法。
【讨论】:
即使我们没有以编程方式创建任何线程,对于每个应用程序,操作系统都会创建一个默认线程来使用 CPU 执行其代码。
直接调用run方法会让run方法在OS给定的那个主线程中执行
但创建线程类的目的是确保 run 方法在不同的线程中执行。除非 OS 的线程管理器创建一个线程,否则您的 run 方法将不会在单独的线程中执行。要请求操作系统创建单独的线程,您必须调用 start() 方法,该方法将向操作系统发送请求以创建线程。一旦 OS 创建了一个线程,那么 OS 将在新创建的线程上下文中自动调用你的线程类的 run 方法。因此,您的目的是创建一个单独的线程并在单独的线程中执行您的 run 方法。
如果你直接调用run方法,那么就像OS没有为你创建任何线程一样,默认主线程会执行你的run方法。 没有必要为此创建一个单独的线程类!
希望我清楚。如果您需要更多解释来回答您的问题,请告诉我。
注意:虽然书上说 JVM 创建线程,但内部 JVM 必须向 OS 层的线程管理器驱动程序发送请求,以在其线程池中创建一个新线程。这就是为什么我在这里比 JVM 更多地使用 OS 术语。
【讨论】:
我们为什么要调用线程对象的 start() 方法,而后者又会调用 run() 方法
不,它没有。 start() 调用操作系统,它启动一个新线程,(为了大大简化)调用run() 方法。同时start() 方法已经返回给它的调用者。它们不是等价的。
【讨论】:
Runnable 只是一个接口。实现Runnable 的类没有什么特别之处,它只是有一个run 方法。
Thread#start 是本机实现的方法,它创建一个单独的线程并调用Thread 的run 方法,在新线程中执行代码。
Thread 实现Runnable。 run 的代码如下所示:
@Override
public void run() {
if (target != null) {
target.run();
}
}
如果Thread 实例是通过将Runnable 传递给Thread 的构造函数来创建的,则将调用Runnable 的run 方法。
否则,扩展Thread 的类必须重写run 方法才能使start 工作。
在Thread 上调用run 不会创建新线程。
【讨论】:
如果线程已被实例化但尚未启动,则称其处于新状态。
除非在线程实例上调用 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 将被视为普通对象而不是线程对象。
【讨论】:
这是由于Java中的多线程设计。
调用start ()会启动一个新线程,调用run()方法不会启动一个新线程。
如果您在 Thread 上调用 start() 方法,Java 虚拟机将调用 run() 方法,两个线程现在将同时运行 - 当前线程和其他线程或 Runnable 实现。
查看Thread class中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创建对应java线程的native线程并调用run()方法。
native方法的源码参考这个问题:
【讨论】:
当我们使用 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);
}
}
}
【讨论】:
我想你是在谈论启动一个线程。如果是这种情况,您不直接调用 run 方法的原因是您将调用该方法,而不是启动线程。
【讨论】:
如果我们愿意,我们可以调用run() 方法,但是如果我们调用run 方法,它将像普通的Java 方法一样运行。而我们称之为start() 它,JVM 会创建一个新线程并在该线程上执行 run 方法。
【讨论】:
不同的是,如果我们通过start()方法执行run方法,它会创建一个新线程,我们可以在其中执行run方法,否则run()方法将在JVM创建的线程中执行public static void main()方法。这正是多线程的重点,在新线程上运行不同的操作。
【讨论】:
start() 和run() 方法用于运行一个线程。run() 方法只是一个普通方法,它被用户重写,它将在当前线程上调用。
start() 方法间接运行run() 方法并创建一个新线程。
【讨论】: