Java多線程編程(7)--線程組與線程工廠

一.線程組

  實際上,線程組是一個設計失敗的概念。它最初是出於安全的考慮被設計用來隔離不同的applet(已過時)的。然而,ThreadGroup並未實現這一預期目標,並且它所實現的許多方法是有缺陷的。但是ThreadGroup仍然遺留在其他和線程有關的類中,因此這裏只是對它進行一個簡單的介紹。在大多數情況下,我們完全可以忽略線程組這一概念以及它的存在。
  一個線程組代表了一組線程。此外,一個線程組也能包含其他的線程組。線程與線程組的關係類似於文件和文件夾的關係,即一個文件總是位於特定的文件夾中,而一個文件夾可以包含多個文件和文件夾。通過線程組可以很方便的對多個線程進行管理。下圖展示了線程組與線程及其他線程組的關係:

  上面的線程和線程組組成了一棵樹,除了根線程組外,其他每個線程組都有一個父線程組。
  Thread類有幾個構造器允許我們在創建線程的時候指定其所屬的線程組。如果在創建線程的時候沒有指定線程組,那麼這個線程就屬於其父線程所屬的線程組。因此,每一個線程都一個線程組與之關聯。

1.成員變量

  Java中使用ThreadGroup類來表示線程組。先來看這個類有哪些成員變量:

  • parent:父線程組;
  • name:線程組名稱;
  • maxPriority:最大優先級。該線程組中的每個線程的優先級都不能超過這個值。
  • destroyed:該線程組是否已經被銷燬。
  • daemon:是否爲守護線程組。線程組是否爲守護線程組與其管理的線程是否爲守護線程沒有關係,但概念類似。即若某線程組爲守護線程組,則當該線程組的最後一個線程被停止或最後一個線程組被銷燬後,該線程組將會自動銷燬。
  • nUnstartedThreads:線程組中未啓動的線程個數。
  • nthreads:線程組中已啓動的線程個數,不包含子線程組中的線程;
  • threads:用來存儲線程組中線程的數組,不包含未啓動的線程;
  • ngroups:線程組中子線程組的個數,不包含子線程組中的線程組;
  • groups:用來存儲線程組中子線程組的數組。

2.構造方法

  接着繼續來看ThreadGroup的構造方法:

public ThreadGroup(String name) {
    this(Thread.currentThread().getThreadGroup(), name);
}

public ThreadGroup(ThreadGroup parent, String name) {
    this(checkParentAccess(parent), parent, name);
}

private ThreadGroup(Void unused, ThreadGroup parent, String name) {
    this.name = name;
    this.maxPriority = parent.maxPriority;
    this.daemon = parent.daemon;
    this.parent = parent;
    parent.add(this);
}

  ThreadGroup有兩個public的構造方法可以供我們使用,其中ThreadGroup(ThreadGroup parent, String name)可以指定父線程組,而ThreadGroup(String name)則默認以當前線程所在的線程組作爲父線程組。
  實際上,ThreadGroup還有一個無參的構造方法:

/**
 * Creates an empty Thread group that is not in any Thread group.
 * This method is used to create the system Thread group.
 */
private ThreadGroup() {     // called from C code
    this.name = "system";
    this.maxPriority = Thread.MAX_PRIORITY;
    this.parent = null;
}

  這個構造方法用於創建系統線程組,它會在JVM啓動的時候被底層C語言代碼來調用。系統線程組是所有線程組的祖先,它沒有父線程組。

3.成員方法

  下面介紹ThreadGroup的幾個成員方法:

  • int activeCount()

  返回線程組和子線程組中活躍的線程數。這是一個估值,因爲在遍歷線程的過程中,有些線程可能已經停止。

  • int activeGroupCount()

  返回線程組和子線程組中活躍的線程組數。線程組只有兩種狀態,active和destroyed,因此未被銷燬的線程組都是活躍的線程組。這也是一個估值,因爲在遍歷線程組的過程中,有些線程組可能已經被銷燬。

  • void destroy()

  銷燬當前線程組。若線程組已被銷燬或包含活躍的線程時該方法將會拋出異常。

  • int enumerate​(Thread[] list)

  將該線程組及子線程組中活躍的線程拷貝至指定的數組。

  • int enumerate​(Thread[] list, boolean recurse)

  將該線程組及子線程組(可選,recurse爲false時只拷貝該線程組中活躍的線程)中活躍的線程拷貝至指定的數組。

  • int enumerate​(ThreadGroup[] list)

  將該線程組及子線程組中活躍的線程組拷貝至指定的數組。

  • int enumerate​(ThreadGroup[] list, boolean recurse)

  將該線程組及子線程組(可選,recurse爲false時只拷貝該線程組中活躍的線程組)中活躍的線程組拷貝至指定的數組。

  • void interrupt()

  中斷線程組中所有的線程。

二.線程工廠

  ThreadFactory接口是Java中的線程工廠,它是工廠模式的一種體現。它定義瞭如下工廠方法:

public Thread newThread(Runnable r);

  通過自定義線程工廠,我們可以在創建線程時對線程進行一些設置,例如是否是守護線程,統一給線程命名,設置線程優先級,設置線程組等,這使得在創建多個線程時無需手動調用Thread類的構造方法。例如Executors的newFixedThreadPoll(int nThreads, ThreadFactory threadFactory)方法,該方法會返回一個包含固定數量線程的線程池(有關線程池的內容會在後面的文章中介紹),我們可以將線程工廠傳遞給這個方法,這樣線程池在創建線程時就會通過我們的線程工廠的方法去創建。
  例如,下面的線程工廠爲每一個線程都設置了統一格式的名字:

import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

public class MyThreadFactory implements ThreadFactory {
    private static final String THREAD_NAME_PREFIX = "mythread-";
    private static final AtomicInteger THREAD_NUMBER = new AtomicInteger(1);

    @Override
    public Thread newThread(Runnable r) {
        return new Thread(r, THREAD_NAME_PREFIX + THREAD_NUMBER.getAndIncrement());
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章