Java有一种特殊的线程称为守护(daemon)线程。此类线程的优先级很低,通常只在同一程序中没有其他线程在运行时才运行。JVM在程序中没有非守护线程在运行、终止程序时才结束守护线程。
守护线程通常用作程序中其他普通(或称为用户)线程的服务提供者。 一般有一个无限循环等待服务请求或执行线程任务。 不能用它们执行重要的任务因为不知道它们什么时候会运行并可能在没有其他线程运行时的任意时间被结束。 一个典型的例子就是Java的垃圾收集线程。
本节的实现代码在 com.elanzone.books.noteeg.chpt1.sect08 package
数据类 (Event)
用户线程类 (WriterTask)
private Deque<Event> deque; public WriterTask(Deque<Event> deque) { this.deque = deque; }
for (int i = 1; i < 100; i++) { String eventName = String.format("The thread %s has generated an event", Thread.currentThread().getId()); deque.addFirst(new Event(eventName)); System.out.printf("deque's size: %d, evnet: %s\n", deque.size(), eventName); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } }
守护线程类 (CleanerTask)
private Deque<Event> deque; public CleanerTask(Deque<Event> deque) { this.deque = deque; setDaemon(true); // 设置为守护线程 }
while (true) { clean(new Date()); }
private void clean(Date date) { long difference; boolean delete; if (deque.size() == 0) { System.out.println("Cleaner: empty deque."); return; } delete = false; do { Event e = deque.getLast(); difference = date.getTime() - e.getDate().getTime(); if (difference > 10000) { System.out.printf("Cleaner: %s\n", e.getEvent()); deque.removeLast(); delete = true; } } while (difference > 10000); if (delete) { System.out.printf("Cleaner: Size of the queue: %d\n", deque. size()); } }
控制类 (Main)
Deque<Event> deque = new ArrayDeque<>();
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();
如果您分析程序执行的输出信息,您会看到队列不断增长直到有 30 个事件,然后大小在 27 和 30 个事件中变化,直到运行结束。
程序启动了 3 个 WriterTask 线程,每个线程写入 1 个事件并睡 1 秒。10 秒后,队列里有 30 个线程。 在这 10 秒中,CleanerTask 在 3 个 WriterTask 线程睡眠时执行,但是它不会删除事件,因为它们都是在 10 秒内生成的。 剩余执行过程中,CleanerTask 每秒删除 3 个事件,3 个 WriterTask 线程写入另外 3 个,所以队列中的事件数在 27 和 30 之间变化。
您可以改变 WriterTask 线程睡眠的时间。如果您使用一个较小的时间,您会看到 CleanerTask 运行时间更少,队列大小将变大,因为 CleanerTask 来不及删除事件。