java多线程基本概述(十五)——DaemonThread
所谓守护线程(DaemonThread),是指在程序运行的时候在后台提供的一种通用的服务线程,并且这种线程并不属于程序中不可或缺的一部分。因此,当所有非守护线程(前台线程)都结束时,程序也就终止了。同时会杀死所有的后台线程,反过来说,只要又任何非守护线程还在执行,程序就不会终止,比如main()方法就是一个非守护线程。
1.
例子:
package tij; import java.util.concurrent.TimeUnit; /** * Created by huaox on 2017/4/19. */ public class DaemonTest implements Runnable{ @Override public void run() { try { while (true){ TimeUnit.MILLISECONDS.sleep(100); System.out.println(Thread.currentThread()+" "+this); } }catch (InterruptedException e){ System.out.println("sleep() interrupted"); } } public static void main(String[] args) throws InterruptedException { for (int i = 0; i < 10; i++) { Thread daemon = new Thread(new DaemonTest()); daemon.setDaemon(true);//必须再线程启动之前把它设为守护线程,否则无效 daemon.start(); } System.out.println("All daemon started"); TimeUnit.MILLISECONDS.sleep(200);//把这行语句可以注释掉查看效果 } }
输出结果:
All daemon started Thread[Thread-6,5,main] tij.DaemonTest@3943de20 Thread[Thread-2,5,main] tij.DaemonTest@28979470 Thread[Thread-4,5,main] tij.DaemonTest@333cafca Thread[Thread-3,5,main] tij.DaemonTest@131c736d Thread[Thread-5,5,main] tij.DaemonTest@362363a6 Thread[Thread-0,5,main] tij.DaemonTest@43a3a747 Thread[Thread-1,5,main] tij.DaemonTest@4521d907 Thread[Thread-8,5,main] tij.DaemonTest@782b1823 Thread[Thread-7,5,main] tij.DaemonTest@1bb19ff0 Thread[Thread-9,5,main] tij.DaemonTest@4559f79 Process finished with exit code 0
因为前台线程main()方法,正在休眠,那么另外的十个守护线程才有机会执行。如果注释掉main()线程中的那条休眠语句,那么程序的执行效果如下:
All daemon started
Process finished with exit code 0
可以看到程序在main()执行完立即返回了,并没有等待后台线程的执行。
2.我们也可以通过ThreadFactory来定制有Executor创建的线程的属性(名称,优先级,名称):
代码如下:
package tij; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; /** * Created by huaox on 2017/4/19. * */ class DaemonThreadFactory implements ThreadFactory{ @Override public Thread newThread(Runnable r) { Thread thread = new Thread(r); thread.setDaemon(true); return thread; } } class DaemonFromFactory implements Runnable{ @Override public void run() { try { while (true){ TimeUnit.MILLISECONDS.sleep(100); System.out.println(Thread.currentThread()+" "+this); } } catch (InterruptedException e) { System.out.println("interrupted"); } } } public class DaemonTest2 { public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newCachedThreadPool(new DaemonThreadFactory());//使用自己的ThreadFactory for (int i = 0; i < 10; i++) { executorService.execute(new DaemonFromFactory()); } System.out.println("All daemon started"); TimeUnit.MILLISECONDS.sleep(500);//把这行语句可以注释掉查看效果 } }
输出结果:
All daemon started Thread[Thread-9,5,main] tij.DaemonFromFactory@b20568f Thread[Thread-8,5,main] tij.DaemonFromFactory@3d6741a8 Thread[Thread-7,5,main] tij.DaemonFromFactory@3d7c301d Thread[Thread-5,5,main] tij.DaemonFromFactory@655a2155 Thread[Thread-6,5,main] tij.DaemonFromFactory@5169ce60 Thread[Thread-4,5,main] tij.DaemonFromFactory@2cf9cd59 Thread[Thread-2,5,main] tij.DaemonFromFactory@710a3057 Thread[Thread-3,5,main] tij.DaemonFromFactory@7f05b150 Thread[Thread-0,5,main] tij.DaemonFromFactory@47a2a66c Thread[Thread-1,5,main] tij.DaemonFromFactory@6f9777db Thread[Thread-1,5,main] tij.DaemonFromFactory@6f9777db Thread[Thread-0,5,main] tij.DaemonFromFactory@47a2a66c Thread[Thread-3,5,main] tij.DaemonFromFactory@7f05b150 Thread[Thread-2,5,main] tij.DaemonFromFactory@710a3057 Thread[Thread-4,5,main] tij.DaemonFromFactory@2cf9cd59 Thread[Thread-6,5,main] tij.DaemonFromFactory@5169ce60 Thread[Thread-5,5,main] tij.DaemonFromFactory@655a2155 Thread[Thread-7,5,main] tij.DaemonFromFactory@3d7c301d Thread[Thread-8,5,main] tij.DaemonFromFactory@3d6741a8 Thread[Thread-9,5,main] tij.DaemonFromFactory@b20568f Thread[Thread-9,5,main] tij.DaemonFromFactory@b20568f Thread[Thread-7,5,main] tij.DaemonFromFactory@3d7c301d Thread[Thread-8,5,main] tij.DaemonFromFactory@3d6741a8 Thread[Thread-4,5,main] tij.DaemonFromFactory@2cf9cd59 Thread[Thread-6,5,main] tij.DaemonFromFactory@5169ce60 Thread[Thread-5,5,main] tij.DaemonFromFactory@655a2155 Thread[Thread-2,5,main] tij.DaemonFromFactory@710a3057 Thread[Thread-3,5,main] tij.DaemonFromFactory@7f05b150 Thread[Thread-0,5,main] tij.DaemonFromFactory@47a2a66c Thread[Thread-1,5,main] tij.DaemonFromFactory@6f9777db Thread[Thread-1,5,main] tij.DaemonFromFactory@6f9777db Thread[Thread-3,5,main] tij.DaemonFromFactory@7f05b150 Thread[Thread-0,5,main] tij.DaemonFromFactory@47a2a66c Thread[Thread-2,5,main] tij.DaemonFromFactory@710a3057 Thread[Thread-5,5,main] tij.DaemonFromFactory@655a2155 Thread[Thread-6,5,main] tij.DaemonFromFactory@5169ce60 Thread[Thread-4,5,main] tij.DaemonFromFactory@2cf9cd59 Thread[Thread-8,5,main] tij.DaemonFromFactory@3d6741a8 Thread[Thread-7,5,main] tij.DaemonFromFactory@3d7c301d Thread[Thread-9,5,main] tij.DaemonFromFactory@b20568f Process finished with exit code 0
可以通过调用isDaemon()方法来查看一个先蹭时候属于后台线程,如果时一个后台线程,那么它创建的任何线程都将被自动设置为守护线程。示例如下:
package tij; import java.util.concurrent.TimeUnit; /** * Created by huaox on 2017/4/19. * */ class Daemon implements Runnable{ Thread[] threads = new Thread[10]; @Override public void run() { for (int i = 0; i < 10; i++) { threads[i] = new Thread(new DaemonSpawn()); threads[i].start();//这个地方之前并没有给DaemonSpawn这个线程设置为守护线程,但从输出看,它“自动”被设置为守护线程了 System.out.println("DaemonSpawn "+i+" started "+threads[i].isDaemon()); } for (int i = 0; i < 10; i++) { System.out.println("threads[ "+i+"].isDaemon() = "+threads[i].isDaemon()); } while (true) Thread.yield(); } } class DaemonSpawn implements Runnable{ @Override public void run() { while (true) Thread.yield(); } } public class DaemonTest3 { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new Daemon()); thread.setDaemon(true); thread.start(); System.out.println("thread.isDaemon() = "+thread.isDaemon()); TimeUnit.SECONDS.sleep(5);//给守护线程一点时间去执行完成 } }
输出结果:
thread.isDaemon() = true , DaemonSpawn 0 started true DaemonSpawn 1 started true DaemonSpawn 2 started true DaemonSpawn 3 started true DaemonSpawn 4 started true DaemonSpawn 5 started true DaemonSpawn 6 started true DaemonSpawn 7 started true DaemonSpawn 8 started true DaemonSpawn 9 started true threads[ 0].isDaemon() = true threads[ 1].isDaemon() = true threads[ 2].isDaemon() = true threads[ 3].isDaemon() = true threads[ 4].isDaemon() = true threads[ 5].isDaemon() = true threads[ 6].isDaemon() = true threads[ 7].isDaemon() = true threads[ 8].isDaemon() = true threads[ 9].isDaemon() = true Process finished with exit code 0
从结果可以验证之前的结果。
3.守护线程的finally不一定执行!!!
示例如下:
class Adaemon implements Runnable{ @Override public void run() { try { System.out.println("Adaemon started"); TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }finally { System.out.println("this should always run?"); } } } public class DaemonTest3 { public static void main(String[] args) throws InterruptedException{ Thread thread = new Thread(new Adaemon()); thread.setDaemon(true); thread.start(); TimeUnit.SECONDS.sleep(1); } }
输出结果:
Adaemon started this should always run? Process finished with exit code 0
可以看到finally中的自居并不会被执行。当注销设置守护线程的那句代码时会发现finally子句被执行