开启线程为什么是执行start()方法而不直接执行run()方法
程序员文章站
2022-06-05 13:46:33
...
先看一段代码
public class Battles {
public static void main(String[] args) {
Thread t = new Thread(){
@Override
public void run(){
pong();
}
};
t.run();//重点在这,此处执行的是run()方法
System.out.println(Thread.currentThread().getName());
System.out.println("ping");
}
private static void pong() {
System.out.println(Thread.currentThread().getName());
System.out.println("pong");
}
}
大家可以试想一下输出是什么,在以往创建线程执行start()方法来看,新建的线程似乎比main线程要慢一点,“ping”和“pong”的输出可能并没有固定的顺序,而代码并不是执行的start()方法而是直接执行run()方法,到底有什么不一样呢,start()方法不依旧会执行run()方法吗?
先看结果:
main
pong
main
ping
发现了奇怪的一点,重写的run方法在输出线程名字的时候居然也是main,这两个线程都是用的同一个main线程,难道new Thread并没有帮我创建新线程吗?
带着这个疑问,深究一下start()方法和run()方法的区别----------直接上源码:
首先看run()方法
@Override
public void run() {
if (target != null) {
target.run(); //没有多余的操作,直接调用了重写的run()方法,并没有创建线程的操作
}
}
锁定start()方法
public synchronized void start() { //首先表明了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);
boolean started = false;
try {
start0(); //核心的地方就是调用了satrt0()方法
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 void start0(); //该方法并没有方法体,却有一个native的关键字修饰
先讲讲native关键字,native method就是Java调用非Java代码的接口,就是说native method 的方法实现由其他语言实现的,比如C语言等
/* Make sure registerNatives is the first thing <clinit> does. */
private static native void registerNatives();
static {
registerNatives(); //在这个静态代码块中就使用了registerNatives将本地方法加载进来供给native method使用
}
start0()方法会调用本地文件中的方法---------------还有诸多常见方法,如stop0,isAlive,yield,sleep等
static JNINativeMethod methods[] = {
{"start0", "()V", (void *)&JVM_StartThread}, // 可以看出调用了JVM_StartThread
{"stop0", "(" OBJ ")V", (void *)&JVM_StopThread},
{"isAlive", "()Z", (void *)&JVM_IsThreadAlive},
{"suspend0", "()V", (void *)&JVM_SuspendThread},
{"resume0", "()V", (void *)&JVM_ResumeThread},
{"setPriority0", "(I)V", (void *)&JVM_SetThreadPriority},
{"yield", "()V", (void *)&JVM_Yield},
{"sleep", "(J)V", (void *)&JVM_Sleep},
{"currentThread", "()" THD, (void *)&JVM_CurrentThread},
{"countStackFrames", "()I", (void *)&JVM_CountStackFrames},
{"interrupt0", "()V", (void *)&JVM_Interrupt},
{"isInterrupted", "(Z)Z", (void *)&JVM_IsInterrupted},
{"holdsLock", "(" OBJ ")Z", (void *)&JVM_HoldsLock},
{"getThreads", "()[" THD, (void *)&JVM_GetAllThreads},
{"dumpThreads", "([" THD ")[[" STE, (void *)&JVM_DumpThreads},
{"setNativeName", "(" STR ")V", (void *)&JVM_SetNativeThreadName},
};
#undef THD
#undef OBJ
#undef STE
#undef STR
JNIEXPORT void JNICALL
Java_java_lang_Thread_registerNatives(JNIEnv *env, jclass cls)
{
(*env)->RegisterNatives(env, cls, methods, ARRAY_LENGTH(methods));
}
JVM_StartThread方法会创建一个本地线程,最终会去调用run方法
总的来说:Java的里面创建线程之后必须要调用启动方法才能真正的创建一个线程,该方法会调用虚拟机启动一个本地线程,本地线程的创建会调用当前系统创建线程的方法进行创建,并且线程被执行的时候会回调跑方法进行业务逻辑的处理
总结:开启线程为什么是执行start方法而不是执行run方法:直接调用run方法该线程并不会创建出来,而是直接使用主线程去执行重写的run逻辑,只有调用start方法才会创建一个新的本地进程,通过本地进程去执行重写的run逻辑
上一篇: Spring4.3x教程之三AOP详解
下一篇: Spring 04 AOP