为什么启动线程是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 接口, 并运行线程; -- ...
随机推荐
- UIAutomator2安装及连接
记录一下自己的偿试过程,内容来自:https://github.com/openatx/uiautomator2 d.service("uiautomator").stop()是因 ...
- Typora Ubuntu 不显示 加粗
问题描述: Typora 在 Ubuntu18.04 上面不显示 Markdown 加粗语法 解决办法: 在 Typora's github.css 里面,将 body 修改为如下内容 body { ...
- 项目readme文件目录生成工具 treer
生成目录的工具呢有tree和treer,但是tree不知道怎么忽略node_modules文件夹, 而treer就简单了,下面就是基本的命令了 其中-i是指忽略xxx, -e是指导出 安装 npm i ...
- 使用jQuery实现Ajax
jQuery对Ajax操作进行了封装,在jQuery中最底层的方法是$.ajax(), 第二层是load(), $.get(), $.post() 第三层是$.getScript(), $.g ...
- 轻松实现记录与撤销——C#中的Command模式
Command模式属于行为模式,作为大名鼎鼎的23个设计模式之一,Command模式理解起来不如工厂模式,单例模式等那么简单直白.究其原因,行为模式着重于使用,如果没有编程实践,确实不如创造模式那么直 ...
- 关于vue的多页面标签功能,对于嵌套router-view缓存的最终无奈解决方法
最近写我自己的后台开发框架,要弄一个多页面标签功能,之前有试过vue-element-admin的多页面,以为很完美,就按它的思路重新写了一个,但发现还是有问题的. vue-element-admin ...
- Johnson-Trotter(JT)算法生成排列
对于生成{1,……,n}的所有n!个排列的问题,我们可以利用减治法,该问题的规模减一就是要生成所有(n-1)!个排列.假设这个小问题已经解决了,我们可以把n插入到n-1个元素的每一种排列中的n ...
- ASP.NET中使用Entity Framework开发增删改查的Demo(EF增删改查+母版页的使用)
这里更多的是当作随身笔记使用,记录一下学到的知识,以便淡忘的时候能快速回顾 这里是该项目的第二部分, 第一部分 第二部分(当前部分) 大完结版本 此Demo是新建了一个音乐类型的web,然后使用母版页 ...
- Java 第十一届 蓝桥杯 省模拟赛 螺旋矩阵
螺旋矩阵 题目 问题描述 对于一个 n 行 m 列的表格,我们可以使用螺旋的方式给表格依次填上正整数,我们称填好的表格为一个螺旋矩阵. 例如,一个 4 行 5 列的螺旋矩阵如下: 1 2 3 4 5 ...
- Java实现 蓝桥杯VIP 算法训练 明明的随机数
问题描述 明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了N个1到1000之间的随机整数(N≤100),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应 ...