Java併發編程初級篇(九):線程組

Java API提供了一個線程組類ThreadGroup,這個類提供了一些方法可讓咱們方便地對加入這個線程組的多個線程進行操做。java

想使用線程組首先須要實例化一個線程組對象,並把建立的線程加入到這個線程組中。數組

ThreadGroup group = new ThreadGroup("Searcher");
Thread thread = new Thread(group, Runnable r);

查看Thread的源代碼,咱們發如今初始化Thread線程對象後,只是把ThreadGroup對象賦值給Thread類的group屬性,只有當調用start()方法啓動線程的時候,才真正的把線程加入到了線程組中。dom

/* The group of this thread */
private ThreadGroup group;

private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc) {
  ...
  this.group = g;
  ...
)

public synchronized void start() {
  ...
  group.add(this);
  ...
)

下面咱們經過一個例子來看一看ThreadGroup爲咱們提供了那些有用的方法。ide

先定義一個Runnable類,在這個類中咱們讓線程休眠一個隨機時間,若是在這個休眠時間內線程被中斷那麼打印中斷信息,而後結束線程。若是線程成功執行完畢那麼打印線程結束信息。this

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        Random random = new Random(new Date().getTime());
        int value = (int)(random.nextDouble() * 100);
        System.out.printf("%s: Started and sleep %ds.\n", Thread.currentThread().getName(), value);
        try {
            TimeUnit.SECONDS.sleep(value);
        } catch (InterruptedException e) {
            System.out.printf("%s: Interrupted.\n", Thread.currentThread().getName());
            return;
        }
        System.out.printf("%s: End.\n", Thread.currentThread().getName());
    }
}

定義主方法類,咱們建立10個線程並加入到線程組中。線程

public class Main {
    public static void main(String[] args) {
        ThreadGroup group = new ThreadGroup("ThreadGroup");

        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(group, new MyRunnable());
            thread.start();

            try {
                TimeUnit.MILLISECONDS.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //獲取線程組中線程數量,並打印每個線程信息。
        System.out.printf("%s: Number of threads is %s.\n", Thread.currentThread().getName(), group.activeCount());
        group.list();

        //使用一個線程數組接收線程組中的全部線程
        Thread[] threads = new Thread[group.activeCount()];
        group.enumerate(threads);
        for (int i = 0; i < threads.length; i++) {
            System.out.printf("%s - %s\n", threads[i].getName(), threads[i].getState());
        }

        //等待第一個線程結束,而後中斷剩餘全部線程
        while (group.activeCount() > 9) {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        group.interrupt();
    }
}

查看控制檯日誌來對ThreadGroup類的相關方法作一個解釋。日誌

首先建立並啓動線程,線程內部打印啓動信息:code

Thread-0: Started and sleep 37s.
Thread-1: Started and sleep 33s.
Thread-2: Started and sleep 28s.
Thread-3: Started and sleep 13s.
Thread-4: Started and sleep 9s.
Thread-5: Started and sleep 12s.
Thread-6: Started and sleep 7s.
Thread-7: Started and sleep 2s.
Thread-8: Started and sleep 34s.
Thread-9: Started and sleep 30s.

接下來調用了ThreadGroup.activeCount()獲取了線程組內的線程數量,並調用ThreadGroup.list()打印線程組內線程信息。對象

main: Number of threads is 10.
java.lang.ThreadGroup[name=ThreadGroup,maxpri=10]
    Thread[Thread-0,5,ThreadGroup]
    Thread[Thread-1,5,ThreadGroup]
    Thread[Thread-2,5,ThreadGroup]
    Thread[Thread-3,5,ThreadGroup]
    Thread[Thread-4,5,ThreadGroup]
    Thread[Thread-5,5,ThreadGroup]
    Thread[Thread-6,5,ThreadGroup]
    Thread[Thread-7,5,ThreadGroup]
    Thread[Thread-8,5,ThreadGroup]
    Thread[Thread-9,5,ThreadGroup]

下面調用ThreadGroup.enumerate(threads)方法用一個線程數組來接收線程組內的線程,並打印線程狀態接口

Thread-0 - TIMED_WAITING
Thread-1 - TIMED_WAITING
Thread-2 - TIMED_WAITING
Thread-3 - TIMED_WAITING
Thread-4 - TIMED_WAITING
Thread-5 - TIMED_WAITING
Thread-6 - TIMED_WAITING
Thread-7 - TIMED_WAITING
Thread-8 - TIMED_WAITING
Thread-9 - TIMED_WAITING

最後咱們等待第一個完成的線程後,利用ThreadGroup.interrupt()中斷剩餘全部線程。

Thread-7: End.
Thread-0: Interrupted.
Thread-2: Interrupted.
Thread-1: Interrupted.
Thread-9: Interrupted.
Thread-8: Interrupted.
Thread-4: Interrupted.
Thread-5: Interrupted.
Thread-6: Interrupted.
Thread-3: Interrupted.

另外經過查看ThreadGroup類的源代碼你會發現他實現了異常處理接口Thread.UncaughtExceptionHandler,並重寫了方法uncaughtException(),固然你也能夠定義本身的類MyThreadGroup extends ThreadGroup,並重寫uncaughtException()來實現本身的線程運行時異常處理邏輯。ThreadGroup類中使用的是Thread.getDefaultUncaughtExceptionHandler()來處理異常,要想讓這個邏輯起做用,你須要使用Thread.setDefaultUncaughtExceptionHandler()靜態方法來爲Thread設置靜態默認異常處理器,若是沒有定義,一樣線程會在控制檯打印異常堆棧信息。

線程組中線程出現運行時異常會首先調用本身的異常處理器,若是沒有定義則會調用線程組的異常處理器,若是尚未定義就會調用默認的異常處理器,而且當線程組中的一個線程拋出異常以後,其他線程都會設置中斷狀態。

public class ThreadGroup implements Thread.UncaughtExceptionHandler {
	public void uncaughtException(Thread t, Throwable e) {
	    if (parent != null) {
	        parent.uncaughtException(t, e);
	    } else {
	        Thread.UncaughtExceptionHandler ueh =
	            Thread.getDefaultUncaughtExceptionHandler();
	        if (ueh != null) {
	            ueh.uncaughtException(t, e);
	        } else if (!(e instanceof ThreadDeath)) {
	            System.err.print("Exception in thread \""
	                             + t.getName() + "\" ");
	            e.printStackTrace(System.err);
	        }
	    }
	}
}
相關文章
相關標籤/搜索