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() 方法?的更多相关文章
- java中多线程执行时,为何调用的是start()方法而不是run()方法
Thead类中start()方法和run()方法的区别 1,start()用来启动一个线程,当调用start()方法时,系统才会开启一个线程,通过Thead类中start()方法来启动的线程处于就绪状 ...
- 最简单的java多线程代码(重写thread或者runnable的run方法)
http://blog.csdn.net/testcs_dn/article/details/42526549 java线程使用示例——最简单的线程 线程使用示例一: [java] view plai ...
- java多线程并发去调用一个类的静态方法安全性探讨
java多线程并发去调用一个类的静态方法安全性探讨 转自:http://blog.csdn.net/weibin_6388/article/details/50750035 这篇文章主要讲多线程对 ...
- Java中是否可以调用一个类中的main方法?
前几天面试的时候,被问到在Java中是否可以调用一个类中的main方法?回来测试了下,答案是可以!代码如下: main1中调用main2的主方法 package org.fiu.test; impor ...
- “全栈2019”Java多线程第三十章:尝试获取锁tryLock()方法详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- “全栈2019”Java多线程第十二章:后台线程setDaemon()方法详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- “全栈2019”Java多线程第七章:等待线程死亡join()方法详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- ajax 执行成功以后返回的数据走的是error方法而不是success方法的问题
今天在一个功能的时候发现写的ajax的方法执行后台代码成功后返回前台时执行的是error方法而不是success方法,代码如下 jQuery('#form').ajaxSubmit({ type: & ...
- C#开发笔记之03-为什么选择IsNotXXX方法而不是IsXXX方法?
C#开发笔记概述 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/959 访问. 为什么有时候要选择IsNotXXX方法而 ...
随机推荐
- 你的网购价格监督利器——python+爬虫+微信机器人
前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:风,又奈何 PS:如有需要Python学习资料的小伙伴可以加点击下方链 ...
- L11注意力机制和Seq2seq模型
注意力机制 在"编码器-解码器(seq2seq)"⼀节⾥,解码器在各个时间步依赖相同的背景变量(context vector)来获取输⼊序列信息.当编码器为循环神经⽹络时,背景变量 ...
- Sprint 5 summary: UI 界面更新,Azure端部署和用户反馈分析 12/28/2015
本次sprint主要完成的任务有对手机APP的UI界面的更新,同时对Azure客户端的部署进行了相应的学习和有关的程序设计.同时对于ALPHA release的用户反馈做出相应的分析以确定接下来工作的 ...
- c++ find 函数与count函数
1 algorithml中的find,还有就是string中的find 对对于第一种其调用形式为 find(start,end,value) start搜寻的起点,end搜寻的终点,要寻找的value ...
- CSS属性中的display属性浅谈;
首先我们要知道什么是块级元素和行内元素有什么区别: 承接上篇文章:(浅谈HTML和body标签) 块级元素:浏览器解析为独占一行的元素(例如:div.table.ul等.),浏览器会在该元素的前后显示 ...
- SQL SERVER 那点事
温故而知新 一.创建数据库 USE MASTER; GO IF EXISTS(SELECT * FROM sys.databases WHERE [name] = 'student') BEGIN A ...
- google无法播放mp4 chrome无法播放h264
写在前面 我在chrome上无法播放h264+Acc的mp4,在firefox.ie都可以播放,而且此mp4在vlc终可以正常播放. 视频链接:http://106.14.221.185:7001/p ...
- 如何用TensorFlow实现线性回归
环境Anaconda 废话不多说,关键看代码 import tensorflow as tf import os os.environ['TF_CPP_MIN_LOG_LEVEL']='2' tf.a ...
- Java 多线程 -- 理解锁:手动实现可重入锁和不可重入锁
JDK提供的大多数内置锁都是可重入的,也就是 说,如果某个线程试图获取一个已经由它自己持有的锁时,那么这个请求会立 刻成功,并且会将这个锁的计数值加1,而当线程退出同步代码块时,计数器 将会递减,当计 ...
- gojs去水印
重点在go.js文件中将这个方法中的代码注释掉即可 搜索关键字 7ca11abfd022028846 然后注释下列代码,注释前先整理JS格式 function ni() { if(th) { var ...