Java里有一种特殊的线程叫守护线程(Daemon)。这种线程的优先级很低,通常,当同一个应用程序里没有其他线程运行的时候,守护线程才运行。当没有其他线程的时候,守护线程执行结束后,jvm也将结束这个程序了。
因为这种特性,通常作为普通线程的服务提供者。它通常时无限循环的,以等待服务请求或者执行线程的任务。
它不能做重要的任务,因为我们不可能知道守护线程什么时候执行。
典型的例子就是java的垃圾回收器
范例:两个线程: 1. 普通线程: 每秒往deque里面添加Event; 2. 守护线程: 每十秒清除一次十秒前的Event;
普通进程:
package com.rr.current2.c1_6_daemon.test;
import java.util.Date;
import java.util.Deque;
import java.util.concurrent.TimeUnit;
/**
* Created by Isaac on 16-5-10.
* 1. 普通线程: 每秒往deque里面添加Event
*/
public class Task implements Runnable {
private Deque<Event> deque;
public Task(Deque<Event> deque) {
this.deque = deque;
}
@Override
public void run() {
for (int i = 0, len = 100; i < len; i++) {
Date date = new Date();
synchronized (this) {
deque.addFirst(new Event(date,
String.format("%s %s (%d)!",
Thread.currentThread().getName(), date, i)));
}
System.out.printf("%s 创建了一个事件(%d)!\n",
Thread.currentThread().getName(), i);
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
守护进程:
package com.rr.current2.c1_6_daemon.test;
import java.util.Date;
import java.util.Deque;
import java.util.concurrent.TimeUnit;
/**
* Created by Isaac on 16-5-10.
* 2. 守护线程: 每十秒清除一次十秒前的Event
*/
public class DaemonThread extends Thread {
private Deque<Event> deque;
public DaemonThread(Deque<Event> deque) {
this.deque = deque;
//可以在构造器中,设置守护进程
//setDaemon(true);
}
@Override
public void run() {
boolean flag;
Event event;
Date date;
while (true) {
//等待10秒
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
//从最后面取数据
flag = true;
date = new Date();
while (flag) {
if(deque.size() == 0)
return;
event = deque.getLast();
//大于十秒钟
if (date.getTime() - event.getCreatedTime().getTime() > 10000) {
deque.removeLast();
} else {
flag = false;
}
}
System.out.println("***************** 当前deque *****************");
for (Event aDeque : deque) {
System.out.println(aDeque.getInfo());
}
}
}
}
Event:
package com.rr.current2.c1_6_daemon.test;
import java.util.Date;
/**
* Created by Isaac on 16-5-10.
*/
public class Event {
private String info;
private Date createdTime;
public Event(Date createdTime, String info) {
this.info = info;
this.createdTime = createdTime;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
public Date getCreatedTime() {
return createdTime;
}
public void setCreatedTime(Date createdTime) {
this.createdTime = createdTime;
}
@Override
public String toString() {
return "Event{" +
"info='" + info + '\'' +
", createdTime=" + createdTime +
'}';
}
}
测试:
package com.rr.current2.c1_6_daemon.test;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Iterator;
/**
* Created by Isaac on 16-5-10.
* 两个线程:
* 1. 普通线程: 每秒往deque里面添加Event
* 2. 守护线程: 每十秒清除一次十秒前的Event
*/
public class Test {
public static void main(String[] args) {
Deque<Event> deque = new ArrayDeque<>();
//普通进程
Task task = new Task(deque);
//开启三个普通进程
for(int i = 0 , len = 3; i < len; i ++){
new Thread(task).start();
}
//守护进程
DaemonThread daemon = new DaemonThread(deque);
//需要在start()之前,设置daemon;一旦线程开始运行,将不能再修改守护状态;
daemon.setDaemon(true);
daemon.start();
System.out.println(daemon.isDaemon());
}
/**
* java.util.ArrayDeque是Deque接口的动态数组实现,容量会按需扩展,线程不安全。
* 作为栈使用比java.util.Stack快,作为队列使用比java.util.LinkedList快。
* 大多数的操作消耗常数时间。
*/
public void testDeque(){
Deque<Integer> deque = new ArrayDeque<>();
// 4, 3, 2, 1 -> []
// deque.addFirst(1);
// deque.addFirst(2);
// deque.addFirst(3);
// deque.addFirst(4);
// [] <- 1, 2, 3, 4
// deque.add(1);
// deque.add(2);
// deque.add(3);
// deque.add(4);
// [] <- 1, 2, 3, 4
// deque.addLast(1);
// deque.addLast(2);
// deque.addLast(3);
// deque.addLast(4);
// [] <- 1, 2, 3, 4
// deque.offer(1);
// deque.offer(2);
// deque.offer(3);
// deque.offer(4);
// 4, 3, 2, 1 -> []
// deque.offerFirst(1);
// deque.offerFirst(2);
// deque.offerFirst(3);
// deque.offerFirst(4);
// [] <- 1, 2, 3, 4
// deque.offerLast(1);
// deque.offerLast(2);
// deque.offerLast(3);
// deque.offerLast(4);
Iterator<Integer> it = deque.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
当把Task的休眠时间调小的时候,例如10ms,队列长度将不断增加,DaemonThread将不会被调用;
setDaemon()方法只能在start()方法被调用之前设置。一旦线程开始运行,将不能再修改守护状态了。
isDaemon()方法被用来检查一个线程是不是守卫线程,返回值为true表示这个线程时守护线程。
Daemon Thread 产生的新线程也是Daemon Thread。