为什么启动线程是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 接口, 并运行线程; -- ...
随机推荐
- Meta标签基本使用
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><t ...
- Docker 入门:容器
容器看着像机器,实际是进程,是一个运行时程序. 要操作一个 Docker 容器,只需要执行 docker container 命令. 可以通过 help 查看 run 运行容器 基础使用: docke ...
- web自动化之文件上传操作
#!/usr/bin/python3 # -*- coding: utf-8 -*- #Author: xiaojian #Time: 2018/11/16 20:49 import win32gui ...
- 读Pyqt4教程,带你入门Pyqt4 _004
在PyQt4教程的这部分中,我们将探讨应用中事件和信号的发生. 事件是GUI程序的重要部分,由用户或者系统产生.当我们调用应用的 exec_() 方法,应用进入主循环.主循环获取事件并把它们发往对象. ...
- BJDCTF-WP
BJDCTF 2nd WP 引言 由于在备考,所以没多少时间做,并且也实属是菜,所以就做了几个题目,这里就分享一下啦 Hi~ o( ̄▽ ̄)ブ [BJDCTF 2nd]fake google 知识点:S ...
- DQN(Deep Q-learning)入门教程(四)之Q-learning Play Flappy Bird
在上一篇博客中,我们详细的对Q-learning的算法流程进行了介绍.同时我们使用了\(\epsilon-贪婪法\)防止陷入局部最优. 那么我们可以想一下,最后我们得到的结果是什么样的呢?因为我们考虑 ...
- nacos 配置
具体请访问 https://nacos.io/zh-cn/docs/what-is-nacos.html 网站查看文档,现在开始使用Nacos. 1. 下载Nacos源码 Nacos可以通过 http ...
- golang内置类型和内置函数
golang内置类型和内置函数是不需要引入包直接可用的 golang内置类型: 数值类型 string int,unint float32,float64 bool array 有长度的 comple ...
- DOM对HTML元素的增删改操作和事件概念和事件监听
DOM创建节点的方法: document.createElement(Tag),Tag必须是合法的HTML元素 DOM复制节点的方法: 节点cloneNode(boolean deep),当deep为 ...
- Java实现 蓝桥杯 历届试题 核桃的数量
历届试题 核桃的数量 时间限制:1.0s 内存限制:256.0MB 问题描述 小张是软件项目经理,他带领3个开发组.工期紧,今天都在加班呢.为鼓舞士气,小张打算给每个组发一袋核桃(据传言能补脑).他的 ...