写于:2019-11-04

Thread 构造函数

从构造函数中能够得到几个重要的入参:

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

stackSize javaDoc 描述

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 自行分配。

精彩内容推送,请关注公众号!
最近更新时间: 4/16/2020, 8:37:50 PM