Java並發編程樣本(七):守護線程的建立和運行_java

來源:互聯網
上載者:User

Java有一種特殊線程,守護線程,這種線程優先順序特別低,只有在同一程式中的其他線程不執行時才會執行。

由於守護線程擁有這些特性,所以,一般用為為程式中的普通線程(也稱為使用者線程)提供服務。它們一般會有一個無限迴圈,或用於等待請求服務,或用於執行任務等。它們不可以做任何重要的工作,因為我們不確定他們什麼時才能分配到CPU已耗用時間,而且當沒有其他線程執行時,它們就會自動終止。這類線程的一個典型應用就是Java的記憶體回收。

在本節樣本中,我們將建立兩個線程,一個是普通線程,向隊列中寫入事件;另外一個是守護線程,清除隊列中的事件,刪除存在時間超過10秒的事件。

知其然

按照如下步驟,實現樣本程式。

1.建立Event類,該類僅僅用於儲存程式執行所需的事件資訊。聲明兩個屬性,一個是java.util.Date類型的的date熟悉,另外一個是String類型的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.聲明一個用來儲存事件的隊列屬性,實作類別的建構函式,並且利用其參數來初始化隊列屬性。代碼如下:

複製代碼 代碼如下:

private Deque<Event> deque;

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

4.實現該任務的run()方法,方法中含有一個遍曆100次的迴圈。在每次遍曆中,建立一個新的Event對象,然後儲存到隊列中,再睡眠1秒鐘。代碼如下:

複製代碼 代碼如下:

@Override
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的類,並繼承Thread類。代碼如下:

複製代碼 代碼如下:

public class CleanerTask extends Thread {

6.聲明一個用來儲存事件的隊列屬性,實作類別的建構函式,並且利用其參數來初始化隊列屬性。在構造方法中,通過調用setDaemon()方法,將該線程設定為守護線程。代碼如下:

複製代碼 代碼如下:

private Deque<Event> deque;

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

7.實現run()方法,方法體內有一個無限迴圈,用於擷取目前時間,然後調用clearn()方法。代碼如下:

複製代碼 代碼如下:

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

8.實現clean()方法,在該方法內,擷取最後面的一個時間,然後檢查時間時間和目前時間的時間差,如果在10秒鐘之前建立的,則刪除當前事件,再檢查下一個事件。如果有事件被刪除,則顯示列印出被刪除事件的資訊,然後還將列印出隊列的最新長度,這樣就可以觀察到程式的執行進展。代碼如下:

複製代碼 代碼如下:

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.getDate());
            deque.removeLast();
            delete = true;
        }
    } while (difference > 10000);

    if (delete) {
        System.out.printf("Clearner: 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<>();

11.建立並啟動三個WriterTask線程和一個CleanerTask線程。代碼如下:

複製代碼 代碼如下:

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();

12.執行程式,查看執行結果。

知其所以然

剖析器的執行結果就可以看出,隊列先增加到30,然後就在27到30之間變化,知道程式執行結束。

程式首先從三個WriterTask線程開始執行,每個線程先隊列增加一個事件,然後睡眠1秒鐘。在前10秒過後,在隊列中將存在三十個事件。在這10秒期間,當三個WriterTask線程都睡眠時,CleanerTask線程也會運行,但是不會刪除任何事件,因為所有的事件的產生時間還不超過10秒。在前10秒過後的時間裡,每秒鐘三個WriterTask向隊列中添加三個事件;同樣,CleanerTask每秒會刪除三個事件。所以,事件的數目在27到30之間徘徊。

當WriterTask線程都休眠時,我們就可以自由處理時間,這段時間讓守護線程得以運行。如果將WriterTask線程的睡眠時間設定得更短一點,那麼CleanerTask線程將擷取更少的CPU已耗用時間。果真如此的話,因為CleanerTask線程一直得不到足夠的已耗用時間不能用於刪除足夠的事件,隊列的長度將會一直增長下去。

永無止境

僅能在調用start()方法之前,通過調用setDaemon()方法將線程設定為守護線程。一旦線程開始運行,則不能修改守護狀態。

還可以使用isDaemon()來檢查一個線程是否為守護線程。如果是守護線程,則返回true;如果是普通線程,則返回false。

拿來主義

本文是從 《Java 7 Concurrency Cookbook》 (D瓜哥竊譯為 《Java7並發樣本集》 )翻譯而來,僅作為學習資料使用。沒有授權,不得用於任何商業行為。

小有所成

本節所用的所有範例程式碼的完整版。

Event類的完整代碼

複製代碼 代碼如下:

package com.diguage.books.concurrencycookbook.chapter1.recipe7;

import java.util.Date;

/**
 * 事件資訊類
 * Date: 2013-09-19
 * Time: 22:56
 */
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;
    }
}

WriterTask類的完整代碼

複製代碼 代碼如下:

package com.diguage.books.concurrencycookbook.chapter1.recipe7;

import java.util.Date;
import java.util.Deque;
import java.util.concurrent.TimeUnit;

/**
 * 每秒產生一個事件。
 * Date: 2013-09-19
 * Time: 22:59
 */
public class WriterTask implements Runnable {
    private Deque<Event> deque;

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

    @Override
    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();
            }
        }
    }
}

CleanerTask類的完整代碼

複製代碼 代碼如下:

package com.diguage.books.concurrencycookbook.chapter1.recipe7;

import java.util.Date;
import java.util.Deque;

/**
 * 事件清理
 * Date: 2013-09-19
 * Time: 23:33
 */
public class CleanerTask extends Thread {
    private Deque<Event> deque;

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

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

    /**
     * 刪除事件。
     *
     * @param date
     */
    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.getDate());
                deque.removeLast();
                delete = true;
            }
        } while (difference > 10000);

        if (delete) {
            System.out.printf("Clearner: Size of the queue: %d\n", deque.size());
        }
    }
}

Main類的完整代碼

複製代碼 代碼如下:

package com.diguage.books.concurrencycookbook.chapter1.recipe7;

import java.util.ArrayDeque;
import java.util.Deque;

/**
 * Date: 2013-09-19
 * Time: 23:54
 */
public class Main {
    public static void main(String[] args) {
        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();
    }
}


相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.