25. 守护线程
大约 2 分钟
1. 守护线程
1.JAVA中的线程分为两类,用户线程和守护线程,默认创建的进程、线程都是用户线程
2.当JVM中存在用户线程时,守护线程不会退出,只有当没有任何用户线程时,守护线程会跟着退出。
3.用户线程创建的守护线程,只要有用户线程存在就不会退出;守护线程创建的子线程,不管子线程是不是守护线程都会随着父线程的退出而退出。
2. 应用场景
生产者-消费者模式下,生产者和消费者都是线程,当生产者线程已经确定不会再产生新的消费数据而退出时,消费者线程也没有存在的必要,此时消费者线程可以设置为守护线程。
需要注意的是:通常的web应用中,会存在很多用户线程,不可能所有的用户线程都退出,此时设置守护线程没有意义,因为永远无法退出,需要使用额外的机制来退出。
3. Show me code
2.1 代码
import java.util.concurrent.TimeUnit;
public class DaemonThreadDemo {
private static class ParentThread extends Thread {
private boolean childDaemon = false;
public ParentThread(boolean childDaemon) {
this.childDaemon = childDaemon;
}
@Override
public void run() {
ChildThread childThread = new ChildThread();
childThread.setName("daemonChild");
childThread.setDaemon(childDaemon);
childThread.start();
System.out.println(getName() + "run....");
quietlySleep();
}
}
private static class ChildThread extends Thread {
@Override
public void run() {
while(true) {
System.out.println(getName() + " child run....");
quietlySleep();
}
}
}
private static void quietlySleep() {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
// nothing to do
}
}
private static void testDependency(boolean threadADaemon, boolean threadBDaemon) {
ChildThread childThread1 = new ChildThread();
childThread1.setName("childThread1 ");
childThread1.setDaemon(threadADaemon);
childThread1.start();
ChildThread childThread2 = new ChildThread();
childThread2.setName("childThread2 ");
childThread2.setDaemon(threadBDaemon);
childThread2.start();
}
private static void testCreateChildThread(boolean parentDaemon, boolean childDaemon) {
ParentThread parentThread = new ParentThread(childDaemon);
parentThread.setDaemon(parentDaemon);
parentThread.start();
}
public static void main(String[] args) {
//只要其中一个线程是用户线程,不会退出,导致守护线程也不会退出
// testDependency(true, false);
//两个线程都是守护线程,因此只要主进程退出,则都退出
// testDependency(true, true);
//父线程是守护线程,不管子线程是否守护线程,都会跟着主线程退出而退出
// testCreateChildThread(true,true);
// testCreateChildThread(true,false);
//父线程为用户线程,子线程是守护线程,跟着主线程退出而退出
// testCreateChildThread(false,true);
//父线程为用户线程,子线程为守护线程,不会跟着父线程退出而退出
testCreateChildThread(false,false);
}
}
2.2 打印日志
2.2.1 testDependency(true, false);
childThread1 child run....
childThread2 child run....
childThread2 child run....
childThread1 child run....
childThread2 child run....
childThread1 child run....
2.2.2 testDependency(true, true);
childThread1 child run....
2.2.3 testCreateChildThread(true,true);
无日志,立即退出。
2.2.4 testCreateChildThread(true,false);
无日志,立即退出。
2.2.5 testCreateChildThread(false,true);
Thread-0run....
daemonChild child run....
daemonChild child run....
2.2.6 testCreateChildThread(false,false);
Thread-0run....
daemonChild child run....
daemonChild child run....
daemonChild child run....
daemonChild child run....
daemonChild child run....