22.jdk源码阅读之Thread(上)

1. 写在前面

Java 中的 Thread 类是多线程编程的基础,也是我们日常工作中用的比较多的类,但是你真的了解它吗?下面这几个问题你是否有思考过?

  1. start() 和 run() 方法有什么区别?
  2. 什么是线程的生命周期?
  3. 什么是守护线程(Daemon Thread)?
  4. 如何中断线程?
  5. 什么是线程优先级?
  6. 什么是线程组(ThreadGroup)?
  7. 什么是线程本地变量(ThreadLocal)?
  8. 什么是死锁?如何避免

2. 全局视角

在这里插入图片描述

2.1 Runnable 接口

  • 定义了一个方法 run(),需要实现该接口的类提供具体的任务执行逻辑。
  • Thread 类通过实现 Runnable 接口,使得线程对象可以直接执行任务。
public interface Runnable {public abstract void run();
}

2.2 Thread 类的部分重要方法

  • start():启动线程,调用 run() 方法。
  • run():线程执行的任务逻辑,通常需要重写。
  • join():等待线程终止。
  • sleep(long millis):使当前线程休眠指定的毫秒数。
  • interrupt():中断线程。
  • isInterrupted():检查线程是否被中断。
  • setDaemon(boolean on):将线程设置为守护线程
  • getPriority() 和 setPriority(int newPriority):获取和设置线程的优先级。
  • getName() 和 setName(String name):获取和设置线程的名称。
  • getState():获取线程的状态。

2.3 Thread 类的构造方法

在这里插入图片描述

Thread 类提供了多种构造方法,以便灵活创建线程对象。常见的构造方法包括:

  • Thread()
  • Thread(Runnable target)
  • Thread(Runnable target, String name)
  • Thread(String name)
  • Thread(ThreadGroup group, Runnable target)
  • Thread(ThreadGroup group, Runnable target, String name)

下面我们来详细介绍下各个构造方法是如何使用的。

3. 从使用说起

3.1 无参构造方法

无参构造方法创建一个新的线程对象,但不指定任何任务或线程名称。

public class Main {public static void main(String[] args) {Thread thread = new Thread() {@Overridepublic void run() {System.out.println("Thread running using no-arg constructor");}};thread.start();}
}

3.2 使用 Runnable 作为参数的构造方法

这个构造方法接受一个实现了 Runnable 接口的对象作为参数,用于指定线程要执行的任务。

public class Main {public static void main(String[] args) {Runnable task = new Runnable() {@Overridepublic void run() {System.out.println("Thread running using Runnable constructor");}};Thread thread = new Thread(task);thread.start();}
}

3.3 使用 Runnable 和 String 作为参数的构造方法

这个构造方法接受一个实现了 Runnable 接口的对象和一个线程名称,用于指定线程要执行的任务和线程的名称。

public class Main {public static void main(String[] args) {Runnable task = new Runnable() {@Overridepublic void run() {System.out.println("Thread running using Runnable and String constructor");}};Thread thread = new Thread(task, "MyThread");thread.start();System.out.println("Thread Name: " + thread.getName());}
}

3.4 使用 String 作为参数的构造方法

这个构造方法接受一个线程名称,用于指定线程的名称。

public class Main {public static void main(String[] args) {Thread thread = new Thread("MyThread") {@Overridepublic void run() {System.out.println("Thread running using String constructor");}};thread.start();System.out.println("Thread Name: " + thread.getName());}
}

3.5 使用 ThreadGroup 和 Runnable 作为参数的构造方法

这个构造方法接受一个线程组和一个实现了 Runnable 接口的对象,用于指定线程所属的线程组和要执行的任务。

public class Main {public static void main(String[] args) {ThreadGroup group = new ThreadGroup("MyGroup");Runnable task = new Runnable() {@Overridepublic void run() {System.out.println("Thread running using ThreadGroup and Runnable constructor");}};Thread thread = new Thread(group, task);thread.start();System.out.println("Thread Group: " + thread.getThreadGroup().getName());}
}

3.6 使用 ThreadGroup, Runnable, 和 String 作为参数的构造方法

