在 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的線程后,虛擬機將會自動退出。