为什么使用start方法启动Java的Thread线程?

2023-11-18

一、简介

在Java代码当中,当我们需要开启子线程去处理一些任务的时候,往往是调用Thread对象的start方法,这样Thread实例中的Runnable对象的run方法就会在一个新的线程当中执行;

// 创建一个线程
Thread thread = new Thread(new Runnable() {
			
	@Override
	public void run() {
		System.out.println("working in " + Thread.currentThread().getName());
	}
});

// 在什么线程调用,run方法的任务就在什么线程执行
thread.run();

// 在一个新的线程中执行run方法中的任务
thread.start();
二、分析run()方法

如下代码可见,当我们直接调用run方法的时候,就相当于实例直接调用一个普通的方法一样,所以无论我们在什么线程中调用run方法,run方法中的业务就在什么线程执行,并不会说启动一个新的线程去执行run方法中的任务;

// Thread.class中的run方法,target为Runnable实例
@Override 
public void run() {
    if (target != null) {
        target.run();
    }
}
三、分析start()方法

如下我们直接来看Thread.class中的代码;

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. */
    // 1. 将当前线程实例添加到ThreadGroup对象group中
    group.add(this);

    boolean started = false;
    try {
        // 2. 调用native方法start0()
        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 */
        }
    }
}

// native 方法
private native void start0();

看上面代码的注释1那里,我们来看下Thread.class代码里面group是哪里来的

private void init(ThreadGroup g, Runnable target, String name,
                  long stackSize, AccessControlContext acc,
                  boolean inheritThreadLocals) {
    if (name == null) {
        throw new NullPointerException("name cannot be null");
    }

    this.name = name;

    Thread parent = currentThread();
    // 1. 从System类中获取安全管理器
    SecurityManager security = System.getSecurityManager();
    if (g == null) {
        /* Determine if it's an applet or not */

        /* If there is a security manager, ask the security manager
           what to do. */
        if (security != null) {
            // 2. 从安全管理器中过去ThreadGroup对象
            g = security.getThreadGroup();
        }

        /* If the security doesn't have a strong opinion of the matter
           use the parent thread group. */
        if (g == null) {
            g = parent.getThreadGroup();
        }
    }

    g.addUnstarted();

    this.group = g;
        
    // 省略一部分代码
    ···
}

从上面注释1,2可以看出,Thread实例中的ThreadGroup实例g主要是从底层代码中获取的,即group.add(this)执行之后,将当前线程传给了底层系统去管理

下面看下start0()方法,因为start0()方法为Native方法,看下是怎么实现的,如下为src/main/native/Thread.c的代码

static JNINativeMethod methods[] = {
    // 从这里我们可以看到start0方法主要JVM_StartThread的一个方法引用
    {"start0",           "(JZ)V",      (void *)&JVM_StartThread},
    {"setPriority0",     "(I)V",       (void *)&JVM_SetThreadPriority},
    {"yield",            "()V",        (void *)&JVM_Yield},
    {"sleep",            "(Ljava/lang/Object;J)V",       (void *)&JVM_Sleep},
    {"currentThread",    "()" THD,     (void *)&JVM_CurrentThread},
    {"interrupt0",       "()V",        (void *)&JVM_Interrupt},
    {"isInterrupted",    "(Z)Z",       (void *)&JVM_IsInterrupted},
    {"holdsLock",        "(" OBJ ")Z", (void *)&JVM_HoldsLock},
    {"setNativeName",    "(" STR ")V", (void *)&JVM_SetNativeThreadName},
};

下面一下JVM_StartThread的情况

// 如下为/openjdkjvm/OpenjdkJvm.cc中的代码
JNIEXPORT void JVM_StartThread(JNIEnv* env, jobject jthread, jlong stack_size, jboolean daemon) {
  art::Thread::CreateNativeThread(env, jthread, stack_size, daemon == JNI_TRUE);
}


// 如下为/runtime/thread.cc中创建native线程的代码
void Thread::CreateNativeThread(JNIEnv* env, jobject java_peer, size_t stack_size, bool is_daemon) {
    ···
    // 这里就不做展开了
}

