daemon线程的概念

在学习操作系统概念的时候,我们就曾听说过daemon的概念。daemon本身指的是在后台运行的进程或者线程,一般用来提供某些不需要与用户直接交互的服务,有点像我们见到的一些系统服务。在java线程中,一般可以分为两类,一类是普通的线程,就是那些我们通过常用的Thread类或者Runnable接口实现并启动的类。还有一类是daemon线程。这种线程也通过和创建普通线程同样的方式来创建,不过需要通过setDaemon方法设置为daemon线程。

daemon线程有几个典型的特征:

1. daemon线程是运行于后台的,不和用户直接交互。

2. 相对普通的线程来说,daeomn线程可以说是普通线程的下属,它的优先级要低一些。

3. daemon线程具有一定程度的继承性,这个继承性不是指类的继承,而是指当一个daemon线程创建一个新线程的话,这个新创建的线程就默认为daemon线程了。

4. 和普通线程的退出机制不同,在jvm即将关闭的时候,普通线程需要执行一系列的记录或者退出方法,比如需要执行finalize方法的则需要执行这部分,有finally块的代码也必须执行。而daemon线程退出的时候,jvm直接将它丢弃并退出,里面就算有finally块定义的代码也不会被执行。

一个daemon线程的示例

创建或者使用daemon线程一般包括一下3个步骤:

1. 如果线程本身就是daemon线程了,那么通过常规线程创建手段创建出来的就已经是daemon线程。

2. 如果通过普通线程创建创建出来的话,需要在启动线程前调用setDaemon()方法。切记,一定要在调用start()方法前。

3.我们可以通过调用isDaemon()方法来判断一个线程是否为daeomn.

下面是示例代码:

  1. class MyDaemon implements Runnable
  2. {
  3. Thread thrd;
  4. MyDaemon()
  5. {
  6. // Create the thread
  7. thrd = new Thread(this);
  8. // Set to daemon
  9. thrd.setDaemon(true);
  10. // Start the thread
  11. thrd.start();
  12. }
  13. public void run()
  14. {
  15. try
  16. {
  17. for(;;)
  18. {
  19. System.out.print(".");
  20. Thread.sleep(1000);
  21. }
  22. }
  23. catch(InterruptedException exc)
  24. {
  25. System.out.println("MyDaemon interrupted.");
  26. }
  27. }
  28. }
  29. class DaemonDemo
  30. {
  31. public static void main(String[] args)
  32. {
  33. MyDaemon dt = new MyDaemon();
  34. if(dt.thrd.isDaemon())
  35. System.out.println("dt is a daemon thread.");
  36. System.out.println("Sleeping in main thread.");
  37. try
  38. {
  39. Thread.sleep(10000);
  40. }
  41. catch(InterruptedException exc)
  42. {
  43. System.out.println("Main thread interrupted.");
  44. }
  45. System.out.println("\nMain thread ending.");
  46. }
  47. }

在上面的代码中,我们实现Runnable接口定义一个MyDaemon类,在构造函数中调用setDaemon()设置该线程为daemon.在main方法中启动MyDaemon线程之后,main方法结束时daemon线程也自动结束了。上述代码的执行结果如下:

  1. dt is a daemon thread.
  2. Sleeping in main thread.
  3. ..........
  4. Main thread ending.

一个比较有意思的事情就是,如果我们将前面代码里setDaemon()方法的这一行注释了,也就是说将该线程设置为普通的用户线程,再执行上面的代码时,我们会发现,程序不会终止,会一直执行下去,虽然主线程已经结束了。其输出的结果会像如下所示:

  1. Sleeping in main thread.
  2. ..........
  3. Main thread ending.
  4. .......................

设置daemon线程的意义

从前面的理解来看,daemon线程有点像一个我们画的草图,随时可以丢弃。它一般是用于在jvm关闭的时候,我们需要启动一些线程做一些辅助性的工作,但是我们又不希望这种工作妨碍到jvm正常关闭。和其他正常的线程来说,或许我们应该称之为不碍事的线程更合适。

daemon线程的一些应用

