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子句被执行

 

posted @ 2017-04-19 22:03  soar_hu  阅读(268)  评论(0编辑  收藏  举报