• 极客专栏正式上线!欢迎访问 https://www.jikewenku.com/topic.html
  • 极客专栏正式上线!欢迎访问 https://www.jikewenku.com/topic.html

Java并发编程与技术内幕:ThreadGroup线程组应用

技术杂谈 勤劳的小蚂蚁 3个月前 (01-20) 75次浏览 已收录 0个评论 扫描二维码

 摘要:线程组ThreadGroup表示一组线程的集合,一旦一个线程归属到一个线程组之中后,就不能再更换其所在的线程组。那么为什么要使用线程组呢?个人认为有以下的好处:方便统一管理,线程组可以进行复制,快速定位到一个线程,统一进行异常设置等。ThreadGroup它其实并不属于Java并发包中的内容,它是java.lang中的内容。但是掌握对其的于理解,在实际应用中有很大的帮助。
1、获取当前线程组名
Thread.currentThread().getThreadGroup().getName()
在main方法是调用输出是:main
2、将线程放入到一个线程组中去
ThreadGroup threadGroup1 = new ThreadGroup(“group1”);
ThreadGroup threadGroup2 = new ThreadGroup(“group2”);
Thread thread1 =new Thread(threadGroup1, “group1’s member”);
Thread thread2 =new Thread(threadGroup2, “group2’s member”);
其中Thread中和ThreadGroup相关的构造函数:
publicThread(ThreadGroup group, Runnable target) {
 init(group, target, “Thread-“ + nextThreadNum(), 0);
   }


   publicThread(ThreadGroup group, String name) {
 init(group, null, name, 0);
   }


   publicThread(ThreadGroup group, Runnable target, String name) {
 init(group, target, name, 0);
   }

   publicThread(ThreadGroup group, Runnable target, String name,
                 long stackSize) {
 init(group, target, name, stackSize);
   }
它们最终都是调用同一个函数:
privatevoidinit(ThreadGroup g, Runnable target, String name,
                     long stackSize) {
 Thread parent = currentThread();
 SecurityManager security = System.getSecurityManager();
 if (g == null) {
        //安全检查
     if (security != null) {
   g = security.getThreadGroup();
     }

       //设置线程组
     if (g == null) {
   g = parent.getThreadGroup();
     }
 }

   //检查可达性
 g.checkAccess();

    //是否有权限访问
 if (security != null) {
     if (isCCLOverridden(getClass())) {
         security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
     }
 }

    //往线程组添加线程但未启动
    g.addUnstarted();

 this.group = g;
 this.daemon = parent.isDaemon();//是否守护线程
 this.priority = parent.getPriority();//优先级
 this.name = name.toCharArray();
 if (security == null || isCCLOverridden(parent.getClass()))
     this.contextClassLoader = parent.getContextClassLoader();
 else
     this.contextClassLoader = parent.contextClassLoader;
 this.inheritedAccessControlContext = AccessController.getContext();
 this.target = target;
 setPriority(priority);
       if (parent.inheritableThreadLocals != null)
     this.inheritableThreadLocals =
   ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
       this.stackSize = stackSize;
       tid = nextThreadID();
       this.me = this;

   }

3、复制线程组:
//这样可以复制group里面的thread信息
   Thread[] threads = new Thread[threadGroup.activeCount()];
   threadGroup.enumerate(threads);
这里的activeCount很明显就是取得活动的线程,注意。默认情况 下,连同其子线程组也会进行复制。
4、未捕获异常处理
ThreadGroup中有一个uncaughtException()方法。当线程组中某个线程发生Unchecked exception异常时,由执行环境调用此方法进行相关处理,如果有必要,可以重新定义此方法
1、实例应用
package com.func.axc.threadgroup;


import java.util.Date;
import java.util.Random;
import java.util.concurrent.TimeUnit;

classResult {
 
 private String name;

 public String getName() {
   return name;
 }

 publicvoidsetName(String name) {
   this.name = name;
 }
 
}

