第2章 深入理解Thread构造函数

devtools/2025/2/26 1:24:44/

Thread的构造函数。
![[Pasted image 20241206152027.png]]

2.1 线程的命名


在构造一个Thread时可以为其命名。

2.1.1 线程的默认命名


下面构造函数中,并没有为线程命名。

java">Thread()
Thread(Runnable target)
Thread(ThreadGroup group, Runnable target)

打开源码会看到

java">public Thread(Runnable target) {  this(null, target, "Thread-" + nextThreadNum(), 0);  
}private static int threadInitNumber;  private static synchronized int nextThreadNum() {  return threadInitNumber++;  
}

故对于没有命名的线程的名字会以"Thread-"开头,后面的数字依次递增。

java">public static void defaultName() {  Runnable runnable = () -> System.out.println(Thread.currentThread().getName());  // 将会创建三个线程并调用其start方法  IntStream.rangeClosed(1, 3).boxed().map(x -> runnable).map(Thread::new).forEach(Thread::start);  
}
输出 : 
Thread-1
Thread-0
Thread-2

2.1.2 命名线程


下面的构造方法可以在创建一个Thread时为其命名。

java">Thread(String name)
Thread(ThreadGroup group, Runnable target)
Thread(ThreadGroup group, Runnable target, String name)
Thread(ThreadGroup group, Runnable target, String name, long stackSize)
Thread(ThreadGroup group, Runnable target, String name, long stackSize,
boolean inheritThreadLocals)
Thread(ThreadGroup group, String name)
java">public static Runnable runnable = () -> System.out.println(Thread.currentThread().getName());  
public static List<String> list = Arrays.asList("anan", "jcjc", "yryr", "mymy");public static void assignName() {  IntStream.rangeClosed(0, 3).boxed().map(list::get).map(threadName -> new Thread(runnable, threadName)).forEach(Thread::start);  
}
输出 : 
anan
jcjc
yryr
mymy

2.1.3 修改线程的名字


在线程启动之前,你可以更改线程的名字,但调用之后就不能更改了。
这是setName的源码

java">public final synchronized void setName(String name) {  checkAccess();  if (name == null) {  throw new NullPointerException("name cannot be null");  }  this.name = name;  if (threadStatus != 0) { // 线程不是NEW状态对其的修改不会生效  setNativeName(name);  }
}

2.2 线程的父子关系


  • 一个线程的创建肯定是由另一个线程完成的
  • 被创建的线程的父线程就是创建这个线程的线程。
java">例如在main线程中创建了一个线程x,那么x的父线程就是main线程

2.3 Thread与ThreadGroup


在线程的构造函数可以显式地指定线程的Group,也就是ThreadGroup
如果在构造一个线程时没有指定它的Group,那么会加入到父线程的Group

java">public static Runnable runnable2 = () -> System.out.println(Thread.currentThread().getThreadGroup().getName());
public static void defaultThreadGroup() {  // 创建一个线程  Thread thread = new Thread(runnable2, "mymy");  ThreadGroup group = new ThreadGroup("yjyj");  Thread thread1 = new Thread(group, runnable2, "jcjc");  thread.start();  thread1.start();  
}
输出 : 
main
yjyj

2.4 Thread和Runnable


Thread负责线程本身相关的职责和控制,而Runnable则负责逻辑执行单元的部分。

2.5 Thread与JVM虚拟机栈


。。。 这段太抽象了

2.5.1 Thread与Stacksize


2.5.2 JVM内存结构


JVM在执行Java程序的时候会把对应的物理内存划分成不同的内存区域,每一个区域都存放着不同数据,也有不同的创建与销毁时机,有些分区会在JVM启动时就创建,有些则是在运行时才创建。

![[Pasted image 20241206162347.png]]

  • 程序计数器
    程序计数器在JVM中所起的作用就是用于存放当前线程接下来将要执行的字节码指令、分支、循环、跳转、异常处理等信息。
  • Java虚拟机栈
    Java虚拟机栈也是线程私有的,它的生命周期与线程相同,是在JVM运行时所创建的,在线程中,方法在执行的时候都会创建一个名为栈帧(stack frame)的数据结构,主要用于存放局部变量表、操作栈、动态链接、方法出口等信息。
    ![[Pasted image 20241206162917.png]]

方法的调用是栈帧被压入和弹出的过程。同等的虚拟机栈如果局部变量表等占用内存
越小则可被压入的栈帧就会越多,反之则可被压入的栈帧就会越少,一般将栈帧内存的大小称为宽度,而栈帧的数量则称为虚拟机栈的深度。

  • 本地方法栈
    Java中提供了调用本地方法的接口(Java NativeInterface),也就是C/C++程序,在线程的执行过程
    中,经常会碰到调用JNI方法的情况,比如网络通信、文件操作的底层,甚至是String的intern等都是JNI方法,JVM为本地方法所划分的内存区域便是本地方法栈,这块内存区域其自由度非常高,完全靠不同的JVM厂商来实现,Java虚拟机规范并未给出强制的规定,同样它也是线程私有的内存区域。
  • 堆内存
    堆内存是JVM中最大的一块内存区域,被所有的线程所共享,Java在运行期间创建的所有对象几乎都存放在该内存区域,该内存区域也是垃圾回收器重点照顾的区域,因此有些时候堆内存被称为“GC堆”。
  • 方法区
    方法区也是被多个线程所共享的内存区域,他主要用于存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器(JIT)编译后的代码等数据。

