Java 多线程发动为什么调用 start() 办法而不是 run() 办法?
多线程在工作中多多少少会用到,咱们知道发动多线程调用的是 start() 办法,而不是 run() 办法,你知道原因吗?
在讨论这个问题之前,咱们先来了解一些多线程的基础知识~
线程的状况
Java 中,界说了 6 种线程状况,在 Thread 类能够找到:
// 为了节省空间,我删除了注释
public enum State {
NEW,//初始状况
RUNNABLE,//运转状况
BLOCKED,// 堵塞状况
WAITING,//等候状况
TIMED_WAITING,//超时等候状况
TERMINATED;//停止状况
}
这 6 种状况之间的相关,能够看下面这张图:
这张图描绘的仍是十分详细的,结合这张图,来说说这几种状况别离代表着什么意思:
1、NEW 表明线程创立成功,但没有运转,在 new Thread 之后,没有 start 之前,线程都处于 NEW 状况;
2、RUNNABLE 表明线程正在运转中,当咱们运转 strat 办法,子线程被创立成功之后,子线程的状况变成 RUNNABLE;
3、TERMINATED 表明线程现已运转完毕,子线程运转完结、被打断、被间断,状况都会从 RUNNABLE 变成 TERMINATED;
4、BLOCKED 表明线程被堵塞,假如线程正好在等候取得 monitor lock 锁,比如在等候进入 synchronized 润饰的代码块或办法时,会从 RUNNABLE 变成 BLOCKED;
5、 WAITING 和 TIMED_WAITING 都表明等候,现在在遇到 Object#wait、Thread#join、
LockSupport#park 这些办法时,线程就会等候另一个线程履行完特定的动作之后,才能结
束等候,只不过 TIMED_WAITING 是带有等候时间的;
优先级
优先级代表线程履行的时机的巨细,优先级高的或许先履行,低的或许后履行。
在 Java 源码中,优先级从低到高别离是 1 到 10,线程默许 new 出来的优先级都是 5,源码如下:
/**
The minimum priority that a thread can have.
*/
public final static int MIN_PRIORITY = 1;
/**
The default priority that is assigned to a thread.
*/
public final static int NORM_PRIORITY = 5;
/**
The maximum priority that a thread can have.
*/
public final static int MAX_PRIORITY = 10;
线程得创立办法
咱们创立多线程有两种办法,一种是承继 Thread 类,另一种是完结 Runnable 接口。两种办法的运用,如下所示:
1、承继 Thread,成为 Thread 的子类
public class MyThread extends Thread{
@Override
public void run() {
System.out.println("我是经过承继 Thread 类完结的~");
}
public static void main(String[] args) {
MyThread thread = new MyThread();
// 发动线程
thread.start();
}
}
2、完结 Runnable 接口
public class MyThread1 {
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("我是经过 runnable 办法完结的~");
}
});
// 发动线程
thread.start();
}
}
不论运用哪一种办法,发动线程都是thread.start()办法,假如你做过试验的话,你会发现 thread.run()也能够履行,为什么就必定需求调用thread.start()办法呢?
先说说定论:首要经过目标.run()办法能够履行办法,可是不是运用的多线程的办法,便是一个一般的办法,要想完结多线程的办法,必定需求经过目标.start()办法。
想要弄理解一个问题,最好的办法便是从源码下手,咱们也从这两个办法的源码开端,先来看看 start 办法的源码:
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();
/* 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);
// 是否发动的标识符
boolean started = false;
try {
// start0() 是发动多线程的要害
// 这里会创立一个新的线程,是一个 native 办法
// 履行完结之后,新的线程现已在运转了
start0();
// 主线程履行
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 */
}
}
}
start 办法的源码也没几行代码,注释也比较详细,最主要的是 start0() 办法,这个后边在解说。再来看看 run() 办法的源码:
@Override
public void run() {
// 简略的运转,不会新起线程,target 是 Runnable
if (target != null) {
target.run();
}
}
run() 办法的源码就比较简略的,便是一个一般办法的调用,这也印证了咱们上面的定论。
接下来咱们就来说一说这个 start0() 这个办法,这个是真实完结多线程的要害,start0() 代码如下:
private native void start0();
start0 被符号成 native ,也便是本地办法,并不需求咱们去完结或许了解,为什么 start0() 会符号成 native?
这个要从 Java 跨渠道说起,看下面这张图:
start() 办法调用 start0() 办法后,该线程并不必定会立马履行,仅仅将线程变成了可运转状况。详细什么时候履行,取决于 CPU ,由 CPU 一致调度。
咱们又知道 Java 是跨渠道的,能够在不同体系上运转,每个体系的 CPU 调度算法不一样,所以就需求做不同的处理,这件工作就只能交给 JVM 来完结了,start0() 办法天然就表符号成了 native。
最终,总结一下,Java 中完结真实的多线程是 start 中的 start0() 办法,run() 办法仅仅一个一般的办法。
本文解释了Java中为何启动多线程时调用start()方法而非run()方法。通过对比两种方法的作用及源码分析,揭示了start()方法如何通过start0()本地方法创建并启动新线程。

被折叠的 条评论
为什么被折叠?



