1.概览
在这篇短文中,我们将介绍一下java中的守护线程daemon threads,看看它们都是用于解决什么问题。与此同时,我们还会解释一下用户线程和守护线程之间的区别。
2.守护线程和用户线程之间的区别
java提供了俩类的线程:用户线程和守护线程(user thread and Daemon thread)。用户线程是高优先级的线程。JVM虚拟机在结束一个用户线程之前,会先等待该用户线程完成它的task。
在另一方面,守护线程是低优先级的线程,它的作用仅仅是为用户线程提供服务。正是由于守护线程是为用户线程提供服务的,仅仅在用户线程处于运行状态时才需要守护线程。另外,一旦所有的用户线程都运行完毕,那么守护线程是无法阻止JVM退出的。
这也是存在于守护线程中的无限循环不会产生问题的原因,因为包括finally 块的任何代码都不会被执行,一旦所有的用户线程结束运行之后。出于这个原因,我们不推荐使用守护线程处理I/O任务。
然而,这个规则也有例外。守护线程中那些设计糟糕的代码也能阻止JVM虚拟机退出。例如,在一个运行中的守护线程上调用Thread.join()方法会阻塞应用程序的关闭。
3.守护线程的用法 Uses of Daemon Threads
对于那些需要后台运行的task来说,守护线程是十分有用的,例如垃圾收集器,释放不再使用的对象的内存,并且从cache中移除那些不想要的入口。大多数虚拟机线程都是守护线程。
4.创建一个守护线程
把一个用户线程设置为守护线程,我们需要做的就是调用 Thread.setDaemon()方法。在本例中,我们将使用继承了Thread类的NewThread类:
NewThread daemonThread = new NewThread();
daemonThread.setDaemon(true);
daemonThread.start();
任何线程都会继承负责创建它的那个线程的daemon状态,由于main线程是一个用户线程,所以在main方法内创建的任意线程默认都是用户线程。
setDaemon()只有在线程对象创建之后且没有start时,才能调用。在线程运行期间调用setDaemon()方法会抛出一个IllegalThreadStateException异常。
@Test(expected = IllegalThreadStateException.class)
public void whenSetDaemonWhileRunning_thenIllegalThreadStateException() {
NewThread daemonThread = new NewThread();
daemonThread.start();
daemonThread.setDaemon(true);
}
5.检查一个线程是否是守护线程
最后,要检查一个线程是否是一个守护线程,我们简单地调用isDaemon()线程即可。
@Test
public void whenCallIsDaemon_thenCorrect() {
NewThread daemonThread = new NewThread();
NewThread userThread = new NewThread();
daemonThread.setDaemon(true);
daemonThread.start();
userThread.start();
assertTrue(daemonThread.isDaemon());
assertFalse(userThread.isDaemon());
}
6.总结
在这篇教程中,我们看到了什么是守护线程以及它们的使用场景,和往常一样,所有的代码都在github上,地址是:over on GitHub