16-线程组

Java 使用 ThreadGroup 来表示线程组,它可以对一批线程进行分类管理,Java 允许程序直接对线程组进行控制,对线程组的控制相当于同时控制这批线程。

如果没有显式指定,则用户创建的线程属于默认线程组。而且,子线程和创建它的父线程处于同一个线程组内。一旦某个线程加入了指定线程组之后,该线程将一直属于该线程组,直到该线程死亡。

Thread 类提供了如下几个构造器来设置新创建的线程属于哪个线程组:

  • Thread(ThreadGroup group,Runnable target):以 target 的 run() 方法作为线程执行体创建新线程,属于 group 线程组。
  • Thread(ThreadGroup group,Runnable target,String name):以 target 的 run() 方法作为线程执行体创建新线程,属于 group 线程组,且线程名为 name。
  • Thread(ThreadGroup group,String name):创建新线程,名为 name,属于 group 线程组。

ThreadGroup 类提供了如下两个简单的构造器来创建实例:

  • ThreadGroup(String name):以指定的线程组名字来创建新的线程组。
  • ThreadGroup(ThreadGroup parent,String name):以指定的名字、指定的父线程组创建一个新线程组。

通过 Thread 类提供的 getThreadGroup() 方法来返回该线程组所属的线程组。还可以通过 ThreadGroup 类的 getName() 方法获取线程组的名字,但不允许改变线程组的名字。

ThreadGroup 类提供了几个常用的方法来操作整个线程组的所有线程:

  • int activeCount():返回此线程组中活动线程的数目。
  • interrupt():中断此线程组中的所有线程。
  • isDaemon():判断该线程组是否是后台线程组。
  • setDaemon(boolean daemon):把该线程组设置成后台线程组,当最后一个线程执行完后,后台线程组被自动销毁。
  • setMaxPriority(int pri):设置线程组的最高优先级。

ThreadGroup 内定义了一个很有用的方法:void uncaughtException(Thread t,Throwable e),该方法可以处理该线程组内的任意线程所抛出的未处理异常。如果线程执行过程中抛出了一个未处理异常,JVM 在结束该线程之前会自动查找是否有对应的 Thread.UncaughtExceptionHandler 对象,如果找到该处理器对象,则会调用该对象的 uncaughtException(Thread t,Throwable e) 方法来处理该异常。

Thread.UncaughtExceptionHandler 是 Thread 类的一个静态内部接口,该接口内只有一个方法:void uncaughtException(Thread t,Throwable e),该方法中的 t 代表出现异常的线程,而 e 代表该线程抛出的异常。Thread 类提供了两个方法来设置异常处理器:

  • static setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh):为该线程类的所有线程实例设置默认的异常处理器。
  • setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh):为指定的线程实例设置异常处理器。

线程组处理异常的默认流程如下:

  1. 如果该线程组有父线程,则调用父线程组的 uncaughtException() 方法来处理该异常。
  2. 如果该线程实例所属的线程类有默认的异常处理器(由setDefaultUncaughtExceptionHandler()方法设置的异常处理器),那么就调用该异常处理器来处理该异常。
  3. 如果该异常对象是 ThreadDeath 的对象,则不做任何处理;否则,将异常跟踪栈的信息打印到 System.err 错误输出流,并结束该线程。