在正式理解这个概念前,先把 守护线程 与 守护进程 这二个极其相似的说法区分开,守护进程通常是为了防止某些应用因各种意外原因退出,而在后台独立运行的系统服务或应用程序。 比如:我们开发了一个邮件发送程序,一直不停的监视队列池,发现有待发送的邮件,就将其发送出去。如果这个程序挂了(或被人误操作关了),邮件就不发出去了,为了防止这种情况,再开发一个类似windows 系统服务的应用,常驻后台,监制这个邮件发送程序是否在运行,如果没运行,则自动将其启动。

而我们今天说的java中的守护线程(Daemon Thread) 指的是一类特殊的Thread,其优先级特别低(低到甚至可以被JVM自动终止),通常这类线程用于在空闲时做一些资源清理类的工作,比如GC线程,如果JVM中所有非守护线程(即:常规的用户线程)都结束了,守护线程会被JVM中止,想想其实也挺合理,没有任何用户线程了,自然也不会有垃圾对象产生,GC线程也没必要存在了。

实际开发中,也可以手动将线程设置为Daemon Thread,只有一个限制:必须在线程的start方法设置,见下面的示例:

package test;

public class Program {

    public static void main(String[] args) {
TestThread t1 = new TestThread();
t1.setDaemon(true);
t1.start();
} private static class TestThread extends Thread {
public void run() {
System.out.println("test");
}
}
}

由于t1设置成Daemon Thread了,运行后,main进程马上就结束,此时没有用户进程在运行,守护进程默认是不执行的,因此运行后,没有任何输出结果,符合我们刚才的解释。

注:在idea等集成IDE环境下测试时,如果多次点击Run按钮,可能会发现第二次运行时,偶尔也会输出test,估计是ide里上次运行后的java进程并未完全退出,可以手动把windows进程中的所有java.exe进程干掉再测试。

如果把t1.setDaemon(true);这一行注释掉,就会输出test了。

另外,如果把main函数最后加一行阻塞的代码,比如:

    public static void main(String[] args) throws IOException {
TestThread t1 = new TestThread();
t1.setDaemon(true);
t1.start();
System.in.read();
}

加了一行System.in.read()后,再运行,会发现test会输出,这是因为main这个用户线程被阻塞了,JVM发现有用户进程在运行,守护进程才能机会被执行。

再来一个复杂点的示例:

假设有二个线程,一个是常规的用户线程,不停写入日志,另一个是守护线程,在空闲时清理日志(仅保留最近的5条日志)

package test;

