zoukankan      html  css  js  c++  java
  • java concurrency: daemon线程

    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.

    下面是示例代码:

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

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

    Java代码  收藏代码
    1. dt is a daemon thread.  
    2. Sleeping in main thread.  
    3. ..........  
    4. Main thread ending.  

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

    Java代码  收藏代码
    1. Sleeping in main thread.  
    2. ..........  
    3. Main thread ending.  
    4. .......................  

    设置daemon线程的意义

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

    daemon线程的一些应用

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

    又一个daemon的示例

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

    具体的代码实现如下:

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

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

    Java代码  收藏代码
    1. Reminder set for 10/21/12 01:57:10 PM  
    2. ..  
    3. Call Harry  
    4.   
    5. ..................  
    6. Main thread ending.  

    总结

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

  • 相关阅读:
    同步、异步 与 阻塞、非阻塞
    【转】综合对比 Kafka、RabbitMQ、RocketMQ、ActiveMQ 四个分布式消息队列
    Kafka总结笔记
    SpringBoot笔记
    过滤器(Filter)和拦截器(Interceptor)的执行顺序和区别
    Java Lambda表达式
    腾讯云博客同步声明(非技术文)
    SpringBoot学习笔记(十七:异步调用)
    设计模式—— 十七:装饰器模式
    Java初级开发0608面试
  • 原文地址:https://www.cnblogs.com/googlemeoften/p/5769072.html
Copyright © 2011-2022 走看看