我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java线程中start方法如何回调run方法

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java线程中start方法如何回调run方法

小编给大家分享一下Java线程中start方法如何回调run方法,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

Java 创建线程的方法

实际上,创建线程最重要的是提供线程函数(回调函数),该函数作为新创建线程的入口函数,实现自己想要的功能。Java 提供了两种方法来创建一个线程:

继承 Thread 类

class MyThread extends Thread{  public void run() {   System.out.println("My thread is started.");  } }

实现该继承类的 run 方法,然后就可以创建这个子类的对象,调用 start 方法即可创建一个新的线程:

MyThread myThread = new MyThread(); myThread.start();

实现 Runnable 接口

class MyRunnable implements Runnable{  public void run() {   System.out.println("My runnable is invoked.");  } }

实现 Runnable 接口的类的对象可以作为一个参数传递到创建的 Thread 对象中,同样调用 Thread#start 方法就可以在一个新的线程中运行 run 方法中的代码了。

Thread myThread = new Thread( new MyRunnable()); myThread.start();

可以看到,不管是用哪种方法,实际上都是要实现一个 run 方法的。 该方法本质是上一个回调方法。由 start 方法新创建的线程会调用这个方法从而执行需要的代码。 从后面可以看到,run 方法并不是真正的线程函数,只是被线程函数调用的一个 Java 方法而已,和其他的 Java 方法没有什么本质的不同。

Java 线程的实现

从概念上来说,一个 Java 线程的创建根本上就对应了一个本地线程(native thread)的创建,两者是一一对应的。 问题是,本地线程执行的应该是本地代码,而 Java 线程提供的线程函数是 Java 方法,编译出的是 Java 字节码,所以可以想象的是, Java 线程其实提供了一个统一的线程函数,该线程函数通过 Java 虚拟机调用 Java 线程方法 , 这是通过 Java 本地方法调用来实现的。

以下是 Thread#start 方法的示例:

public synchronized void start() {  … start0();  …}

可以看到它实际上调用了本地方法 start0, 该方法的声明如下:

private native void start0();

Thread 类有个 registerNatives 本地方法,该方法主要的作用就是注册一些本地方法供 Thread 类使用,如 start0(),stop0() 等等,可以说,所有操作本地线程的本地方法都是由它注册的 . 这个方法放在一个 static 语句块中,这就表明,当该类被加载到 JVM 中的时候,它就会被调用,进而注册相应的本地方法。

private static native void registerNatives(); static{  registerNatives(); }

本地方法 registerNatives 是定义在 Thread.c 文件中的。Thread.c 是个很小的文件,定义了各个操作系统平台都要用到的关于线程的公用数据和操作,如代码清单 1 所示。

清单1

JNIEXPORT void JNICALL Java_Java_lang_Thread_registerNatives (JNIEnv *env, jclass cls){  (*env)->RegisterNatives(env, cls, methods, ARRAY_LENGTH(methods)); } static JNINativeMethod methods[] = {  {"start0", "()V",(void *)&JVM_StartThread},  {"stop0", "(" OBJ ")V", (void *)&JVM_StopThread},  {"isAlive","()Z",(void *)&JVM_IsThreadAlive},  {"suspend0","()V",(void *)&JVM_SuspendThread},  {"resume0","()V",(void *)&JVM_ResumeThread},  {"setPriority0","(I)V",(void *)&JVM_SetThreadPriority},  {"yield", "()V",(void *)&JVM_Yield},  {"sleep","(J)V",(void *)&JVM_Sleep},  {"currentThread","()" THD,(void *)&JVM_CurrentThread},  {"countStackFrames","()I",(void *)&JVM_CountStackFrames},  {"interrupt0","()V",(void *)&JVM_Interrupt},  {"isInterrupted","(Z)Z",(void *)&JVM_IsInterrupted},  {"holdsLock","(" OBJ ")Z",(void *)&JVM_HoldsLock},  {"getThreads","()[" THD,(void *)&JVM_GetAllThreads},  {"dumpThreads","([" THD ")[[" STE, (void *)&JVM_DumpThreads}, };

到此,可以容易的看出 Java 线程调用 start 的方法,实际上会调用到 JVM_StartThread 方法,那这个方法又是怎样的逻辑呢。实际上,我们需要的是(或者说 Java 表现行为)该方法最终要调用 Java 线程的 run 方法,事实的确如此。 在 jvm.cpp 中,有如下代码段:

JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread))  … native_thread = new JavaThread(&thread_entry, sz);

**这里JVM_ENTRY是一个宏,用来定义**JVM_StartThread 函数,可以看到函数内创建了真正的平台相关的本地线程,其线程函数是 thread_entry,如清单 2 所示。

清单2

static void thread_entry(JavaThread* thread, TRAPS) {  HandleMark hm(THREAD);  Handle obj(THREAD, thread->threadObj());  JavaValue result(T_VOID);  JavaCalls::call_virtual(&result,obj,  KlassHandle(THREAD,SystemDictionary::Thread_klass()),  vmSymbolHandles::run_method_name(), vmSymbolHandles::void_method_signature(),THREAD); }

可以看到调用了 vmSymbolHandles::run_method_name 方法,这是在 vmSymbols.hpp 用宏定义的:

class vmSymbolHandles: AllStatic {  … template(run_method_name,"run")  …}

至于 run_method_name 是如何声明定义的,因为涉及到很繁琐的代码细节,本文不做赘述。感兴趣的读者可以自行查看 JVM 的源代码。

