关于java线程的daemon的认识
在 JAVA中的CountDownLatch、CyclicBarrier、Semaphore的简单测试 这文章里说到了线程的daemon问题,特写一篇来分析一下。
上代码:
1 package com.yzl.dubbo; 2 3 import java.util.concurrent.TimeUnit; 4 5 /** 6 * java Thread的daemon属性测试 7 * 结论: 8 * 1、当虚拟机不存在daemon==false的线程时,虚拟机将会自动退出 9 * 2、当虚拟机退出时,daemon里的finally代码不一定会执行完全(可能执行到一半就被强制干掉了) 10 * @author yangzhilong 11 * 12 */ 13 public class Daemon { 14 15 public static void main(String[] args) { 16 Thread thread = new Thread(new DaemonRunner(), "daemon"); 17 //当虚拟机不存在daemon==false的线程时,虚拟机将会自动退出 18 //mian线程属于false 19 //不对这个属性进行设置的线程也是false 20 // thread.setDaemon(false); 21 thread.setDaemon(true); 22 thread.start(); 23 } 24 25 static class DaemonRunner implements Runnable { 26 @Override 27 public void run() { 28 for (int i = 0; i < 10; i++) { 29 try { 30 System.out.println("run ........"); 31 TimeUnit.SECONDS.sleep(5); 32 System.out.println("end run......"); 33 } catch (Exception e) { 34 } finally { 35 System.out.println("finally is runing。。。。"); 36 } 37 } 38 } 39 } 40 }
注释掉20行,放开21行的运行结果如下:
run ........
注释掉21行,放开20行的运行结果如下:
run ........ end run...... finally is runing。。。。 run ........ end run...... finally is runing。。。。 run ........ end run...... finally is runing。。。。 run ........ end run...... finally is runing。。。。 run ........ end run...... finally is runing。。。。 run ........ end run...... finally is runing。。。。 run ........ end run...... finally is runing。。。。 run ........ end run...... finally is runing。。。。 run ........ end run...... finally is runing。。。。 run ........ end run...... finally is runing。。。。
我们来看看Thread的构造函数里的核心源码:
1 private void init(ThreadGroup g, Runnable target, String name, 2 long stackSize, AccessControlContext acc) { 3 if (name == null) { 4 throw new NullPointerException("name cannot be null"); 5 } 6 7 this.name = name; 8 9 Thread parent = currentThread(); 10 SecurityManager security = System.getSecurityManager(); 11 if (g == null) { 12 /* Determine if it's an applet or not */ 13 14 /* If there is a security manager, ask the security manager 15 what to do. */ 16 if (security != null) { 17 g = security.getThreadGroup(); 18 } 19 20 /* If the security doesn't have a strong opinion of the matter 21 use the parent thread group. */ 22 if (g == null) { 23 g = parent.getThreadGroup(); 24 } 25 } 26 27 /* checkAccess regardless of whether or not threadgroup is 28 explicitly passed in. */ 29 g.checkAccess(); 30 31 /* 32 * Do we have the required permissions? 33 */ 34 if (security != null) { 35 if (isCCLOverridden(getClass())) { 36 security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); 37 } 38 } 39 40 g.addUnstarted(); 41 42 this.group = g; 43 this.daemon = parent.isDaemon(); 44 this.priority = parent.getPriority(); 45 if (security == null || isCCLOverridden(parent.getClass())) 46 this.contextClassLoader = parent.getContextClassLoader(); 47 else 48 this.contextClassLoader = parent.contextClassLoader; 49 this.inheritedAccessControlContext = 50 acc != null ? acc : AccessController.getContext(); 51 this.target = target; 52 setPriority(priority); 53 if (parent.inheritableThreadLocals != null) 54 this.inheritableThreadLocals = 55 ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); 56 /* Stash the specified stack size in case the VM cares */ 57 this.stackSize = stackSize; 58 59 /* Set thread ID */ 60 tid = nextThreadID(); 61 }
被new出来的thread如果没有特别设置它的daemon属性,那它的daemon将和创建它的线程的daemon相同,Junit线程是daemon=true(后台线程),所以new出来的线程也是后台线程,当虚拟机中不存在daemon==false的线程后,虚拟机将会自动退出。