import java.io.IOException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue; public class Program { private static int queueCapacity = 10;
private static BlockingQueue<String> logQueue = new ArrayBlockingQueue<String>(queueCapacity); public static void main(String[] args) throws IOException { LogWriter writer = new LogWriter();
LogCleaner cleaner = new LogCleaner();
cleaner.setDaemon(true); writer.start();
cleaner.start();
} /**
* 模拟不停写日志(直到队列写满)
*/
private static class LogWriter extends Thread {
public void run() {
for (int i = 0; i < queueCapacity; i++) {
try {
logQueue.put("" + i);
System.out.println("日志已写入,当前日志内容:" + logQueue);
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} /**
* 模拟在空闲时清理日志(仅保留5条日志)
*/
private static class LogCleaner extends Thread {
public void run() {
while (true) {
if (logQueue.size() > 5) {
try {
logQueue.take();
System.out.println("多余日志被清理,当前日志内容:" + logQueue);
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}

运行结果:

 日志已写入,当前日志内容:[]
日志已写入,当前日志内容:[, ]
日志已写入,当前日志内容:[, , ]
日志已写入,当前日志内容:[, , , ]
日志已写入,当前日志内容:[, , , , ]
日志已写入,当前日志内容:[, , , , , ]
多余日志被清理,当前日志内容:[, , , , ]
日志已写入,当前日志内容:[, , , , , ]
多余日志被清理,当前日志内容:[, , , , ]
日志已写入,当前日志内容:[, , , , , ]
多余日志被清理,当前日志内容:[, , , , ]
日志已写入,当前日志内容:[, , , , , ]
多余日志被清理,当前日志内容:[, , , , ]
日志已写入,当前日志内容:[, , , , , ]
多余日志被清理,当前日志内容:[, , , , ]

参考文章:

http://ifeve.com/thread-management-8/

http://www.cnblogs.com/super-d2/p/3348183.html

java并发编程学习: 守护线程(Daemon Thread)的更多相关文章

  1. Java并发编程学习:线程安全与锁优化

    本文参考<深入理解java虚拟机第二版> 一.什么是线程安全? 这里我借<Java Concurrency In Practice>里面的话:当多个线程访问一个对象,如果不考虑 ...

  2. JAVA并发编程学习笔记------线程的三种创建方式

    创建线程一般有如下几个方式: 1. 通过继承Thread类来创建一个线程: /** * 步骤1:定义一个继承Thread类的子类 * 步骤2:构造子类的一个对象 * 步骤3:启动线程: * */ pu ...

  3. JAVA并发编程——守护线程(Daemon Thread)

    在Java中有两类线程:用户线程 (User Thread).守护线程 (Daemon Thread). 所谓守护 线程,是指在程序运行的时候在后台提供一种通用服务的线程,比如垃圾回收线程就是一个很称 ...

  4. JAVA - 守护线程(Daemon Thread)

    转载自:http://www.cnblogs.com/luochengor/archive/2011/08/11/2134818.html 在Java中有两类线程:用户线程 (User Thread) ...

  5. 守护线程(Daemon Thread)

    在Java中有两类线程:用户线程 (User Thread).守护线程 (Daemon Thread). 所谓守护 线程,是指在程序运行的时候在后台提供一种通用服务的线程,比如垃圾回收线程就是一个很称 ...

  6. 用户线程 (User Thread)、守护线程 (Daemon Thread)

    在Java中有两类线程:用户线程 (User Thread).守护线程 (Daemon Thread). 所谓守护 线程,是指在程序运行的时候在后台提供一种通用服务的线程,比如垃圾回收线程就是一个很称 ...

  7. Java并发编程系列-(2) 线程的并发工具类

    2.线程的并发工具类 2.1 Fork-Join JDK 7中引入了fork-join框架,专门来解决计算密集型的任务.可以将一个大任务,拆分成若干个小任务,如下图所示: Fork-Join框架利用了 ...

  8. Java并发编程学习前期知识下篇

    Java并发编程学习前期知识下篇 通过上一篇<Java并发编程学习前期知识上篇>我们知道了在Java并发中的可见性是什么?volatile的定义以及JMM的定义.我们先来看看几个大厂真实的 ...

  9. Java并发编程学习笔记

    Java编程思想,并发编程学习笔记. 一.基本的线程机制 1.定义任务:Runnable接口 线程可以驱动任务,因此需要一种描述任务的方式,这可以由Runnable接口来提供.要想定义任务,只需实现R ...

随机推荐

  1. 2015年最佳的12个 CSS 开发工具推荐

    CSS所能做的就是改变网页的布局.排版和调整字间距等,但编写 CSS 并不是一项容易的任务,当你接触新的 CSS3 属性及其各自的浏览器前缀的时候,你会发现很伤脑经.值得庆幸的是一些优秀的开发人员提供 ...

  2. json和jsonp的区别,ajax和jsonp的区别

    json和jsonp虽然只有一个字母的区别,但是它们之间扯不上关系. json是一种轻量级的数据交换格式. jsonp是一种跨域数据交互协议. json的优点:(1)基于纯文本传递极其简单,(2)轻量 ...

  3. SharePoint 2007 Full Text Searching PowerShell and CS file content with SharePoint Search

    1. Ensure your site or shared folder in one Content Source. 2. Add file types. 3. The second step in ...

  4. SharePoint 2007 User Re-created in AD with new SID issue on MySite

    When active directory users get deleted and re-created, even with the same user id, there's a nasty ...

  5. Android开发—已root的手机获取data路径

    开发android的时候,尽管手机已经root但是DDMS中还是没有data/data路径怎么办? 可以用cmd命令提示符为逐个文件夹设置权限: 打开cmd,输入 adb shell  回车—> ...

  6. Android 面试题及答案(2)

    1.Activity相关.launchmode,OnSaveInstnceState,生命周期等. 4种默认的launchmode,以及OnNewIntent的回调. OnNewIntent-> ...

  7. [转]完美洗牌(Perfect Shuffle)问题

    [转]原博文地址:https://github.com/julycoding/The-Art-Of-Programming-By-July/blob/master/ebook/zh/02.09.md ...

  8. Dictionary摘抄

    Dictionary,字典,键值对集合. 下面的代码示例创建一个空的带有字符串键的字符串 Dictionary,并使用 Add 方法添加一些元素.该示例演示在尝试添加重复的键时 Add 方法引发Arg ...

  9. SQL SERVER作业的Schedules浅析

    SQL SERVER作业的计划(Schedules),如果你没仔细研究过或没有应用一些复杂的计划(Schedules),那么你觉得SQL SERVER作业的计划(Schedules)非常好用,也没啥问 ...

  10. Python之路:堡垒机实例

    堡垒机前戏 开发堡垒机之前,先来学习Python的paramiko模块,该模块机遇SSH用于连接远程服务器并执行相关操作 SSHClient 用于连接远程服务器并执行基本命令 基于用户名密码连接: 1 ...