为什么启动线程是start方法?
为什么启动线程是start方法
十年可见春去秋来,百年可证生老病死,千年可叹王朝更替,万年可见斗转星移。
凡人如果用一天的视野,去窥探百万年的天地,是否就如同井底之蛙?
背景:启动线程是start() 还是run() 方法?相信这个问题很多人都知道是start(),但是如果我再问下去呢,为什么是start()?你会如何作答呢?
一、理论课
当用start()开始一个线程后,线程就进入就绪状态,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM调度并执行;但是这并不意味着线程就会立即运行,只有当cpu分配时间片时,这个线程获得时间片时,才开始执行run()方法;start()方法去调用run(),而run()方法则是需要去重写的,其包含的是线程的主体(真正的逻辑)。
二、线程六大状态
Java 中,定义了 6 种线程状态,NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING和TERMINATED。
public enum State{
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}
6 种线程状态关系图

三、代码层次
杨总说的,一切问题归咎于源码!
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 */
}
}
}
run方法源码:
@Override
public void run() {
// 简单的运行,不会新起线程,target 是 Runnable
if (target != null) {
target.run();
}
}
从start()和run()方法的源码可以看出,start方法的源码也没几行代码,最主要的是 start0() 方法;run() 方法的源码也比较简单的,就是一个普通方法的调用;重点是这个 start0() 方法,她是真正实现多线程的关键。
start0方法源码:
// native :就是本地方法
private native void start0();
关于native方法简述:
1、被native关键字修饰的方法叫做本地方法,本地方法和其它方法不一样,本地方法意味着和平台有关,因此使用了native的程序可移植性都不太高;
2、native方法在JVM中运行时数据区也和其它方法不一样,它有专门的本地方法栈;
3、native方法主要用于加载文件和动态链接库,由于Java语言无法访问操作系统底层信息(比如:底层硬件设备等),这时候就需要借助C语言来完成了;
4、被native修饰的方法可以被C语言重写。
Java 跨平台图

