java的三大特性之一,继承;那线程之间是否有继承关系?看一下thread的源码。
1 /** 2 * Initializes a Thread. 3 * 4 * @param g the Thread group 5 * @param target the object whose run() method gets called 6 * @param name the name of the new Thread 7 * @param stackSize the desired stack size for the new thread, or 8 * zero to indicate that this parameter is to be ignored. 9 * @param acc the AccessControlContext to inherit, or10 * AccessController.getContext() if null11 * @param inheritThreadLocals if {@code true}, inherit initial values for12 * inheritable thread-locals from the constructing thread13 */14 private void init(ThreadGroup g, Runnable target, String name,15 long stackSize, AccessControlContext acc,16 boolean inheritThreadLocals) {17 if (name == null) {18 throw new NullPointerException("name cannot be null");19 } 20 21 this.name = name; 22 23 Thread parent = currentThread(); 24 SecurityManager security = System.getSecurityManager(); 25 if (g == null) { 26 /* Determine if it's an applet or not */ 27 28 /* If there is a security manager, ask the security manager 29 what to do. */ 30 if (security != null) { 31 g = security.getThreadGroup(); 32 } 33 34 /* If the security doesn't have a strong opinion of the matter 35 use the parent thread group. */ 36 if (g == null) { 37 g = parent.getThreadGroup(); 38 } 39 } 40 41 /* checkAccess regardless of whether or not threadgroup is 42 explicitly passed in. */ 43 g.checkAccess(); 44 45 /* 46 * Do we have the required permissions? 47 */ 48 if (security != null) { 49 if (isCCLOverridden(getClass())) { 50 security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); 51 } 52 } 53 54 g.addUnstarted(); 55 56 this.group = g; 57 this.daemon = parent.isDaemon(); 58 this.priority = parent.getPriority(); 59 if (security == null || isCCLOverridden(parent.getClass())) 60 this.contextClassLoader = parent.getContextClassLoader(); 61 else 62 this.contextClassLoader = parent.contextClassLoader; 63 this.inheritedAccessControlContext = 64 acc != null ? acc : AccessController.getContext(); 65 this.target = target; 66 setPriority(priority); 67 if (inheritThreadLocals && parent.inheritableThreadLocals != null) 68 this.inheritableThreadLocals = 69 ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); 70 /* Stash the specified stack size in case the VM cares */ 71 this.stackSize = stackSize; 72 73 /* Set thread ID */ 74 tid = nextThreadID(); 75 }
纵观thread的所有构造函数中,都调用了init方法,不难从中发现线程之间的父子关系。
if (name == null) { throw new NullPointerException("name cannot be null"); }
name:即线程的名称,可以自定义,默认采用Thread-+数字给线程命名。
Thread parent = currentThread(); SecurityManager security = System.getSecurityManager();
在线程的生命周期中,如果一个线程new出来之后,在start之前,只是一个thread实例,并没有创建一个新的线程,所以这里的 Thread parent = currentThread(); 代表的是创建它的那个线程。
因此可以得出结论:
1.一个线程一定是由另一个线程创建的。
2.被创建的线程的父线程 是创建它的线程。
3.main函数所在的线程是由jvm创建的,因此推断出所有的线程的父线程是main线程。
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(); } }
init方法中,第一个参数为 ThreadGroup,从上面的代码块看出,如果没有传入线程组,则默认加入父线程所在的线程组。下面代码测试一下:
public static void main(String[] args) { Thread t1 = new Thread("t1"); ThreadGroup group = new ThreadGroup("group1"); Thread t2 = new Thread(group, "t2"); ThreadGroup threadGroup = Thread.currentThread().getThreadGroup(); System.out.println("父线程组 name:"+threadGroup.getName()); System.out.println("t1所在线程组 name:"+t1.getThreadGroup().getName()); System.out.println("t2所在线程组 name:"+t2.getThreadGroup().getName()); }
结果:
父线程组 name:main
t1所在线程组 name:main t2所在线程组 name:group1这里我们先创建线程t1,线程组group1,线程t2,在创建t2的时候,将group1做为参数传递到线程t2的创建中,而t1并没有指定线程组。
分别获取当前线程的线程组name,t1的线程组name,t2的线程组name,可见t1因为没有指定线程组,被加到了当前线程的线程组中。