daemon线程在java中有很多地方用到,一个典型的就是垃圾回收的GC线程。另外如果我们需要用线程做一些比如时间提醒,标记等事情,采用daemon线程也是一个比较合适的选择。

又一个daemon的示例

根据前面的理解,我们再尝试一个更复杂的daemon应用。假定我们在一个应用中需要定义一些时间通知,比如说设置在某个指定的时候弹出一个会议通知的提醒。这是一个比较常见的场景,可以用daemon线程来实现。

具体的代码实现如下:

  1. import java.util.*;
  2. class Reminder implements Runnable
  3. {
  4. Calendar reminderTime;
  5. String message;
  6. Reminder(String msg, int delay)
  7. {
  8. message = msg;
  9. // Get the current time and date.
  10. reminderTime = Calendar.getInstance();
  11. // Add the delay to the time and date.
  12. reminderTime.add(Calendar.SECOND, delay);
  13. System.out.printf("Reminder set for %tD %1$tr\n", reminderTime);
  14. // Create the reminder thread.
  15. Thread dThrd = new Thread(this);
  16. // Set to daemon
  17. dThrd.setDaemon(true);
  18. // Start execution.
  19. dThrd.start();
  20. }
  21. // Run the reminder.
  22. public void run()
  23. {
  24. try
  25. {
  26. for(;;)
  27. {
  28. // Get the current time and date.
  29. Calendar curTime = Calendar.getInstance();
  30. // See if it's time for the reminder.
  31. if(curTime.compareTo(reminderTime) >= 0)
  32. {
  33. System.out.println("\n" + message + "\n");
  34. break;
  35. }
  36. Thread.sleep(1000);
  37. }
  38. }
  39. catch(InterruptedException exc)
  40. {
  41. System.out.println("Reminder interrupted.");
  42. }
  43. }
  44. }
  45. class ReminderDemo
  46. {
  47. public static void main(String[] args)
  48. {
  49. // Get a reminder 2 seconds from now.
  50. Reminder mt = new Reminder("Call Harry", 2);
  51. // Keep the main thread alive for 20 seconds.
  52. for(int i = 0; i < 20; i++)
  53. {
  54. try
  55. {
  56. Thread.sleep(1000);
  57. }
  58. catch(InterruptedException exc)
  59. {
  60. System.out.println("Main thread interrupted.");
  61. }
  62. System.out.print(".");
  63. }
  64. System.out.println("\nMain thread ending.");
  65. }
  66. }

我们设置了一个daemon线程,在一个无限循环里比较当前时间和指定的时间,在达到指定的时间时则显示一个提醒消息。上述代码的输出如下:

  1. Reminder set for 10/21/12 01:57:10 PM
  2. ..
  3. Call Harry
  4. ..................
  5. Main thread ending.

总结

悄悄的,daemon线程走了,正如daemon线程悄悄的来;挥一挥手,带不走jvm的一片云彩:)