这个构造方法接受一个线程组、一个实现了 Runnable 接口的对象和一个线程名称,用于指定线程所属的线程组、要执行的任务和线程的名称。

public class Main {public static void main(String[] args) {ThreadGroup group = new ThreadGroup("MyGroup");Runnable task = new Runnable() {@Overridepublic void run() {System.out.println("Thread running using ThreadGroup, Runnable, and String constructor");}};Thread thread = new Thread(group, task, "MyThread");thread.start();System.out.println("Thread Group: " + thread.getThreadGroup().getName());System.out.println("Thread Name: " + thread.getName());}
}

3.7 使用 ThreadGroup, Runnable, String, 和 long 作为参数的构造方法

这个构造方法接受一个线程组、一个实现了 Runnable 接口的对象、一个线程名称和一个栈大小,用于指定线程所属的线程组、要执行的任务、线程的名称和线程的栈大小。

public class Main {public static void main(String[] args) {ThreadGroup group = new ThreadGroup("MyGroup");Runnable task = new Runnable() {@Overridepublic void run() {System.out.println("Thread running using ThreadGroup, Runnable, String, and long constructor");}};Thread thread = new Thread(group, task, "MyThread", 1024);thread.start();System.out.println("Thread Group: " + thread.getThreadGroup().getName());System.out.println("Thread Name: " + thread.getName());}
}

4. start()方法的底层源码

上面的使用中我们发现start()是用的比较多的一个方法,下面我们就深入看看它的源码实现,源码如下:

/*** Causes this thread to begin execution; the Java Virtual Machine* calls the <code>run</code> method of this thread.* <p>* The result is that two threads are running concurrently: the* current thread (which returns from the call to the* <code>start</code> method) and the other thread (which executes its* <code>run</code> method).* <p>* It is never legal to start a thread more than once.* In particular, a thread may not be restarted once it has completed* execution.** @exception  IllegalThreadStateException  if the thread was already*               started.* @see        #run()* @see        #stop()*/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();started = true;} finally {try {if (!started) {group.threadStartFailed(this);}} catch (Throwable ignore) {/* do nothing. If start0 threw a Throwable thenit will be passed up the call stack */}}}

start() 方法用于启动一个新线程,使其调用 run() 方法并在新的线程中执行。这个方法是线程启动的核心部分,确保线程正确地从 “NEW” 状态转变到 “RUNNABLE” 状态。下面是对这个方法的逐步解析:

4.1 方法签名

