一、守护线程概念
Java中将线程分为两类,用户线程和守护线程,其中用户线程就是在前台执行的,用于执行具体操作的线程,比如程序中的主线程、网络连接的子线程等。守护线程是指运行在后台的,为用户线程提供服务的线程,Java中最典型的守护线程就是垃圾回收的GC线程。守护线程最大的特点就是当所有用户线程都结束运行后,守护线程会随着Java虚拟机一同结束工作。
Java中要想将一个线程设置为守护线程,只需要调用setDaemon(boolean on)方法,并将参数值赋为true即可。使用守护线程有几个注意点:
1、setDaemon(true)方法必须在线程启动的start()方法之前调用,否则会抛出java.lang.IllegalThreadStateException。这个也比较好理解,意思就是说不能将正在运行的用户线程设置为守护线程。
2、在守护线程中产生的新线程也是守护线程。
3、并不是所有的任务都能分配给守护线程进行执行,比如读写操作或者计算等。这句话可以这样理解,比如在守护线程中定义了一个读写文件的操作,当所有的用户线程都执行完毕退出了,这时候守护线程也没有存在的必要了,也将随JVM一同结束,但是这时守护线程的读写操作还没有完成,也就是说守护线程不能执行完就退出了,这样可能会出现不正确的结果。
二、守护线程案例
现在写一个守护线程的案例来具体学习一下守护线程的使用。案例的场景如下:程序定义并启动一个守护线程,守护线程不断地向一个文件中写入内容,同时程序的主线程等待用户从键盘的输入,当用户输入之后,主线程执行结束,这样可以观察一下主线程和守护线程的执行过程。
案例代码如下:
class DaemonThread implements Runnable {
@Override
public void run() {
System.out.println("守护线程准备开始执行了!" + Thread.currentThread().getName());
try {
writeFile();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("守护线程执行完毕!" + Thread.currentThread().getName());
}
public void writeFile() throws Exception{
File file = new File("e:\\daemon.txt");
OutputStream out = new FileOutputStream(file);
for(int i = 0; i < 999; i++) {
out.write(("write" + i + "\n").getBytes());
System.out.println(Thread.currentThread().getName() + "守护线程向文件写入数据!" + i);
Thread.sleep(1000);
}
out.close();
}
}
public class DaemonTest {
public static void main(String[] args) {
DaemonThread test = new DaemonThread();
Thread thread = new Thread(test, "子线程");
thread.setDaemon(true);
thread.start();
Scanner sc = new Scanner(System.in);
sc.next();
sc.close();
System.out.println("主线程执行结束!");
}
}
运行程序,输出结果:
守护线程准备开始执行了!子线程
子线程守护线程向文件写入数据!0
子线程守护线程向文件写入数据!1
子线程守护线程向文件写入数据!0
子线程守护线程向文件写入数据!1
……
从结果可以发现守护线程每隔一秒向文件中写入一条数据,而主线程处于阻塞状态,等待用户从键盘输入,这时如果随便输入一些信息,程序便会结束执行,例如
守护线程准备开始执行了!子线程
子线程守护线程向文件写入数据!0
子线程守护线程向文件写入数据!1
子线程守护线程向文件写入数据!2
aa子线程守护线程向文件写入数据!3
主线程执行结束!
用户输入内容后,主线程结束执行,在这个案例中便没有其他的用户线程在执行了,这样守护线程也就随之结束,并不会继续运行下去,因此生成的文件也只有四行内容。