我们构造线程的时候可以为线程起一个有特殊意义的名字,这也是比较好的一种做法,尤其在线程比较多的程序中,为线程赋予一个包含特殊意义的名字有助于问题的排查和线程的跟踪。 1.1 线程的默认命名
Thread()Thread (Runnable target)Thread (ThreadGroup group,Runnable target) 下面的几个构造函数,并没有提供为线程命名的参数,那么此时线程会有一个默认的命名。 1.2 打开 JDK 的源码会看到下面的代码: /*** Allocates a new {@code Thread} object. This constructor has the same * effect as {@linkplain#Thread(ThreadGroup,Runnable,String) Thread} * {@code (null, null, gname)}, where {@code gname} is a newly generated * name. Automatically generated names are of the form * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer. */ public Thread() { this(null, null, "Thread-" + nextThreadNum(), 0); } /* For autonumbering anonymous threads. */ private static int threadInitNumber; private static synchronized int nextThreadNum() { return threadInitNumber++; }如果没有为线程显示的指定一个名字,那么线程将会以“Thread-”作为前缀与一个自 增数字进行组合,这个自增数字在整个 JVM 进程中将会不断自增,且加了 synchronized 不 会出现重复的情况。
1.3 代码部分
public class ThreadConstructors01 { public static void main(String[] args) { System.out.println(Thread.currentThread().getName());// main // 1. Thread() Thread t1 = new Thread(){ @Override public void run() { // 获取当前运行时线程的名称 System.out.println(Thread.currentThread().getName()); } }; t1.start(); // 2. Thread(Runnable target) Thread t2 = new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()); } }); t2.start(); // 3. Thread(Runnable target, String name) Thread t3 = new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()); } }, "CustomThread-0"); t3.start(); // 4. Thread(String name) Thread t4 = new Thread("CustomThread-1"){ @Override public void run() { System.out.println(Thread.currentThread().getName()); } }; t4.start(); } }运行结果: 并且在使用默认命名和自定义方式之间互不影响,即我们在使用默认命名方式之间进行自定义命名,不影响默认命名方式的数字。
1.4 修改线程名称-setName()
// 修改线程的名称 new Thread(() -> { System.out.println(Thread.currentThread().getName()); Thread.currentThread().setName("AfterThread"); System.out.println(Thread.currentThread().getName()); }, "BeforeThread").start();Thread 的所有构造函数,最终都会去调一个私有构造器,我们截取片段代码对其进行分析,不难发现新创建的任何一个线程的都会有一个父线程。
private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc, boolean inheritThreadLocals) { if (name == null) { throw new NullPointerException("name cannot be null"); } this.name = name; Thread parent = currentThread();上面代码中的 currentThread()是获取当前线程,在线程生命周期中,线程的最初状态为 NEW,没有执行 start 方法之前,它只能算是一个 Thread 的实例,并不意味 着一个新的线程被创建,因此 currentThread()代表的将会是创建它的那个线程。所以说,一个线程的创建肯定是由另外一个线程完成的,被创建的线程属于创建它的线程的子线程。main 函数所在的线程是由 JVM 创建的,也就是 main 线程,那就意味着我 们前面创建的所有线程,其父线程都是 main 线程。