1. 程式人生 > >執行緒管理(七)守護執行緒的建立和執行

執行緒管理(七)守護執行緒的建立和執行

宣告:本文是《 Java 7 Concurrency Cookbook 》的第一章, 作者: Javier Fernández González 譯者:鄭玉婷 校對:方騰飛

守護執行緒的建立和執行

Java有一種特別的執行緒叫做守護執行緒。這種執行緒的優先順序非常低,通常在程式裡沒有其他執行緒執行時才會執行它。當守護執行緒是程式裡唯一在執行的執行緒時,JVM會結束守護執行緒並終止程式。

根據這些特點,守護執行緒通常用於在同一程式裡給普通執行緒(也叫使用者執行緒)提供服務。它們通常無限迴圈的等待服務請求或執行執行緒任務。它們不能做重要的任務,因為我們不知道什麼時候會被分配到CPU時間片,並且只要沒有其他執行緒在執行,它們可能隨時被終止。JAVA中最典型的這種型別代表就是垃圾回收器。

在這個指南中, 我們將學習如何建立一個守護執行緒,開發一個用2個執行緒的例子;我們的使用執行緒會寫事件到queue, 守護執行緒會清除queue裡10秒前建立的事件。

準備

指南中的例子是使用Eclipse IDE 來實現的。如果你使用Eclipse 或者其他的IDE,例如NetBeans, 開啟並建立一個新的java專案。

怎麼做呢

按照這些步驟來實現下面的例子:

1.   建立 Event 類. 這個類只是用來儲存我們程式裡的工作的事件資訊。宣告2個屬性,一個是java. util.Date 型別的 date 和另一個是String 型別的event 。並生成它們的讀值和寫值方法。

2.   建立 WriterTask 類並實現Runnable介面。

public class WriterTask implements Runnable {

3.   宣告queue,儲存事件並實現類的建構函式,初始化queue。

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

4.   實現這個任務的 run() 方法 。 此方法有100個迴圈。在每個迴圈中我們會建立 一個Event物件,並儲存到 queue裡, 然後休眠1秒。

@Override
public void run() {
for (int i=1; 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 類並一定擴充套件Thread類。

public class CleanerTask extends Thread {

6.   宣告 queue,儲存事件並實現類的建構函式,初始化queue,在這個建構函式,用setDaemon() 方法讓此執行緒成為守護執行緒。

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

7.   實現run()方法。它是無限迴圈來獲取當前日期並呼叫 clean() 方法.

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

8.   實現 clean() 方法. 它獲取最後的事件,如果它在10秒前被建立,就刪除它並檢視下一個事件。如果一個事件被刪除,它會寫一個事件資訊和queue的新的大小,為了讓你看到變化過程。

private void clean(Date date) {
  long difference;
  boolean delete;
  if (deque.size()==0) {
    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());
  }
}

9.   現在實現主類。 建立一個類名為 Main 和 main() 方法。

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

10. 建立使用 Deque 類的queue 來儲存事件。

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

11. 建立 和開始3個 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. 執行程式檢視結果。

它是怎麼工作的

如果分析這個程式的輸出,你可以發現queue可以一直增加直到它有30個事件,然後它的大小會在27-30之間直到執行結束。

程式開始時有3個 WriterTask 執行緒。每個執行緒寫一個事件然後休眠1秒。10秒之後,我們有30個事件在queue裡。在這10秒內,當3個 WriterTask 執行緒休眠時, CleanerTasks已經開始執行,但是它沒有刪除任何事件,因為所有事件都才生成不到10秒。在剩下的執行裡,CleanerTask 每秒刪除3個事件, 然而3個 WriterTask 執行緒會另寫3個,所以queue的大小在27-30之間。

你可以修改 WriterTask 執行緒的休眠時間。如果你使用一個較小的值,你會發現CleanerTask 被分配到 CPU 時間片會更少,由於 CleanerTask 沒有刪除任何事件,所以queue大小會一直增加。

更多

只能在start() 方法之前可以呼叫 setDaemon() 方法。一旦執行緒運行了,就不能修改守護狀態。

可以使用 isDaemon() 方法來檢查執行緒是否是守護執行緒(方法返回 true) 或者是使用者執行緒 (方法返回 false)。