总结:从上面代码可以看出,Thread调用start的时候,将thread实例传给虚拟机持有,然后调用native创建一个新的线程,由虚拟机进行调度。

水平有限,有误请指正!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么使用start方法启动Java的Thread线程? 的相关文章

  • 如何将本机库链接到 IntelliJ 中的 jar?

    我正在尝试在 IntelliJ 中设置 OpenCV 但是我一直在弄清楚如何告诉 IntelliJ 在哪里可以找到本机库位置 在 Eclipse 中 添加 jar 后 您可以在 Build Config 屏幕中设置 Native 库的位置
  • 序列的排列?

    我有具体数量的数字 现在我想以某种方式显示这个序列的所有可能的排列 例如 如果数字数量为3 我想显示 0 0 0 0 0 1 0 0 2 0 1 0 0 1 1 0 1 2 0 2 0 0 2 1 0 2 2 1 0 0 1 0 1 1 0
  • Java 枚举与创建位掩码和检查权限的混淆

    我想将此 c 权限模块移植到 java 但是当我无法将数值保存在数据库中然后将其转换为枚举表示形式时 我很困惑如何执行此操作 在 C 中 我创建一个如下所示的枚举 public enum ArticlePermission CanRead
  • .properties 中的通配符

    是否存在任何方法 我可以将通配符添加到属性文件中 并且具有所有含义 例如a b c d lalalala 或为所有以结尾的内容设置一个正则表达式a b c anything 普通的 Java 属性文件无法处理这个问题 不 请记住 它实际上是
  • Pig Udf 显示结果

    我是 Pig 的新手 我用 Java 编写了一个 udf 并且包含了一个 System out println 其中的声明 我必须知道在 Pig 中运行时该语句在哪里打印 假设你的UDF 扩展了 EvalFunc 您可以使用从返回的 Log
  • 如何获取之前的URL?

    我需要调用我的网络应用程序的 URL 例如 如果有一个从 stackoverflow com 到我的网站 foo com 的链接 我需要 Web 应用程序 托管 bean 中的 stackoverflow 链接 感谢所有帮助 谢谢 并不总是
  • jQuery AJAX 调用 Java 方法

    使用 jQuery AJAX 我们可以调用特定的 JAVA 方法 例如从 Action 类 该 Java 方法返回的数据将用于填充一些 HTML 代码 请告诉我是否可以使用 jQuery 轻松完成此操作 就像在 DWR 中一样 此外 对于
  • 谷歌应用程序引擎会话

    什么是java应用程序引擎 默认会话超时 如果我们将会话超时设置为非常非常长的时间 会不会产生不良影响 因为谷歌应用程序引擎会话默认情况下仅存储在数据存储中 就像facebook一样 每次访问该页面时 会话仍然永远存在 默认会话超时设置为
  • 在接口中使用默认方法是否违反接口隔离原则?

    我正在学习 SOLID 原则 ISP 指出 客户端不应被迫依赖于他们所使用的接口 不使用 在接口中使用默认方法是否违反了这个原则 我见过类似的问题 但我在这里发布了一个示例 以便更清楚地了解我的示例是否违反了 ISP 假设我有这个例子 pu
  • 从最终实体获取根证书和中间证书

    作为密码学的菜鸟 我每天都会偶然发现一些简单的事情 今天只是那些日子之一 我想用 bouncy castle 库验证 java 中的 smime 消息 我想我几乎已经弄清楚了 但此时的问题是 PKIXparameters 对象的构建 假设我
  • 在 junit 测试中获取 javax.lang.model.element.Element 类

    我想测试我的实用程序类 ElementUtils 但我不知道如何将类作为元素获取 在 AnnotationProcessors 中 我使用以下代码获取元素 Set
  • tomcat 中受密码保护的应用程序

    我正在使用 JSP Servlet 开发一个Web应用程序 并且我使用了Tomcat 7 0 33 as a web container 所以我的要求是tomcat中的每个应用程序都会password像受保护的manager applica
  • Java 和 Python 可以在同一个应用程序中共存吗?

    我需要一个 Java 实例直接从 Python 实例数据存储中获取数据 我不知道这是否可能 数据存储是否透明 唯一 或者每个实例 如果它们确实可以共存 都有其单独的数据存储 总结一下 Java 应用程序如何从 Python 应用程序的数据存
  • Eclipse 选项卡宽度不变

    我浏览了一些与此相关的帖子 但它们似乎并不能帮助我解决我的问题 我有一个项目 其中 java 文件以 2 个空格的宽度缩进 我想将所有内容更改为 4 空格宽度 我尝试了 正确的缩进 选项 但当我将几行修改为 4 空格缩进时 它只是将所有内容
  • 包 javax.el 不存在

    我正在使用 jre6 eclipse 并导入 javax el 错误 包 javax el 不存在 javac 导入 javax el 过来 这不应该是java的一部分吗 谁能告诉我为什么会这样 谢谢 米 EL 统一表达语言 是 Java
  • 在java中为组合框分配键

    我想添加一个JComboBox在 Swing 中这很简单 但我想为组合中的每个项目分配值 我有以下代码 JComboBox jc1 new JComboBox jc1 addItem a jc1 addItem b jc1 addItem
  • 使用 CXF-RS 组件时,为什么我们使用 而不是普通的

    作为后续这个问题 https stackoverflow com questions 20598199 对于如何正确使用CXF RS组件我还是有点困惑 我很困惑为什么我们需要
  • CamcorderProfile.videoCodec 返回错误值

    根据docs https developer android com reference android media CamcorderProfile html 您可以使用CamcorderProfile获取设备默认视频编解码格式 然后将其
  • 如何防止在Spring Boot单元测试中执行import.sql

    我的类路径中有一个 import sql 文件 其中包含一些 INSERT 语句 当使用 profile devel 运行我的应用程序时 它的数据被加载到 postgres 数据库中 到目前为止一切正常 当使用测试配置文件执行测试时 imp
  • Spring Rest 和 Jsonp

    我正在尝试让我的 Spring Rest 控制器返回jsonp但我没有快乐 如果我想返回 json 但我有返回的要求 完全相同的代码可以正常工作jsonp我添加了一个转换器 我在网上找到了用于执行 jsonp 转换的源代码 我正在使用 Sp