public synchronized void start() {
  • public:表示这个方法是公有的,可以从类的外部调用。
  • synchronized:表示这个方法是同步的,确保同一时间只有一个线程可以执行该方法,防止并发问题。

4.2 方法实现

    /*** 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".*/

这段注释说明了 start() 方法的一些背景信息:

  • 这个方法不会被主线程或由虚拟机创建的 “系统” 线程调用。
  • 任何将来添加到这个方法的新功能也可能需要添加到虚拟机中。
  • threadStatus 为 0 表示线程处于 “NEW” 状态。
    if (threadStatus != 0)throw new IllegalThreadStateException();
  • 这段代码检查线程的状态。如果 threadStatus 不是 0(即线程不是处于 “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);
  • 这段代码通知线程组(ThreadGroup)该线程即将启动。线程组会将该线程添加到其线程列表中,并减少未启动线程的计数。
    boolean started = false;try {start0();started = true;} finally {try {if (!started) {group.threadStartFailed(this);}} catch (Throwable ignore) {/* do nothing. If start0 threw a Throwable thenit will be passed up the call stack */}}
  • boolean started = false;:初始化一个布尔变量 started 为 false,用于跟踪线程是否成功启动。
  • start0();:调用本地方法 start0(),这是一个本地方法,用于启动新线程。start0() 是一个私有的本地方法,由 JVM 实现,用来执行底层的线程启动操作。
  • started = true;:如果 start0() 成功执行,将 started 设置为 true。

4.3 finally 块

  • finally 块确保在任何情况下都能执行清理操作。
  • 如果 start0() 方法抛出异常且 started 仍然为 false,则调用 group.threadStartFailed(this); 通知线程组线程启动失败。
  • catch (Throwable ignore):捕获所有异常,并忽略它们。这是为了确保如果 start0() 抛出异常,它会被传递到调用栈上,而不会被这个捕获块阻止。

5. run()方法

/*** If this thread was constructed using a separate* <code>Runnable</code> run object, then that* <code>Runnable</code> object's <code>run</code> method is called;* otherwise, this method does nothing and returns.* <p>* Subclasses of <code>Thread</code> should override this method.** @see     #start()* @see     #stop()* @see     #Thread(ThreadGroup, Runnable, String)*/@Overridepublic void run() {if (target != null) {target.run();}}

run()方法的源代码如上,看起来很简单,run() 方法是线程执行的入口点。当一个线程启动后,JVM 会调用该线程的 run() 方法。这个方法的默认实现检查线程是否有一个关联的 Runnable 对象,如果有,则调用该 Runnable 对象的 run() 方法。

5.1 方法签名和注释

/**
* If this thread was constructed using a separate
* <code>Runnable</code> run object, then that
* <code>Runnable</code> object's <code>run</code> method is called;
* otherwise, this method does nothing and returns.
* <p>
* Subclasses of <code>Thread</code> should override this method.
*
* @see     #start()
* @see     #stop()
* @see     #Thread(ThreadGroup, Runnable, String)
*/
@Override
public void run() {
  • 如果该线程是用一个单独的 Runnable 对象构造的,那么会调用这个 Runnable 对象的 run() 方法;否则,这个方法什么也不做,直接返回。
  • Thread 类的子类应该重写这个方法,以提供具体的执行逻辑。
  • 提供了一些相关方法的链接,包括 start()、stop() 和 Thread(ThreadGroup, Runnable, String)。

5.2 方法实现

    if (target != null) {target.run();}
}
  • if (target != null)

    • 检查 target 是否为 null。target 是一个 Runnable 对象,表示线程要执行的任务。
    • target 是 Thread 类的一个实例变量,当使用 Thread(Runnable target) 构造方法创建线程时,会将传入的 Runnable 对象赋值给 target。
  • target.run()

    • 如果 target 不为 null,则调用 target 的 run() 方法。这意味着如果线程是用一个 Runnable 对象创建的,那么实际执行的是这个 Runnable 对象的 run() 方法
    • 如果 target 为 null,则什么也不做,直接返回

5.3 例子

下面是一个使用 Thread 类和 Runnable 接口的示例,展示了如何使用 run() 方法:

5.3.1 使用 Runnable 接口

public class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("Runnable run method executed.");}
}public class Main {public static void main(String[] args) {MyRunnable myRunnable = new MyRunnable();Thread thread = new Thread(myRunnable);thread.start(); // This will call myRunnable's run() method}
}

在这个例子中,MyRunnable 实现了 Runnable 接口,并重写了 run() 方法。创建 Thread 对象时,将 MyRunnable 对象传递给 Thread 的构造方法。调用 thread.start() 时,最终会调用 MyRunnable 对象的 run() 方法。

5.3.2 继承 Thread 类

public class MyThread extends Thread {@Overridepublic void run() {System.out.println("Thread run method executed.");}
}public class Main {public static void main(String[] args) {MyThread myThread = new MyThread();myThread.start(); // This will call MyThread's run() method}
}

在这个例子中,MyThread 继承了 Thread 类,并重写了 run() 方法。创建 MyThread 对象并调用 myThread.start() 时,会执行 MyThread 类的 run() 方法。

系列文章

1.JDK源码阅读之环境搭建

2.JDK源码阅读之目录介绍

3.jdk源码阅读之ArrayList(上)

4.jdk源码阅读之ArrayList(下)

5.jdk源码阅读之HashMap

6.jdk源码阅读之HashMap(下)

7.jdk源码阅读之ConcurrentHashMap(上)

8.jdk源码阅读之ConcurrentHashMap(下)

9.jdk源码阅读之ThreadLocal

10.jdk源码阅读之ReentrantLock

11.jdk源码阅读之CountDownLatch

12.jdk源码阅读之CyclicBarrier

13.jdk源码阅读之Semaphore

14.jdk源码阅读之线程池(上)

15.jdk源码阅读之线程池(下)

16.jdk源码阅读之ArrayBlockingQueue

17.jdk源码阅读之LinkedBlockingQueue

18.jdk源码阅读之CopyOnWriteArrayList

19.jdk源码阅读之FutureTask

20.jdk源码阅读之CompletableFuture

21.jdk源码阅读之AtomicLong

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3269737.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

邮件攻击案例系列三:动态 IP 池爆破员工邮箱钓鱼重要客户

案例描述 2023 年 11 月&#xff0c;某制造业企业员工 Emily 接到海外客户电话&#xff0c;向其核实一封电子邮件的真实性&#xff0c;因为客户认为&#xff0c;该邮件所给出的链接不像是该公司的官网网址。Emily 查看自己的邮箱&#xff0c;并未发现客户所说的邮件。但从客户…

RPA:如何一次回答多个问题

洞悉技术的本质&#xff0c;享受科技的乐趣 先完成10%目标&#xff0c;迈出100%之一行动 2分钟的努力也有价值 从每天解决1个小问题开始。 本文介绍如何使用playwright来处理新页面 三句话说清楚问题 一天回答一个问题太慢了&#xff0c;我想一天回答 3个问题 了解基本原理 新页…

YOLOv5改进 | 卷积模块 | 即插即用的递归门控卷积gnConv

秋招面试专栏推荐 &#xff1a;深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 &#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 专栏目录&#xff1a; 《YOLOv5入门 改…

概率模拟(sigmoid、softmax)

概率模拟&#xff08;sigmoid、softmax&#xff09; 1. sigmoid1.1 sigmoid 定义1.2 sigmoid 主要特性1.3 sigmoid 的缺点1.4 代码画 sigmoid 函数图像 2. softmax2.1 softmax 定义与原理2.2 softmax 特点与优势2.3 softmax 应用场景2.4 softmax 实现方式2.5 softmax 注意事项2…

C++从入门到起飞之——友元内部类匿名对象 全方位剖析!

&#x1f308;个人主页&#xff1a;秋风起&#xff0c;再归来~&#x1f525;系列专栏&#xff1a;C从入门到起飞 &#x1f516;克心守己&#xff0c;律己则安 目录 1、友元 2、内部类 3. 匿名对象 4、完结散花 1、友元 • 友元提供了⼀种突破类访问限定符封装的…

在 Jetpack Compose 中使用 CameraX示例

在使用Jetpack Compose开发安卓应用&#xff0c;当在学习使用CameraX组件时发现官方提供的教程不是Compose的。教程地址如下&#xff1a; https://developer.android.com/codelabs/camerax-getting-started?hlzh-cn#1 与是我就记录一下&#xff0c;简单的示例。 内容参考&…

吴恩达的TranslationAgent学习

TranslationAgent构成 整个[TranslationAgent (github.com)]在流程上分为短文本的一次性翻译和长文本的分chunk翻译&#xff08;按照Token进行划分&#xff09;。 但是不论长文本翻译还是短文本翻译&#xff0c;总体流程遵循执行、纠正再执行的逻辑循环实现。 这种按照自省思路…

基于JSP的电子商城系统

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;JSPJavaB/S架构 工具&#xff1a;Eclipse、Tomcat 系统展示 首页 管理员功能界面 用户功能界面 医…

Kylin 入门教程

Apache Kylin 是一个开源的分布式数据仓库和 OLAP(在线分析处理)引擎,旨在提供亚秒级查询响应时间,即使在处理超大规模数据集时也是如此。Kylin 可以有效地将原始数据预计算为多维数据立方体(Cube),并利用这些预计算结果来提供快速查询。本文将带你从基础知识到操作实践…

项目管理工具-Maven-创建一个mavenweb项目

文章目录 IDEA开发maven项目依赖范围 IDEA开发maven项目 点击NewProject&#xff0c;填写项目名字Name为javaWeb-maven&#xff0c;填写项目的存储地址&#xff0c;选择Archetype为org.apache.maven.archetypes:maven-archetype-webapp&#xff0c;然后再点击Create&#xff0…

Android WebViewClient 的 `shouldOverrideUrlLoading` 方法

简介 在Android开发中&#xff0c;WebView是一个强大的工具&#xff0c;可以在你的应用中显示网页内容。了解 WebViewClient 中的 shouldOverrideUrlLoading 方法是至关重要的&#xff0c;因为这个方法允许你控制 URL 在 WebView 中的处理方式。 在本文中&#xff0c;我们将详…

基于FFmpeg和SDL的音视频解码播放的实现过程与相关细节

目录 1、视频播放器原理 2、FFMPEG解码 2.1 FFMPEG库 2.2、数据类型 2.3、解码 2.3.1、接口函数 2.3.2、解码流程 3、SDL播放 3.1、接口函数 3.2、视频播放 3.3、音频播放 4、音视频的同步 4.1、获取音频的播放时间戳 4.2、获取当前视频帧时间戳 4.3、获取视…

OZON打开哈萨克斯坦市场,OZON测试开通哈萨克斯坦市场中国产品

在全球化日益深入的今天&#xff0c;跨境电商成为了连接不同国家和地区消费者的重要桥梁。2024年7月26日&#xff0c;Ozon Global宣布了一项重大扩展计划&#xff0c;正式将中国卖家的销售版图拓展至哈萨克斯坦市场&#xff0c;为中国企业打开了新的增长机遇之门。 OZON哈萨克斯…

实现共模噪声电流相互抵消的方法

共模传导路径中噪声电流相互抵消&#xff0c;从而使总的共模电流减小&#xff0c; 终达到降噪的目的。目前为实现共模噪声电流相互抵消&#xff0c;主要是采用动点电容抵消法。 动点电容抵消法原理 动点电容抵消法就是选取合适的动点&#xff0c;添加原副边跨接电容&#xff0c…

【Leetcode】二十、记忆化搜索:零钱兑换

文章目录 1、记忆化搜索2、leetcode509&#xff1a;斐波那契数列3、leetcode322&#xff1a;零钱兑换 1、记忆化搜索 也叫备忘录&#xff0c;即把已经计算过的结果存下来&#xff0c;下次再遇到&#xff0c;就直接取&#xff0c;不用重新计算。目的是以减少重复计算。 以前面提…

深度强化学习 ②(DRL)

参考视频&#xff1a;&#x1f4fa;王树森教授深度强化学习 前言&#xff1a; 最近在学习深度强化学习&#xff0c;学的一知半解&#x1f622;&#x1f622;&#x1f622;&#xff0c;这是我的笔记&#xff0c;欢迎和我一起学习交流~ 这篇博客目前还相对比较乱&#xff0c;后面…

【算法刷题】【力扣】| 最长回文子串|

给你一个字符串 s&#xff0c;找到 s 中最长的 示例 1&#xff1a; 输入&#xff1a;s "babad" 输出&#xff1a;"bab" 解释&#xff1a;"aba" 同样是符合题意的答案。示例 2&#xff1a; 输入&#xff1a;s "cbbd" 输出&#x…

全网最最实用--模型高效推理:量化基础

文章目录 一、量化基础--计算机中数的表示1. 原码&#xff08;Sign-Magnitude&#xff09;2. 反码&#xff08;Ones Complement&#xff09;3. 补码&#xff08;Twos Complement&#xff09;4. 浮点数&#xff08;Floating Point&#xff09;a.常用的浮点数标准--IEEE 754(FP32…

如何利用业余时间做副业,在家里赚钱,来增加收入

人一生每个阶段都会有压力和烦恼&#xff0c;中年人更是如此。 上有老下有小&#xff0c;生活的重担都在一个人身上&#xff0c;压得人喘不过气&#xff0c;这些都需要钱&#xff0c;仅靠工资已经很难维持一家人的开支了。 所以很多人打算利用业余时间做副业&#xff0c;来增加…

几个小创新模型,Transformer与SVM、LSTM、BiLSTM、Adaboost的结合,MATLAB分类全家桶再更新!...

截止到本期MATLAB机器学习分类全家桶&#xff0c;一共发了5篇&#xff0c;参考文章如下&#xff1a; 1.机器学习分类全家桶&#xff0c;模式识别&#xff0c;故障诊断的看这一篇绝对够了&#xff01;MATLAB代码 2. 再更新&#xff0c;机器学习分类全家桶&#xff0c;模式识别&a…