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