Java多线程 5 多线程其他知识简要介绍

一、线程组

  1. /**
  2. * A thread group represents a set of threads. In addition, a thread
  3. * group can also include other thread groups. The thread groups form
  4. * a tree in which every thread group except the initial thread group
  5. * has a parent.
  6. * <p>
  7. * A thread is allowed to access information about its own thread
  8. * group, but not to access information about its thread group's
  9. * parent thread group or any other thread groups.
  10. *
  11. * @author  unascribed
  12. * @version 1.66, 03/13/08
  13. * @since   JDK1.0
  14. */

一个线程组代表了一系列的线程。并且,一个线程组可以包括其他的线程组。除了初始线程组外,每个线程组都有一个父线程组,类似于树的结构。

一个线程可以访问它所在线程组的信息, 不可以访问它父线程组和其他线程组的信息。

从这段话中可以大概明白线程组的概念,所有的线程和线程组构成一个树的结构,如下:

Java多线程 5 多线程其他知识简要介绍

查看Thread的API,可以看到,创建一个线程可以指定它的线程组和不指定线程组。如果指定其所属的线程组,那么该线程组是创建它的线程所属线程组的子线程组。如果不指定线程组,则属于默认情况,该线程和创建它的线程在同一个线程组。

以上面的图举个简单的例子:

如果main线程创建了Thread1线程,没有指定Thread1所在的线程组,那么Thread1就默认和main线程属于同一个线程组,即系统线程组。

如果main线程创建了Thread3线程,没指定Thread3所在的线程组为线程组1,那么线程组1就属于系统线程组,和main线程在树结构中平级。

一旦某个线程加入了指定线程组之后,该线程将一直属于该线程组,直到该线程死亡,线程运行中途不能改变它所属的线程组。因为指定线程所在线程组是在创建线程的视乎完成的,所以之后不能再修改它所在的线程组。

下面是ThreadGroup的方法摘要

方法摘要
 int activeCount()
          返回此线程组中活动线程的估计数。
 int activeGroupCount()
          返回此线程组中活动线程组的估计数。
 boolean allowThreadSuspension(boolean b)
          已过时。 此调用的定义取决于 suspend(),它被废弃了。更进一步地说,此调用的行为从不被指定。
 void checkAccess()
          确定当前运行的线程是否有权修改此线程组。
 void destroy()
          销毁此线程组及其所有子组。
 int enumerate(Thread[] list)
          把此线程组及其子组中的所有活动线程复制到指定数组中。
 int enumerate(Thread[] list, boolean recurse)
          把此线程组中的所有活动线程复制到指定数组中。
 int enumerate(ThreadGroup[] list)
          把对此线程组中的所有活动子组的引用复制到指定数组中。
 int enumerate(ThreadGroup[] list, boolean recurse) 
          把对此线程组中的所有活动子组的引用复制到指定数组中。
 int getMaxPriority()
          返回此线程组的最高优先级。
 String getName()
          返回此线程组的名称。
 ThreadGroup getParent()
          返回此线程组的父线程组。
 void interrupt()
          中断此线程组中的所有线程。
 boolean isDaemon()
          测试此线程组是否为一个后台程序线程组。
 boolean isDestroyed()
          测试此线程组是否已经被销毁。
 void list()
          将有关此线程组的信息打印到标准输出。
 boolean parentOf(ThreadGroup g)
          测试此线程组是否为线程组参数或其祖先线程组之一。
 void resume()
          已过时。 此方法只用于联合 Thread.suspend 和 ThreadGroup.suspend 时,因为它们所固有的容易导致死锁的特性,所以两者都已废弃。有关详细信息,请参阅Thread.suspend()
 void setDaemon(boolean daemon)
          更改此线程组的后台程序状态。
 void setMaxPriority(int pri)
          设置线程组的最高优先级。
 void stop()
          已过时。 此方法具有固有的不安全性。有关详细信息,请参阅 Thread.stop()
 void suspend()
          已过时。 此方法容易导致死锁。有关详细信息,请参阅 Thread.suspend()
 String toString()
          返回此线程组的字符串表示形式。
 void uncaughtException(Thread t,Throwable e) 
          当此线程组中的线程因为一个未捕获的异常而停止,并且线程没有安装特定 Thread.UncaughtExceptionHandler 时,由 Java Virtual Machine 调用此方法。

二、线程组与未处理的异常

从JDK1.5开始,Java加强了线程的异常处理,如果线程执行过程中抛出了一个未处理的异常,JVM在结束该线程之前会自动查找是否有对应的Thread.UncaughtExceptionHandler对象,如果找到该处理器对象,将会调用该对象的uncaughtException(Thread t,Throwable e)方法来处理该异常。

Thread.UncaughtExceptionHandler是Thread类的一个内部公共静态接口,该接口内只有一个方法:

void uncaughtException(Thread t,Throwable t),该方法中的t代表出现异常的线程,而e代表该线程抛出的异常。

Thread类提供了两个方法来设置异常处理器:

public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh)

线程类的所有线程实例设置默认的异常处理器

public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh)

为指定线程的实例设置异常处理器

ThreadGroup类实现了Thread.UncaughtExceptionHandler接口,所以每个线程所属的线程组将会作为默认的异常处理器。当一个线程抛出未处理的异常时,JVM会首先查找该异常对应的异常处理器(setUncaughtExceptionHandler方法设置的异常处理器),如果找到该异常处理器,将调用该异常处理器处理该异常,否则,JVM将会调用该线程所属的线程组对象的uncaughtException方法来处理该异常,线程组处理异常的流程如下:

1)、如果该线程组有父线程组,则调用父线程组的uncaughtException方法来处理该异常

2)、否则,如果该线程实例所属的线程类有默认的异常处理器(由setDefaultUncaughtExceptionHandler方法设置的异常处理器),那么就调用该异常处理器来处理该异常

3)、否则,将异常调试栈的信息打印到System.err错误输出流,并结束该线程。

看下面的例子:

  1. class MyHandler implements Thread.UncaughtExceptionHandler{
  2. @Override
  3. public void uncaughtException(Thread t, Throwable e) {
  4. System.out.println("出现了异常");
  5. e.printStackTrace();
  6. }
  7. }
  8. public class Test{
  9. public static void main(String[] args) {
  10. Thread.currentThread().setUncaughtExceptionHandler(new MyHandler());
  11. int a=1/0;
  12. }
  13. }

在主线程中设置了异常处理器,最后捕获了异常。

三、Callable和Future

参考:http://lavasoft.blog.51cto.com/62575/222082

四、volatile关键字

参考:http://lavasoft.blog.51cto.com/62575/222076

五、显示同步锁

参考:http://lavasoft.blog.51cto.com/62575/222084

上一篇:spring mvc 返回json数据的四种方式


下一篇:angular : copy vs extend