java里有一种特殊的线程叫做守护线程(Daemon)线程。这种线程的优先级很低,通常来说,当同一个应用程序里没有其他的线程运行的时候,守护线程才运行。当程序中唯一运行的的线程是守护线程时,并且守护线程执行结束后 ,JVM也就结束了这个程序。

    因为这种特性,守护线程通常被用来作为同一程序中普通线程(用户线程)的服务提供者。它们通常是无线循环的,以等待服务请求或者执行线程的任务。它们不能做重要工作,因为我们不可能知道守护线程什么时候获取CPU时钟,并且,在没有其他线程运行时,守护线程随时可以结束。典型应用就是JAVA GC。

      如何创建守护线程,写一个简单的DEMO。场景如下:有两线程,一种是用户线程,它将事件写到一个队列中。另一个是守护线程。他将管理这个队列。如果生成的事件超过10秒钟,就会被移除。

     1.创建一个Event类。在类中声明两个私有属性,一个日期类型属性date;另一个字符串类型的属性event.并生成这两个属性的读写方法。

 

public class Event {
     private Date date;
     private String event;
    public Date getDate() {
        return date;
    }
    public void setDate(Date date) {
        this.date = date;
    }
    public String getEvent() {
        return event;
    }
    public void setEvent(String event) {
        this.event = event;
    }

  2.创建WriterTask类,用以实现Runnable接口。

     public class WriterTask implements Runnable{}

  3.声明一个存放Event对象的队列,并实现带参数的构造器,来初始化这个队列对象。  

Deque<Event> deque;

    public WriterTask(Deque<Event> deque) {
        this.deque = deque;
    }

   4.实现线程的run()方法。它将执行100次循环。在每次循环中,都会创建一个新的Event对象,并放入队列中。然后休眠一秒钟。

public void run(){
        for (int i=0;i<100;i++){
            Event event=new Event();
            event.setDate(new Date());
            event.setEvent(String.format("The thread %s has generated an event", Thread.currentThread().getId()));
            deque.addFirst(event);
            try{
                TimeUnit.SECONDS.sleep(1);
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
    }

   5.创建CleanerTask类并继承Thrad类。 

public class CleanerTask extends Thread{}

   6.声明存放Event对象的队列,并实现构造器,来初始化这个队列对象。同时,在这个构造器中,通过setDaemon()方法把这个线程设置为守护线程。

Deque<Event> deque;
       public CleanerTask(Deque<Event> deque) {
          this.deque = deque;
          setDaemon(true);
    }

    7.实现run()方法,它会无限制的重复运行,在每次运行中,将获取当前的时间,并调用clean()方法。

public void run(){
        while(true){
            Date date=new Date();
            clean(date);
        }
    }

   8.实现clean()方法。clean()方法将读取队列的最后一个事件对象,如果这个事件是10秒种前创建的,就将它删除并且检查下一个。如果有事件被删除,clean()讲打印被删除事件信息,讲打印队列长度。

public void clean(Date date){
        long diffrence;
        boolean delete;
        if(deque.size()==0){
            return;
        }
        delete=false;
        do{
            Event e=deque.getLast();
            diffrence=date.getTime()-e.getDate().getTime();
            if(diffrence>10000){
                System.out.printf("Cleaner:%s\n",e.getEvent());
                deque.removeLast();
                delete=true;
            }
        }while(diffrence>10000);
        if(delete){
            System.out.printf("Cleaner: Size of the queue: %d\n",deque.size());
   }
   
   }public void clean(Date date){
        long diffrence;
        boolean delete;
        if(deque.size()==0){
            return;
        }
        delete=false;
        do{
            Event e=deque.getLast();
            diffrence=date.getTime()-e.getDate().getTime();
            if(diffrence>10000){
                System.out.printf("Cleaner:%s\n",e.getEvent());
                deque.removeLast();
                delete=true;
            }
        }while(diffrence>10000);
        if(delete){
            System.out.printf("Cleaner: Size of the queue: %d\n",deque.size());
   }

  9.创建一个包含main()方法的Main主类。

public class Main {
      public static void main(String[] args) {}}

  10.创建一个队列对象Deque,用来存放事件。

Deque<Event> deque=new ArrayDeque<Event>();

   11.创建三个WriterTask线程和一个CleanerTask线程,并启动。

WriterTask writer=new WriterTask(deque);
        for(int i=0;i<3;i++){
            Thread thread=new Thread(writer);
            thread.start();
        }
        CleanerTask cleaner=new CleanerTask(deque);
        cleaner.start();
    }
}

   12.运行,查看结果。发现,队列对象会不断增长到30个,然后到程序结束,队列长度维持在27-30之间,