为什么启动线程是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方法?的更多相关文章

  1. 启动线程用start方法

    启动线程用start方法而不是用run方法 public static void main(String[] args) { Thread t=new Thread("Thread-TEST ...

  2. C#中添加三个线程同时启动执行某一方法,并依次调用某方法中的循环打印输。

    添加三个线程同时启动执行某一方法,并依次调用某方法中的打印输:ABC ABC ABC ABC 实现代码如下: using System; using System.Collections.Generi ...

  3. Java中Thread方法启动线程

    public class ThreadTest extends Thread {  private int count = 10; @Override public void run() { //重写 ...

  4. Struts+Spring+Hibernate项目的启动线程

    在Java Web项目中,经常要在项目开始运行时启动一个线程,每隔一定的时间就运行一定的代码,比如扫描数据库的变化等等.要实现这个功能,可以现在web.xml文件中定义一个Listener,然后在这个 ...

  5. 我的Android最佳实践之—— Android启动画面的实现方法

    本文实例讲述了Android启动画面的实现方法.分享给大家供大家参考.具体分析如下: 在应用程序中经常用到启动画面,会启动一个后台线程为主程序的运行准备资源.Android要实现启动画面可以这样做: ...

  6. 线程的实现方法以及区别 extends Thread、implements Runable

    /** 线程存在于进程当中,进程由系统创建. 创建新的执行线程有两种方法 注意:   线程复写run方法,然后用start()方法调用,其实就是调用的run()方法,只是如果直接启动run()方法, ...

  7. java线程 — 创建和启动线程

    创建和启动线程,传统有两种方式: 方式1:继承Thread类: 方式2:实现Runnable接口: 线程类(java.lang.Thread):Thread类和Thread的子类才能称之为线程类.阅读 ...

  8. java多线程之守护线程以及Join方法

    版权声明:本文出自汪磊的博客,转载请务必注明出处. 一.守护线程概述及示例 守护线程就是为其它线程提供"守护"作用,说白了就是为其它线程服务的,比如GC线程. java程序中线程分 ...

  9. 【Java 语言】Java 多线程 一 ( 线程启动 | 线程中断 )

    一. 线程启动 线程启动 : -- 1. 继承 Thread 运行线程 : 重写 Thread 类的 run 方法, 然后执行该线程; -- 2. 实现 Runnable 接口, 并运行线程; -- ...

随机推荐

  1. [JavaWeb基础] 024.Socket编程之简单的聊天程序

    1.Socket的简介 1)什么是Socket 网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket.Socket通常用来实现客户方和服务方的连接.Socket ...

  2. [PHP自动化-进阶]001.CURL模拟登录并采集数据

    引言:PHP可以通过libcurl实现模拟登录,提交数据,违法乱纪,烧杀抢虐等等事项. 简单说明一下"libcurl",补一下脑: libcurl目前支持http.https.ft ...

  3. Python中出现 SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 12-13: truncated \UXXXXXXXX escape

    Python中出现 SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 12-13: t ...

  4. Java IO(二十) PrintStream 和 DataOutputStream 异同

    Java IO(二十) PrintStream 和 DataOutputStream 异同 一.相同点 都是继承与FileOutputStream,用于包装其它输出流. 二.不同点 (一).Print ...

  5. java的Interger自动包装带来的问题

    1 首先看一下以下代码: Integer b=7; Integer c=7; Integer r=234; Integer d=234; System.out.println(b==c); Syste ...

  6. Flutter 动画鼻祖之CustomPaint

    老孟导读:CustomPaint可以称之为动画鼻祖,它可以实现任何酷炫的动画和效果.CustomPaint本身没有动画属性,仅仅是绘制属性,一般情况下,CustomPaint会和动画控制配合使用,达到 ...

  7. A barrier for Mobile Forensics - Samsung Secure Folder

    Since I mentioned about "Second Space", let's take a look at Samsung "Secure Folder&q ...

  8. 对象调用 push 方法

    /* Array.prototype.push = function A(val) { this[this.length] = val; // =>this.length 在原来的基础上加1 r ...

  9. ActiveMQ 笔记(七)ActiveMQ的多节点集群

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 一.Activemq 的集群思想 1.使用Activemq集群的原因 面试题: 引入消息中间件后如何保证 ...

  10. 初步理解 MySQL数据库

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 1. 索引是做什么的? 索引用于快速找出在某个列中有一特定值的行.不使用索引,MYSQL必须从第1条记录 ...