在start()中start0 被标记成 native ,也就是本地方法,并不需要我们去实现或者了解,只要了解下为什么 start0() 会标记成 native ?
如上图,start() 方法调用 start0() 方法后,该线程并不一定会立马执行,只是将线程变成了可运行状态(NEW ---> RUNNABLE);具体什么时候执行,取决于 CPU ,由 CPU 统一调度;我们又知道 Java 是跨平台的,可以在不同系统上运行,每个系统的 CPU 调度算法不一样,所以就需要做不同的处理,这件事情就只能交给 JVM 来实现了,start0() 方法自然就表标记成了 native。
四、总结
Java 中实现真正的多线程是 start 中的 start0() 方法,run() 方法只是一个包含业务逻辑普通的方法;start是启动多线程的唯一方式,其使得线程由创建态到就绪态,而这个线程是否被运行是由系统调度所决定的。
十年可见春去秋来
百年可证生老病死
千年可叹王朝更替
万年可见斗转星移
凡人如果用一天的视野
去窥探百万年的天地
是否就如同井底之蛙?
为什么启动线程是start方法?的更多相关文章
- 启动线程用start方法
启动线程用start方法而不是用run方法 public static void main(String[] args) { Thread t=new Thread("Thread-TEST ...
- C#中添加三个线程同时启动执行某一方法,并依次调用某方法中的循环打印输。
添加三个线程同时启动执行某一方法,并依次调用某方法中的打印输:ABC ABC ABC ABC 实现代码如下: using System; using System.Collections.Generi ...
- Java中Thread方法启动线程
public class ThreadTest extends Thread { private int count = 10; @Override public void run() { //重写 ...
- Struts+Spring+Hibernate项目的启动线程
在Java Web项目中,经常要在项目开始运行时启动一个线程,每隔一定的时间就运行一定的代码,比如扫描数据库的变化等等.要实现这个功能,可以现在web.xml文件中定义一个Listener,然后在这个 ...
- 我的Android最佳实践之—— Android启动画面的实现方法
本文实例讲述了Android启动画面的实现方法.分享给大家供大家参考.具体分析如下: 在应用程序中经常用到启动画面,会启动一个后台线程为主程序的运行准备资源.Android要实现启动画面可以这样做: ...
- 线程的实现方法以及区别 extends Thread、implements Runable
/** 线程存在于进程当中,进程由系统创建. 创建新的执行线程有两种方法 注意: 线程复写run方法,然后用start()方法调用,其实就是调用的run()方法,只是如果直接启动run()方法, ...
- java线程 — 创建和启动线程
创建和启动线程,传统有两种方式: 方式1:继承Thread类: 方式2:实现Runnable接口: 线程类(java.lang.Thread):Thread类和Thread的子类才能称之为线程类.阅读 ...
- java多线程之守护线程以及Join方法
版权声明:本文出自汪磊的博客,转载请务必注明出处. 一.守护线程概述及示例 守护线程就是为其它线程提供"守护"作用,说白了就是为其它线程服务的,比如GC线程. java程序中线程分 ...
- 【Java 语言】Java 多线程 一 ( 线程启动 | 线程中断 )
一. 线程启动 线程启动 : -- 1. 继承 Thread 运行线程 : 重写 Thread 类的 run 方法, 然后执行该线程; -- 2. 实现 Runnable 接口, 并运行线程; -- ...
随机推荐
- Spark SQL源码解析(五)SparkPlan准备和执行阶段
Spark SQL原理解析前言: Spark SQL源码剖析(一)SQL解析框架Catalyst流程概述 Spark SQL源码解析(二)Antlr4解析Sql并生成树 Spark SQL源码解析(三 ...
- Javascript书写位置
1.行内式js(很少使用) 以on开头,如onclick HTML中推荐双引号,JS推荐单引号 2.内嵌式js(常用) <script> alert('hello world'); < ...
- 【真相揭秘】requests获取网页编码乱码本质
有没有被网页编码抓狂,怎么转都是乱码. 通过查看requests源代码,才发现是库本身历史原因造成的. 作者是严格http协议标准写这个库的,<HTTP权威指南>里第16章国际化里提到,如 ...
- 上古神器vim系列之移动三板斧
[导读] 前文总结了vim如何进入,如何保存退出,如何进入编辑模式.本文来总结一些稍微进阶的内容,在normal模式下如何高效的浏览代码. 模式回顾 在normal模式下主要用于浏览代码,那么有哪些方 ...
- PHP常量和数据类型
引言 先用一个题来作为开端:PHP字符串的三种定义方式是什么?有什么区别? 它们分别是单引号'',双引号"",newdoc和heredoc. 区别是:单引号不能解析变量,不能解析转 ...
- Java实现 蓝桥杯 传纸条
题目描述 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学安排做成一个mm行nn列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法直接交谈了.幸运 ...
- Java实现 LeetCode 575 分糖果(看看是你的长度小还是我的种类少)
575. 分糖果 给定一个偶数长度的数组,其中不同的数字代表着不同种类的糖果,每一个数字代表一个糖果.你需要把这些糖果平均分给一个弟弟和一个妹妹.返回妹妹可以获得的最大糖果的种类数. 示例 1: 输入 ...
- Java实现 LeetCode 304 二维区域和检索 - 矩阵不可变
304. 二维区域和检索 - 矩阵不可变 给定一个二维矩阵,计算其子矩形范围内元素的总和,该子矩阵的左上角为 (row1, col1) ,右下角为 (row2, col2). Range Sum Qu ...
- Java实现 蓝桥杯VIP 算法提高 3-3求圆面积表面积体积
算法提高 3-3求圆面积表面积体积 时间限制:1.0s 内存限制:256.0MB 问题描述 接受用户输⼊的数值,输出以该值为半径的(1)圆面积,(2)球体表面积,(3)球体体积.pi 取值3.1415 ...
- MD760按键说明书