问题
Java 线程调用start()后会立即执行run()方法吗?
我们在开发中,经常和线程打交道,有些东西总是司空见惯,想当然地认为某些事情理所当然...
但是今天偶然发现一个有趣的现象:
class Test {
public static void main(String[] args) {
System.out.println("hello https://tool.lu/");
Runnable runnable = new Runnable(){
@Override
public void run() {
System.out.println("--run()--");
}
};
Thread thread = new Thread(runnable);
thread.start();
System.out.println("--after start()--");
}
}
运行结果如下:
看到运行结果之后,我愣了一下,WTF?
跟我想的有点不一样啊,
理论上来讲,线程调用start()之后,将会调用该线程的run();
我又赶紧去查看了Java的官方文档:JavaAPI
Cause this thread to begin execution ; the Java Virtual Machine calls the run method of this thread.
通过上面我们可以发现start()就是使该线程开始运行,JVM会调用线程的run()方法。
那我们只能从源码中找答案啦。
/**
* 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".
*/
// Android-changed: throw if 'started' is true
if (threadStatus != 0 || started)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this);
started = false;
try {
nativeCreate(this, stackSize, daemon);
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
private native static void nativeCreate(Thread t, long stackSize, boolean daemon);
关键代码已经贴出,但是似乎关键在于nativeCreate()方法。该方法属于c方法,有时间再追踪一下。
思考
通过代码测试我们发现线程调用start()方法,并不会立刻执行run()方法。但是两者之间的时间差是多少呢?
测试用例,有兴趣的朋友can have a try.
把运行结果给出来:
通过我的多次测试,run()和start()的时间差一般都在[0,8]之内,当然运行足够多次会发现时间差会更大。
总结
虽然该用例看似没什么卵用,但不亲自上手尝试,还真会回答错...有趣有趣...
需要注意的是如果我们在线程中创建对象,而在start()方法后直接使用该对象,就会出现该问题测试用例。
夫小惑易方,大惑易性...