网站首页 > java教程 正文
在上篇文章中我们提到在Thread构造函数中可以显式的指定线程名,其实在线程的构造函数中不但可以指定线程名,还可以指定线程组,也就是前面提到的参数中的ThreadGroup。在之前的分享中,我们提到一个概念,就是在调用了线程的构造方法之后,都会调用其中的一个init()方法。这里我们就从init()方法入手来进行分析。
Thread 与ThreadGroup
在init()方法中有如下的一段代码。
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) {
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();
}
}
通过上面代码,我们可以知道,如果在Thread构造函数中没有指定ThreadGroup,那么子线程就会被加入到父线程所在的线程组。通过如下的测试代码来看一下这其中的关系。
public class ThreadConstruction {
public static void main(String[] args){
Thread t1 = new Thread("T1");
ThreadGroup group = new ThreadGroup("TestGroup");
Thread t2 = new Thread(group,"T2");
ThreadGroup mainThreadGroup = Thread.currentThread().getThreadGroup();
System.out.println("主线程所属的线程组是:"+mainThreadGroup.getName());
System.out.println("T1 线程和 主线程 是否属于同一组 "+(mainThreadGroup==t1.getThreadGroup()));
System.out.println("T2 线程和 主线程 是否属于同一组 "+(mainThreadGroup==t2.getThreadGroup()));
System.out.println("T2 线程和 group 是否属于同一组 "+(group==t2.getThreadGroup()));
}
}
从上面代码可以看出,先创建了一个Thread t1 的线程,在创建了一个ThreadGroup对象,创建了一个Thread t2 的线程,并且将其加入到了group中。并没有给T1指定任何的group。执行上面的代码运行结果如下图所示。
从上面的结果,我们可以得到如下的几个结论
- main函数所在的线程组被称为是主线程组
- 构造线程的时候如果没有指定线程组,那么它的线程组与父线程同在同一个线程组。
在默认设置中,子线程和父线程都属于同一个线程组,并且还会与父线程拥有同样的优先级。这个会在后续的分享中进行详细的介绍。
Thread 和 StackSize的关系
在Thread的构造函数中,有一个被我们忽略的参数stackSize,这个参数到底是干什么用的,它对线程的影响到底是什么样的呢?,接下来就来看一下这个问题。
一般情况下,线程在创建的时候使用者其实并不会手动指定栈内存地址,而通过XSS参数进行设置。通过查找资料不难发现stackSize越大就表示正在线程内方法调用的递归深度就越大。stackSize越小则代表创建线程数越多。当然这个也是因平台而异的。
在有些平台下,将stack设置得越高,可以允许递归的深度就越深,反之,设置越低则表示,能够允许递归的深度就越浅。当然在某些平台下这些参数的设置根本就不起任何作用。只是给了开发者一个心理安慰,测试代码如下
public class ThreadConstruction {
public static void main(String[] args) {
ThreadGroup group = new ThreadGroup("TestGroup");
Runnable runnable = new Runnable() {
final int MAX = Integer.MAX_VALUE;
@Override
public void run() {
int i = 0;
recurse(i);
}
private void recurse(int i){
System.out.println(i);
if (i<MAX){
recurse(i+1);
}
}
};
Thread thread = new Thread(group,runnable,"Test",Integer.parseInt("1"));
thread.start();
}
}
Thread 与 虚拟机栈
我们之前了解过,在JVM内存中,程序计数器是一块比较小的内存空间,这个部分的内存不会出现任何溢出现象的。在所有内存空间区域中,与线程的创建、运行、销毁等一系列操作有关系的就是虚拟机栈内存了。栈内存的大小直接决定了JVM中可以被创建多少个线程。代码如下
public class ThreadCounter extends Thread {
final static AtomicInteger counter = new AtomicInteger(0);
public static void main(String[] args) {
try {
while (true){
new ThreadCounter().start();
}
}catch (Throwable e){
System.out.println("failed At => "+counter.get());
}
}
@Override
public void run() {
try {
System.out.println("The "+counter.getAndIncrement()+"thread be created.");
TimeUnit.MINUTES.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
从代码中可以知道,我们一直创建线程移植到JVM不能在为线程分配空间为止。这样就可以测试出来栈内存空间大小对于线程分配的影响。
通过图表可以分析出来,线程数量与虚拟机栈空间大小的一种变化影响规律。
总结
在JVM中到底能创建多少线程,与堆内存、栈内存的大小有着直接的关系。
猜你喜欢
- 2025-01-05 Java高并发编程-线程入门
- 2025-01-05 tomcat8.5配置高并发
- 2025-01-05 Java编程-高并发情况下接口性能优化实践-提升吞吐量TPS
- 2025-01-05 大促流量激增,通过什么手段提升系统的高并发、高可用性?
- 2025-01-05 Java 多线程与高并发,基础概念回顾
- 2025-01-05 实战场景下的Java高并发知识指南
- 2025-01-05 一篇文章教会你如何搭建高可用高并发系统
- 2025-01-05 一文看透Java高并发:Synchronized锁的性质、原理及其缺陷
- 2025-01-05 Kafka高可用,高吞吐量低延迟的高并发的特性背后实现机制
- 2025-01-05 java 高并发解决方案
你 发表评论:
欢迎- 04-24Java Collections 工具类集合框架中常用算法解析
- 04-24桶排序的简单理解
- 04-24Java集合框架底层实现原理大揭秘
- 04-24Java 集合框架全面解析:选对数据结构,提升开发效率
- 04-24c#集合排序
- 04-24Java面试中常被问到的集合类深度解读
- 04-24VBA技术资料MF278:对集合进行排序
- 04-24Spring 最常用的 7 大类注解,史上最强整理
- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)