随机推荐

  • MFC Windows 程序设计(一)-程序员的解放

    MFC Windows 程序设计 一 程序员的解放 程序之美 很久很久以前 程序员是一个很辛苦的工作 因为那时候大多数的软件都是用C语言编写的 Microsoft Visual Basic还没有出现 更不要说现在的Java Android
  • Tomcat修改默认端口号

    1 背景 在默认情况下 tomcat的端口是8080 使用了两个tomcat 那么就需要修改其中的一个的端口号才能使得两个同时工作 2 方法 2 1改动一 那么 如何修改tomcat的端口号呢 首先到安装目录 或者解压目录 下找到conf文
  • VUE之Echarts图表x轴y轴提示文字过长处理为省略号

    只需对显示文字格式修改即可 yAxis type category axisLine show false 轴线 axisTick show false 去除刻度 axisLabel formatter function params co
  • silk lobe资源公众号_资源合集

    11 月 十一月 iOS内置韩文字体 Apple SD Gothic Neo 锤子 黑 Smartisan 与方正合作定制的UI黑体 Emoji 鸽了好久的可爱 Emoji 字体 移植到安卓手机 沙扬娜拉 岩田仿宋 复古聚珍仿宋风格 返璞归
  • chatgpt赋能python:Python如何优化中文SEO

    Python如何优化中文SEO Python 作为一种流行的编程语言 可以用来开发各种不同的应用程序 当涉及到网络营销和搜索引擎优化 SEO 时 Python的功能也非常有用 在本篇文章中 我们将介绍如何使用Python来优化中文SEO 以
  • opencv显示对比

    在opencv中我们一般都要展示处理前后图像的对比 有时候我们会imshow两次来展示两张图片 那为什么我们不放在一个图片里呢 这样显然是更加优雅的模式 上代码 Mat combineImage Mat before Mat after a
  • Go语言实现Onvif客户端:4、配置网络信息

    Go语言实现Onvif客户端 4 配置网络信息 文章目录 Go语言实现Onvif客户端 4 配置网络信息 1 思路 2 代码 上一节获取到网络接口token后 就可进行一些网络配置了 这里我们暂时只实现进行ip地址的配置接口和封装 1 思路
  • 【SpringCloud】pom.xml文件解析

    本文档为本人学习交流所用 参考原文档 https www cnblogs com hoyong articles 13034270 html 1 pom xml是什么 pom是Project Object Model 项目对象模型 的缩写
  • 虚表

    虚表 虚函数表 C 中 一个类存在虚函数 那么编译器就会为这个类生成一个虚函数表 在虚函数表里存放的是这个类所有虚函数的地址 虚表从属于类 编译器会为包含虚函数的类加上一个成员变量 该成员变量是一个指向虚函数表的指针 因此虚表指针是一个成员
  • UE4安卓打包配置(大陆内网络整顿后,Android打包时AndroidWorks无法使用的解决方法)

    由于国内进行了网络整顿 UE4官网上用CodeWorksforAndroid下载安卓打包工具配置的方法已经不能使用了 开了VPN也链接不上 这使得用UE4打包配置安卓游戏变得非常麻烦 博主捣鼓了好几天才打包成功 深感在中国学习UE4的艰难与
  • 力扣-图解算法数据结构-剑指 Offer 05. 替换空格

    题目要求 力扣题解 代码 program mydemo description 剑指 Offer 05 替换空格 author Mr zeng create 2021 03 05 11 04 public class Solution1 p
  • @escook/request-miniprogram基于 Promise 的小程序网路请求库

    安装 npm install escook request miniprogram 导入 按需导入 http 对象 import http from escook request miniprogram 将按需导入的 http 挂载到 wx
  • 静态资源存放的位置

    存放的四个位置 classpath META INF resources classpath resources classpath static classpath public 如果要访问的话 是当前项目的根路径 静态资源名 因为这个图
  • C#中浮点数的比较

    前几天去面试 被问到怎么比较两个浮点数的大小 当时只说了个大概 看得出来面试官不是太满意 回来特意查了一下 在MSDN上发现了比较浮点数是否相等的不错的方法 Initialize two doubles with apparently id
  • 接口测试用例设计 - 实战篇

    目录 一 接口测试流程 二 分析接口文档中哪些元素 三 如何设计接口测试用例 3 1 为什么要设计测试用例 3 2 设计接口测试用例从哪些方面考虑 四 常用的接口测试用例覆盖方法 五 接口测试的接口优先级 5 1 优先级 针对所有接口 5
  • MATLAB代码显示内存不足的解决方法

    总结了下大家对于运行MATLAB代码 显示内存不足的问题 在网上进行调研 总结如下 一般out of memenry存在以下几种情况 1 变量需要的存储空间超过了可用的内存空间 2 数据需要的存储空间 超过内存中最大的可用连续存储空间 3
  • 最大子列和问题【简单易懂】

    问题 给定N个整数的序列 求函数的最大值 算法一 例如序列为 1 2 3 4 所以子列分别为 1 1 2 1 2 3 1 2 3 4 2 2 3 2 3 4 3 3 4 4 我们要做的就是依次将这些子列的和求出并比较 得出最大子列和 首先将
  • 2020算法设计与分析 官方考前模拟卷 参考答案

    算法设计与分析 样例试题 算法设计与分析总结笔记 注 此试题仅供了解题型 和期末考试试题没有任何直接关系 FBI Warning 这套题难度较大 千万不要坏了心态 xj大佬说要是考试那么难他直播粪坑蝶泳 Power By 王宏志教授 5 分
  • matlab的tfdata函数_matlab 入门基本操作命令与函数

    一 tf 函数 是传递函数的意思 一般学自动控制原理的时候经常用 在s域中 比如你要输入G s 1 s 2 2s 1 就可以在matlab中输入G tf 1 1 2 1 就OK了 不懂的话你可以在command窗口输入help tf 就行了
  • 为什么使用start方法启动Java的Thread线程?

    一 简介 在Java代码当中 当我们需要开启子线程去处理一些任务的时候 往往是调用Thread对象的start方法 这样Thread实例中的Runnable对象的run方法就会在一个新的线程当中执行 创建一个线程 Thread thread