写于:2019-11-04

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

1、Runnable target

2、String name

3、ThreadGroup group

4、long stackSize

以上这些参数都可以为空,下面来逐个分析上面的入参含义

一、Runnable target

[THEORY]-[01]-线程概述 中末尾提到了 Runnable ,这里不再赘述。

二、String name

该参数的含义:线程名称。

在应用程序中会存在很多的线程,而相关的日志,会打印线程信息,包括线程名称,而特定的线程名称能够便于定位问题和线程追踪。

线程的默认名称

在 Thread 构造函数中,线程名称的入参允许为空,当不指定线程名称时,会默认为线程赋予一个名称。

通过,无参构造函数 Thread() 作为入口,进行追踪分析 Thread 源码。

  1. public class Thread implements Runnable {
  2. public Thread() {
  3. init(null, null, "Thread-" + nextThreadNum(), 0);
  4. }
  5. private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
  6. init(g, target, name, stackSize, null, true);
  7. }
  8. private static int threadInitNumber;
  9. private static synchronized int nextThreadNum() {
  10. return threadInitNumber++;
  11. }
  12. }

通过代码能够知道线程的默认名称为: “Thread-“ + 数字(从0开始递增)。
如: Thread-01,Thread-02

小贴士: 在线程未启动时,能够进行线程名称的修改。其代码如下:

  1. public class Thread implements Runnable {
  2. public final synchronized void setName(String name) {
  3. ......
  4. this.name = name;
  5. if (threadStatus != 0) { // 当前线程状态为 NEW 的时候可以修改,一旦线程启动便无法修改。
  6. setNativeName(name);
  7. }
  8. }

三、ThreadGroup group

1、线程的父子关系

Thread 所有的构造函数,最终都调用了 Thread#init 方法,代码内容如下:

  1. public class Thread implements Runnable {
  2. private void init(ThreadGroup g, Runnable target, String name,
  3. long stackSize, AccessControlContext acc,
  4. boolean inheritThreadLocals) {
  5. ......
  6. Thread parent = currentThread(); //
  7. ......
  8. }
  9. // 返回当前执行的线程对象的引用
  10. public static native Thread currentThread();
  11. }

上述代码中 currentThread() 方法,根据 java doc 得知,返回的是当前执行的线程对象的引用。

根据线程的生命周期,Thread 实例在调用 start 方法前,都不能称为一个线程,所以:

  • a、一个线程的创建肯定由另一个线程完成
  • b、被创建的父线程是创建它的线程

小贴士: main 方法的执行,JVM 会为其创建一个 main 线程,也就是说,在 main 方法中启动的线程父线程为 mian 线程。【多个嵌套创建忽略】

2、 ThreadGroup 的默认值

ThreadGroup 能够对一组线程进行统一管理,如:统一中断等操作。

Thread 所有的构造函数,最终都调用了 Thread#init 方法,代码内容如下:

  1. public class Thread implements Runnable {
  2. private void init(ThreadGroup g, Runnable target, String name,
  3. long stackSize, AccessControlContext acc,
  4. boolean inheritThreadLocals) {
  5. ......
  6. Thread parent = currentThread(); // 当前线程为父线程
  7. if (g == null) {
  8. /* Determine if it's an applet or not */
  9. /* If there is a security manager, ask the security manager
  10. what to do. */
  11. if (security != null) {
  12. g = security.getThreadGroup();
  13. }
  14. /* If the security doesn't have a strong opinion of the matter
  15. use the parent thread group. */
  16. if (g == null) {
  17. g = parent.getThreadGroup();
  18. }
  19. }
  20. ......
  21. }
  22. }

通过源码能够得知,在未指定 ThreadGroup 时,线程默认的 ThreadGroup 为其父线程的 ThreadGroup

小贴士 main 线程对应的 Thread Group 为 main,在 main 中创建的子线程默认的 Thread Group 也为 mian 测试代码:

  1. public class ThreadGroupDemo {
  2. public static void main(String[] args) {
  3. // 打印main 线程 ThreadGroup
  4. Optional.ofNullable(
  5. Thread.currentThread().getThreadGroup().getName()
  6. ).ifPresent(item ->{
  7. System.out.println(Thread.currentThread().getName() + " threadgroup :" +
  8. Thread.currentThread().getThreadGroup().toString());
  9. });
  10. // 子线程的 ThreadGroup
  11. new Thread(()->{
  12. Optional.ofNullable(
  13. Thread.currentThread().getThreadGroup().getName()
  14. ).ifPresent(item ->{
  15. System.out.println(Thread.currentThread().getName() + " threadgroup :" +
  16. Thread.currentThread().getThreadGroup().toString());
  17. });
  18. },"son").start();
  19. }
  20. }

控制台打印

  1. main threadgroup :java.lang.ThreadGroup[name=main,maxpri=10]
  2. son threadgroup :java.lang.ThreadGroup[name=main,maxpri=10]

四、long stackSize

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