publicclassSearchTaskimplementsRunnable {

 publicSearchTask(Result result) {
   this.result = result;
 }

 private Result result;

 @Override
 publicvoidrun() {
   String name = Thread.currentThread().getName();
   System.out.println(“Thread Start “ + name);
   try {
     doTask();
     result.setName(name);
   } catch (InterruptedException e) {
     System.out.printf(“Thread %s: Interruptedn”, name);
     return;
   }
   System.out.println(“Thread end “ + name);
 }

 privatevoiddoTask() throws InterruptedException {
   Random random = new Random((new Date()).getTime());
   intvalue = (int) (random.nextDouble() * 100);
   System.out.printf(“Thread %s: %dn”, Thread.currentThread().getName(),
       value);
   TimeUnit.SECONDS.sleep(value);
 }

 publicstaticvoidmain(String[] args) {
   System.out.println(“main thread start:”);
   
   //创建5个线程,并入group里面进行管理
   ThreadGroup threadGroup = new ThreadGroup(“Searcher”);
   Result result = new Result();
   SearchTask searchTask = new SearchTask(result);
   for (int i = 0; i < 5; i++) {
     Thread thred = new Thread(threadGroup, searchTask);
     thred.start();
     try {
       TimeUnit.SECONDS.sleep(1);
     } catch (InterruptedException e) {
       e.printStackTrace();
     }
   }
   //通过这种方法可以看group里面的所有信息
   System.out.printf(“Number of Threads: %dn”, threadGroup.activeCount());
   System.out.printf(“Information about the Thread Groupn”);
   threadGroup.list();

   //这样可以复制group里面的thread信息
   Thread[] threads = new Thread[threadGroup.activeCount()];
   threadGroup.enumerate(threads);
   for (int i = 0; i < threadGroup.activeCount(); i++) {
     System.out.printf(“Thread %s: %sn”, threads[i].getName(),
         threads[i].getState());
   }
   
   waitFinish(threadGroup);
   //将group里面的所有线程都给interpet
   threadGroup.interrupt();
   
   System.out.println(“main thread end:”);
 }

 privatestaticvoidwaitFinish(ThreadGroup threadGroup) {
   while (threadGroup.activeCount() > 0) {
     try {
       TimeUnit.SECONDS.sleep(1);
     } catch (InterruptedException e) {
       e.printStackTrace();
     }
   }
 }

}
输出结果:
2、统一异常处理实例 
package com.func.axc.threadgroup;

/**
* 功能概要:
*
* @author linbingwen
* @since 2016年6月11日
*/
publicclassThreadGroupDemo{

 publicstaticvoidmain(String[] args){
   ThreadGroup threadGroup1 =
   // 这是匿名类写法
   new ThreadGroup(“group1”) {
     // 继承ThreadGroup并重新定义以下方法
     // 在线程成员抛出unchecked exception
     // 会执行此方法
     publicvoiduncaughtException(Thread t, Throwable e){
       System.out.println(t.getName() + “: “ + e.getMessage());
     }
   };
   // 这是匿名类写法
   Thread thread1 =
   // 这个线程是threadGroup1的一员
   new Thread(threadGroup1, new Runnable() {
     publicvoidrun(){
       // 抛出unchecked异常
       thrownew RuntimeException(“测试异常”);
     }
   });

   thread1.start();
 }

}

