写于:2019-11-04
从构造函数中能够得到几个重要的入参:
1、Runnable target
2、String name
3、ThreadGroup group
4、long stackSize
以上这些参数都可以为空,下面来逐个分析上面的入参含义
一、Runnable target
在 [THEORY]-[01]-线程概述 中末尾提到了 Runnable ,这里不再赘述。
二、String name
该参数的含义:线程名称。
在应用程序中会存在很多的线程,而相关的日志,会打印线程信息,包括线程名称,而特定的线程名称能够便于定位问题和线程追踪。
线程的默认名称
在 Thread 构造函数中,线程名称的入参允许为空,当不指定线程名称时,会默认为线程赋予一个名称。
通过,无参构造函数 Thread() 作为入口,进行追踪分析 Thread 源码。
public class Thread implements Runnable {
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
init(g, target, name, stackSize, null, true);
}
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
return threadInitNumber++;
}
}
通过代码能够知道线程的默认名称为: “Thread-“ + 数字(从0开始递增)。
如: Thread-01,Thread-02
小贴士: 在线程未启动时,能够进行线程名称的修改。其代码如下:
public class Thread implements Runnable {
public final synchronized void setName(String name) {
......
this.name = name;
if (threadStatus != 0) { // 当前线程状态为 NEW 的时候可以修改,一旦线程启动便无法修改。
setNativeName(name);
}
}
三、ThreadGroup group
1、线程的父子关系
Thread 所有的构造函数,最终都调用了 Thread#init 方法,代码内容如下:
public class Thread implements Runnable {
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
......
Thread parent = currentThread(); //
......
}
// 返回当前执行的线程对象的引用
public static native Thread currentThread();
}
上述代码中 currentThread() 方法,根据 java doc 得知,返回的是当前执行的线程对象的引用。
根据线程的生命周期,Thread 实例在调用 start 方法前,都不能称为一个线程,所以:
- a、一个线程的创建肯定由另一个线程完成
- b、被创建的父线程是创建它的线程
小贴士: main 方法的执行,JVM 会为其创建一个 main 线程,也就是说,在 main 方法中启动的线程父线程为 mian 线程。【多个嵌套创建忽略】
2、 ThreadGroup 的默认值
ThreadGroup 能够对一组线程进行统一管理,如:统一中断等操作。
Thread 所有的构造函数,最终都调用了 Thread#init 方法,代码内容如下:
public class Thread implements Runnable {
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
......
Thread parent = currentThread(); // 当前线程为父线程
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();
}
}
......
}
}
通过源码能够得知,在未指定 ThreadGroup 时,线程默认的 ThreadGroup 为其父线程的 ThreadGroup
小贴士 main 线程对应的 Thread Group 为 main,在 main 中创建的子线程默认的 Thread Group 也为 mian 测试代码:
public class ThreadGroupDemo {
public static void main(String[] args) {
// 打印main 线程 ThreadGroup
Optional.ofNullable(
Thread.currentThread().getThreadGroup().getName()
).ifPresent(item ->{
System.out.println(Thread.currentThread().getName() + " threadgroup :" +
Thread.currentThread().getThreadGroup().toString());
});
// 子线程的 ThreadGroup
new Thread(()->{
Optional.ofNullable(
Thread.currentThread().getThreadGroup().getName()
).ifPresent(item ->{
System.out.println(Thread.currentThread().getName() + " threadgroup :" +
Thread.currentThread().getThreadGroup().toString());
});
},"son").start();
}
}
控制台打印
main threadgroup :java.lang.ThreadGroup[name=main,maxpri=10]
son threadgroup :java.lang.ThreadGroup[name=main,maxpri=10]
四、long stackSize
Java 官方文档翻译如下:
stackSize[堆栈大小]是虚拟机为改线程分配的地址空间的字节数。 stackSize 参数的影响是高度依赖于平台的,换句话说,就是有的平台能生效,有的平台不生效。 stackSize 越大,代表线程内的方法调用递归深度越深,当然能够允许创建的线程就越少,反之, stackSize 越小,代表线程内的方法调用递归深度越浅,但是能够允许创建的线程越多。 该参数的使用需要谨慎,在有些操作系统硬件上,改值有作用,在有些操作系统硬件上是无效的。
stackSize 默认值
通过 Thread 中的java doc
public class Thread implements Runnable {
// @param stackSize the desired stack size for the new thread,
// or zero to indicate that this parameter is to be ignored.
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
......
}
}
能够得知,stackSzie 默认值为0,此时 stackSize 的大小有 JVM 自行分配。