图. Java 线程创建调用关系图

Java线程中start方法如何回调run方法

start() 创建新进程
run() 没有

PS:下面看下Java线程中run和start方法的区别

Thread类中run()和start()方法的区别如下:

run()方法:在本线程内调用该Runnable对象的run()方法,可以重复多次调用;

start()方法:启动一个线程,调用该Runnable对象的run()方法,不能多次启动一个线程;

package com.ljq.test;public class ThreadTest {    public static void main(String[] args){    Thread thread=new ThreadDemo();    //第一种    //表明: run()和其他方法的调用没任何不同,main方法按顺序执行了它,并打印出最后一句    //thread.run();    //第二种    //表明: start()方法重新创建了一个线程,在main方法执行结束后,由于start()方法创建的线程没有运行结束,    //因此主线程未能退出,直到线程thread也执行完毕.这里要注意,默认创建的线程是用户线程(非守护线程)    //thread.start();    //第三种    //1、为什么没有打印出100句呢?因为我们将thread线程设置为了daemon(守护)线程,程序中只有守护线程存在的时候,是可以退出的,所以只打印了七句便退出了    //2、当java虚拟机中有守护线程在运行的时候,java虚拟机会关闭。当所有常规线程运行完毕以后,    //守护线程不管运行到哪里,虚拟机都会退出运行。所以你的守护线程最好不要写一些会影响程序的业务逻辑。否则无法预料程序到底会出现什么问题    //thread.setDaemon(true);    //thread.start();    //第四种    //用户线程可以被System.exit(0)强制kill掉,所以也只打印出七句    thread.start();    System.out.println("main thread is over");    System.exit(1);  }  public static class ThreadDemo extends Thread{    @Override    public void run() {      for (int i = 0; i < 100; i++) {        System.out.println("This is a Thread test"+i);      }    }  }}

以上是“Java线程中start方法如何回调run方法”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网行业资讯频道!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java线程中start方法如何回调run方法

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java线程中start方法如何回调run方法

小编给大家分享一下Java线程中start方法如何回调run方法,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!Java 创建线程的方法实际上,创建线程最重要的是提
2023-05-30

Java多线程启动为什么调用的是start()方法而不是run() 方法

这篇文章主要讲解了“Java多线程启动为什么调用的是start()方法而不是run() 方法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java多线程启动为什么调用的是start()方法而
2023-06-16

Java中如何启动线程start和run

这篇文章将为大家详细讲解有关Java中如何启动线程start和run,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一、区别Java中启动线程有两种方法,继承Thread类和实现Runnable接口,由于J
2023-05-30

java中start方法与run方法有什么区别

本篇文章给大家分享的是有关java中start方法与run方法有什么区别,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Java有哪些集合类Java中的集合主要分为四类:1、Li
2023-06-14

Java多线程run方法中怎么直接调用service业务类

这篇文章主要介绍“Java多线程run方法中怎么直接调用service业务类”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java多线程run方法中怎么直接调用service业务类”文章能帮助大家解
2023-07-02

Java多线程回调方法实例解析

所谓回调,就是客户程序C调用服务程序S中的某个方法A,然后S又在某个时候反过来调用C中的某个方法B,对于C来说,这个B便叫做回调方法。下面看一个实际例子来理解:本示例设置一个提问者,一个回答者,而回答者需要回答提问者一个很深奥的问题时,这时
2023-05-30

Java多线程run方法中直接调用service业务类应注意的问题

在Java多线程的run方法中直接调用service业务类时,需要注意以下几个问题:1. 线程安全:确保业务类中的方法是线程安全的,即多个线程同时调用该方法时,不会出现数据竞争或者数据不一致的情况。可以通过使用synchronized关键字
2023-08-09

在JAVA中如何调用方法

在Java语言中方法调用的语法格式:对象变量名.方法名(实参列表);其中,圆括号中的“实参列表”为调用方法时实际传入的实际参数,称为实参列表。声明方法时圆括号中的参数称为形式参数,形式参数和实际参数在数据类型和个数上一定要匹配。例如:类Addition声明了方
在JAVA中如何调用方法
2021-03-31

如何在Java中调用jython方法

如何在Java中调用jython方法?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。1 什么是jython? 他其实是一门语言,并非是Java 或者Python的解释器.用它
2023-05-31

java中静态方法如何调用

在Java中,可以通过以下两种方式来调用静态方法:1. 使用类名调用静态方法:可以直接通过类名来调用静态方法,不需要创建类的实例。语法为:`类名.静态方法名(参数列表)`。示例如下:```javapublic class MyClass {
2023-09-14

java如何调用js方法

js方法如下:function add(a,b){return a + b + number;}调用方法如下:(免费学习视频教程分享:java视频教程)package com.cgnb.dataqualitymng; import java.io.FileRe
java如何调用js方法
2017-05-25

java如何调用类方法

要调用类方法,可以使用类名直接调用方法,而不需要创建类的实例对象。例如,假设有一个类名为MathUtils,其中有一个静态方法add(),可以直接通过类名调用该方法:```public class MathUtils {public sta
2023-08-18

Java线程的调度与优先级方法

今天小编给大家分享一下Java线程的调度与优先级方法的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。由于CPU的计算频率非常高
2023-06-29

Java中的闭包与回调方法分析

本篇内容介绍了“Java中的闭包与回调方法分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!闭包是一个可调用的对象,它记录了一些信息,这些信
2023-06-17

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录