2.5.3 Thread与虚拟机栈


2.6 守护线程


守护线程是一类比较特殊的线程,一般用于处理一些后台的工作。

2.6.1 什么是守护线程


java">public static Runnable runnable3 = () -> {  while (true) {  System.out.println("haha");  sleep(1);  }  
};public static void deamonThread() {  System.out.println(Thread.currentThread().getName());  Thread thread = new Thread(runnable3);  thread.setDaemon(true); // 将其设置为守护线程  thread.start(); // 启动线程  
}

main线程

java">deamonThread();  
sleep(1);
输出 : 
main
haha
haha

当main线程退出后,守护线程也随之自动关闭了。
如果父线程为守护线程那么子线程也为守护线程。

2.6.2 守护线程的作用


守护线程经常用作与执行一些后台任务,因此有时它也被称为后台线程,当你希望关闭某些线程的时候,或者退出JVM进程的时候,一些线程能够自动关闭,此时就可以考虑用守护线程为你完成这样的工作。

2.7 本章总结



http://www.ppmy.cn/devtools/162690.html

相关文章

【NLP算法面经】腾讯、头条算法岗详细面经(★附面题整理★)

【NLP算法面经】腾讯、头条算法岗详细面经&#xff08;★附面题整理★&#xff09; &#x1f31f; 嗨&#xff0c;你好&#xff0c;我是 青松 &#xff01; &#x1f308; 自小刺头深草里&#xff0c;而今渐觉出蓬蒿。 NLP Github 项目推荐&#xff1a; 【AI 藏经阁】&#xf…

Lecture 2 - Python

一、Python的执行方式 1. Executable file&#xff08;可执行文件&#xff09;&#xff1a;生成可以直接运行的程序。&#xff08;经过编译的程序&#xff09; 2. Interpreter&#xff08;解释器&#xff09;&#xff1a;Python 使用解释器逐行执行代码&#xff0c;而不是通过…

Element UI中messageBox怎么区分点击取消按钮关闭弹窗,和点击右上角x号以及点击遮罩层关闭按钮

在某些场景下&#xff0c;我们可能需要区分点击取消按钮关闭 messageBox 和点击X号、遮罩层关闭 messageBox 。 实现&#xff1a; 将 distinguishCancelAndClose 设置为 true&#xff0c;这个属性的意思是&#xff1a;是否将取消&#xff08;点击取消按钮&#xff09;与关闭&…

python和pycharm 和Anaconda的关系

好的&#xff0c;下面我会详细说明 Python、PyCharm 和 Anaconda 三者的关系&#xff0c;并逐一解释它们的功能和作用。 1. Python&#xff08;编程语言&#xff09; 定义&#xff1a;Python 是一种高级编程语言&#xff0c;设计简洁&#xff0c;易于学习&#xff0c;且功能强…

FPGA中利用fifo时钟域转换---慢时钟域转快时钟域

FPGA中利用fifo时钟域转换—慢时钟域转快时钟域 一、时间计算方法 FIFO的输入数据的时钟是40MHz&#xff0c;FIFO输出数据取60MHz&#xff0c;刚好是40MHz的1.5倍&#xff0c;将慢时钟域转快时钟域。另外&#xff0c;fifo输出的数据&#xff0c;要输出给上位机&#xff0c;一…

postgresql链接详解

PostgreSQL连接概述 连接基础 在探讨PostgreSQL连接的基础之前&#xff0c;我们需要理解什么是数据库连接。 数据库连接 是客户端应用程序与数据库服务器之间建立的一种通信通道&#xff0c;使用户能够访问和操作数据库中的数据。 PostgreSQL连接涉及以下几个关键要素&#…

Redis 存在线程安全问题吗?为什么?

Redis线程安全问题解析&#xff1a;从基础到深入 前言 Redis 是一种高性能的内存键值数据库&#xff0c;广泛应用于缓存、消息队列等多种场景。在高并发和分布式环境下&#xff0c;程序的线程安全问题尤为关键。许多开发者都会问&#xff1a;Redis 是否存在线程安全问题&#x…

C++ openssl AES/CBC/PKCS7Padding 256位加密 解密示例 MD5示例

C openssl AES/CBC/PKCS7Padding 256位加密 解密示例 加密 为了确保 AES 加密使用 AES/CBC/PKCS7Padding&#xff0c;我们需要确保在加密过程中正确处理填充。OpenSSL 的 AES_cbc_encrypt 函数并不自动处理填充&#xff0c;因此我们需要手动实现 PKCS7 填充。 以下是更新后…