java concurrency: daemon线程的更多相关文章

  1. 【转】关于Java的Daemon线程的理解

    原文地址:http://www.cnblogs.com/ChrisWang/archive/2009/11/28/1612815.html 关于Java的Daemon线程的理解 网上对Java的Dae ...

  2. 深入浅出 Java Concurrency (35): 线程池 part 8 线程池的实现及原理 (3)[转]

    线程池任务执行结果 这一节来探讨下线程池中任务执行的结果以及如何阻塞线程.取消任务等等. 1 package info.imxylz.study.concurrency.future;2 3 publ ...

  3. 深入浅出 Java Concurrency (34): 线程池 part 7 线程池的实现及原理 (2)[转]

    线程池任务执行流程 我们从一个API开始接触Executor是如何处理任务队列的. java.util.concurrent.Executor.execute(Runnable) Executes t ...

  4. 深入浅出 Java Concurrency (33): 线程池 part 6 线程池的实现及原理 (1)[转]

    线程池数据结构与线程构造方法 由于已经看到了ThreadPoolExecutor的源码,因此很容易就看到了ThreadPoolExecutor线程池的数据结构.图1描述了这种数据结构. 图1 Thre ...

  5. 深入浅出 Java Concurrency (30): 线程池 part 3 Executor 生命周期[转]

    我们知道线程是有多种执行状态的,同样管理线程的线程池也有多种状态.JVM会在所有线程(非后台daemon线程)全部终止后才退出,为了节省资源和有效释放资源关闭一个线程池就显得很重要.有时候无法正确的关 ...

  6. 深入浅出 Java Concurrency (28): 线程池 part 1 简介[转]

    从这一节开始正式进入线程池的部分.其实整个体系已经拖了很长的时间,因此后面的章节会加快速度,甚至只是一个半成品或者简单化,以后有时间的慢慢补充.完善. 其实线程池是并发包里面很重要的一部分,在实际情况 ...

  7. 深入浅出 Java Concurrency (36): 线程池 part 9 并发操作异常体系[转]

    并发包引入的工具类很多方法都会抛出一定的异常,这些异常描述了任务在线程池中执行时发生的例外情况,而通常这些例外需要应用程序进行捕捉和处理. 例如在Future接口中有如下一个API: java.uti ...

  8. 深入浅出 Java Concurrency (29): 线程池 part 2 Executor 以及Executors[转]

    Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具.真正的线程池接口是ExecutorService. 下面这张图完整描述了线程 ...

  9. Java Concurrency - 取消线程执行器中的线程

    When you work with an executor, you don't have to manage threads. You only implement the Runnable or ...

随机推荐

  1. codeforces 632D. Longest Subsequence 筛法

    题目链接 记录小于等于m的数出现的次数, 然后从后往前筛, 具体看代码. #include <iostream> #include <vector> #include < ...

  2. codeforces 455C 并查集

    传送门 给n个点, 初始有m条边, q个操作. 每个操作有两种, 1是询问点x所在的连通块内的最长路径, 就是树的直径. 2是将x, y所在的两个连通块连接起来,并且要合并之后的树的直径最小,如果属于 ...

  3. python2.7_1.14_编写一个简单的回显客户端/服务器应用

    1.服务端 server.py # -*- coding: utf-8 -*- import socket import argparse host = 'localhost' data_payloa ...

  4. 07-2. A+B和C (15)

    给定区间[-231, 231]内的3个整数A.B和C,请判断A+B是否大于C. 输入格式: 输入第1行给出正整数T(<=10),是测试用例的个数.随后给出T组测试用例,每组占一行,顺序给出A.B ...

  5. 完美解决CTRL+空格不能切换中/英文输入法的问题

    首先任务栏上的输入法图标上点右键选择设置. 然后选择键设置,双击第一个“在不同的输入语言之间切换”先勾选“切换输入语言”下面选择左手ALT.取消右边“切换键盘布局”前的勾. 然后进入“中文(简体)输入 ...

  6. clistctrl 虚拟列表

    一.什么是虚拟列表控件 虚拟列表控件是指带有LVS_OWNERDATA风格的列表控件.. 二.为什么使用虚拟列表控件 我们知道,通常使用列表控件CListCtrl,需要调用InsertItem把要显示 ...

  7. How to get the xpath by clicking an html element

    How to get the xpath by clicking an html element How to get the xpath by clicking an html element

  8. ural 1057(数位dp)

    数位dp题,关键是用树的思维去考虑. 对于一个数字X,要是能表示成K个B的不同次幂,等价于X在B进制下有且只有K个位上面的数字为一,其他位上的数字都为0. 具体读者可以去参考,国家集训队李聪的论文,里 ...

  9. 编译器DIY——词法分析

    在上一篇文章中已经介绍了读文件的操作,那么这一篇文章中将会细致解释词法分析. 在源文件里解析出的单词流必须识别为保留字,标识符,常量,操作符和界符五大类 1.显然我们须要列举出全部的保留字,而这里与保 ...

  10. 虎说:bootstrap源码解读(重置模块)

    ------<!--action-->------ 开场show:前不生“不犹豫”,后半生“不后悔”.今天又逃课,我不后悔 素材:推特公司的前端框架bootstrap(下称bt),解读源码 ...