首先看其包含的变量
publicclassThreadGroupimplementsThread.UncaughtExceptionHandler{
   privatefinal ThreadGroup parent;//父亲ThreadGroup
   String name;//ThreadGroupr 的名称
   int maxPriority;//线程最大优先级
   boolean destroyed;//是否被销毁
   boolean daemon;//是否守护线程
   boolean vmAllowSuspension;//是否可以中断

   int nUnstartedThreads = 0;//还未启动的线程
   int nthreads;//ThreadGroup中线程数目
   Thread threads[];//ThreadGroup中的线程

   int ngroups;//线程组数目
   ThreadGroup groups[];//线程组数组
从源码中可以看出,其包含的变量并不是很多。这里需要注意
(1)线程组也可以包含其他线程组。如上面的groups[].
(2)线程组构成一棵树,在树中,除了初始线程组外,每个线程组都有一个父线程组
构造函数:
//私有构造函数
   privateThreadGroup() {
   this.name = “system”;
   this.maxPriority = Thread.MAX_PRIORITY;
       this.parent = null;
   }

   //默认是以当前ThreadGroup传入作为parent  ThreadGroup,新线程组的父线程组是目前正在运行线程的线程组。
   publicThreadGroup(String name) {
   this(Thread.currentThread().getThreadGroup(), name);
   }

   //构造函数
   publicThreadGroup(ThreadGroup parent, String name) {
       this(checkParentAccess(parent), parent, name);
   }

   //私有构造函数
   privateThreadGroup(Void unused, ThreadGroup parent, String name) {
   this.name = name;
   this.maxPriority = parent.maxPriority;
   this.daemon = parent.daemon;
   this.vmAllowSuspension = parent.vmAllowSuspension;
   this.parent = parent;
   parent.add(this);

   }

其终的调用构造函数只有一个,父线程组的 checkAccess 方法在checkParentAccess中会调用:
//检查parent ThreadGroup
   privatestatic Void checkParentAccess(ThreadGroup parent) {
       parent.checkAccess();
       returnnull;
   }
未捕获异常设置:
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);
           } elseif (!(e instanceof ThreadDeath)) {
       System.err.print(“Exception in thread “”
                + t.getName() + “” “);
               e.printStackTrace(System.err);
           }
       }

   }

如果父线程组存在, 则调用它的uncaughtException方法.如果父线程组不存在, 但指定了默认处理器 (下节中的As the default handler for the application), 则调用默认的处理器如果默认处理器没有设置, 则写错误日志.但如果 exception是ThreadDeath实例的话, 忽略
线程组复制:
//此线程组及其子组中的所有活动线程复制到指定数组中。
   publicintenumerate(ThreadGroup list[]){
       checkAccess();
   return enumerate(list, 0, true);
   }
    //此线程组及其子组中的所有活动线程复制到指定数组中。
   publicintenumerate(ThreadGroup list[], boolean recurse){
       checkAccess();
   return enumerate(list, 0, recurse);
   }
   //此线程组中的所有活动线程复制到指定数组中。如果 recurse 标志为 true,则还包括对此线程的子组中的所有活动线程的引用。如果数组太小而无法保持所有线程,则    //忽略额外的线程。
   privateintenumerate(ThreadGroup list[], int n, boolean recurse){
   int ngroupsSnapshot = 0;
   ThreadGroup[] groupsSnapshot = null;
   synchronized (this) {
       if (destroyed) {
       return0;
       }
       int ng = ngroups;
       if (ng > list.length – n) {//防止list放不下线程数目
       ng = list.length – n;
       }
       if (ng > 0) {
       System.arraycopy(groups, 0, list, n, ng);//复制线程组
       n += ng;
       }
       if (recurse) { //取得其子组
       ngroupsSnapshot = ngroups;
       if (groups != null) {
                   groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
       } else {
           groupsSnapshot = null;
       }
       }
   }
   if (recurse) {//复制子组
       for (int i = 0 ; i < ngroupsSnapshot ; i++) {
       n = groupsSnapshot[i].enumerate(list, n, true);
       }
   }
   return n;
   }
上面就是一些主要的方法,其它的就不再细讲了。
参考文章:

丨极客文库, 版权所有丨如未注明 , 均为原创丨
本网站采用知识共享署名-非商业性使用-相同方式共享 3.0 中国大陆许可协议进行授权
转载请注明原文链接:Java并发编程与技术内幕:ThreadGroup线程组应用
喜欢 (0)
[247507792@qq.com]
分享 (0)
勤劳的小蚂蚁
关于作者:
温馨提示:本文来源于网络,转载文章皆标明了出处,如果您发现侵权文章,请及时向站长反馈删除。

您必须 登录 才能发表评论!

  • 精品技术教程
  • 编程资源分享
  • 问答交流社区
  • 极客文库知识库

客服QQ


QQ:2248886839


工作时间:09:00-23:00