Java中的线程分为两类:守护线程和用户线程,守护线程被称为后台线程、用户线程被称为前台线程。守护线程一般被用来服务用户线程,两者之间的区别就是体现在JVM的运行上,当所有的用户线程结束,JVM会自动退出,这时候系统服务停止运行,守护线程自然也只能被迫停止。反之,守护线程全部结束不一定会导致JVM退出。
守护线程和用户线程在使用上区别不大,守护线程只需要在使用时执行this.setDaemon(true)方法,且这个方法必须放在this.start()方法之前执行,否则会抛出IllegalThreadStateException异常,JDK源码中此方法上的注释也已经明确指出使用时的注意事项。
/** * Marks this thread as either a daemon thread or a user thread. The * Java Virtual Machine exits when the only threads running are all * daemon threads. * <p> * This method must be called before the thread is started. * <p> * This method first calls the <code>checkAccess</code> method * of this thread * with no arguments. This may result in throwing a * <code>SecurityException </code>(in the current thread). * * @param on if <code>true</code>, marks this thread as a * daemon thread. * @exception IllegalThreadStateException if this thread is active. * @exception SecurityException if the current thread cannot modify * this thread. * @see #isDaemon() * @see #checkAccess */ public final void setDaemon(boolean on) { checkAccess(); if (isAlive()) { throw new IllegalThreadStateException(); } daemon = on; }
下面用一个例子来比较下守护线程和用户线程的执行情况:
package com.zw; /** * 守护线程和用户线程 * @author Administrator * 用户线程结束,JVM也就退出了,守护线程会立刻终止 */ public class TestDaemon { public static void main(String[] args) { MyUserThread m = new MyUserThread(); MyUserThread2 m2 = new MyUserThread2(); MyDaemonThread md = new MyDaemonThread(m, m2); md.setDaemon(true); //设置md为守护线程 md.start(); } } /** * 守护线程 * @author Administrator * */ class MyDaemonThread extends Thread { MyUserThread m = null; MyUserThread2 m2 = null; MyDaemonThread(MyUserThread m,MyUserThread2 m2) { this.m = m; this.m2 = m2; m.start(); m2.start(); } @Override public void run() { // TODO Auto-generated method stub super.run(); while(true) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("守护线程 " + m.getI()); } } } /** * 用户线程 * @author Administrator * */ class MyUserThread extends Thread { private int i = 0; public int getI() { return i; } @Override public void run() { // TODO Auto-generated method stub super.run(); while(i < 5) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("用户线程 " + i++); } } } class MyUserThread2 extends Thread { private int i = 0; public int getI() { return i; } @Override public void run() { // TODO Auto-generated method stub super.run(); while(i < 10) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("用户线程2 " + i++); } } }
执行结果:
用户线程 0
用户线程2 0
守护线程 1
用户线程 1
守护线程 2
用户线程2 1
用户线程 2
守护线程 3
用户线程2 2
用户线程 3
守护线程 4
用户线程2 3
用户线程 4
守护线程 5
用户线程2 4
守护线程 5
用户线程2 5
守护线程 5
用户线程2 6
守护线程 5
用户线程2 7
守护线程 5
用户线程2 8
守护线程 5
用户线程2 9
上面的实例中启动了3个线程,一个守护线程md,两个用户线程m,m2。守护线程中无限循环执行输出,线程m执行结束时,守护线程还在自我循环中,但是当m2也结束时,守护线程也跟着停止了,这是因为m和m2两个用户线程全部结束,JVM检测到没有用户线程在执行,也就自动退出。JVM退出了,守护线程没了依托,也只能被迫停止。
Java中的GC线程就是典型的守护线程,当系统停止了对象的创建,GC没有对象可回收,就会随着JVM退出而退出。