ThreadGroup线程组应用
一、基本方法
1、获取当前线程组名
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
Thread.currentThread().getThreadGroup().getName()
在main方法是调用输出是:main
2、将线程放入到一个线程组中去
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
ThreadGroupthreadGroup1=newThreadGroup("group1");
ThreadGroupthreadGroup2=newThreadGroup("group2");
Threadthread1=newThread(threadGroup1,"group1''smember");
Threadthread2=newThread(threadGroup2,"group2''smember");
其中Thread中和ThreadGroup相关的构造函数:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
publicThread(ThreadGroupgroup,Runnabletarget){
init(group,target,"Thread-"+nextThreadNum(),0);
}
publicThread(ThreadGroupgroup,Stringname){
init(group,null,name,0);
}
publicThread(ThreadGroupgroup,Runnabletarget,Stringname){
init(group,target,name,0);
}
publicThread(ThreadGroupgroup,Runnabletarget,Stringname,
longstackSize){
init(group,target,name,stackSize);
}
它们最终都是调用同一个函数:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
privatevoidinit(ThreadGroupg,Runnabletarget,Stringname,
longstackSize){
Threadparent=currentThread();
SecurityManagersecurity=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、复制线程组:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
//这样可以复制group里面的thread信息
Thread[]threads=newThread[threadGroup.activeCount()];
threadGroup.enumerate(threads);
这里的activeCount很明显就是取得活动的线程,注意。默认情况下,连同其子线程组也会进行复制。
4、未捕获异常处理
ThreadGroup中有一个uncaughtException()方法。当线程组中某个线程发生Uncheckedexception异常时,由执行环境调用此方法进行相关处理,如果有必要,可以重新定义此方法
二、应用实例
1、实例应用
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
packagecom.func.axc.threadgroup;
importjava.util.Date;
importjava.util.Random;
importjava.util.concurrent.TimeUnit;
classResult{
privateStringname;
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
this.name=name;
}
}
publicclassSearchTaskimplementsRunnable{
publicSearchTask(Resultresult){
this.result=result;
}
privateResultresult;
@Override
publicvoidrun(){
Stringname=Thread.currentThread().getName();
System.out.println("ThreadStart"+name);
try{
doTask();
result.setName(name);
}catch(InterruptedExceptione){
System.out.printf("Thread%s:Interrupted\n",name);
return;
}
System.out.println("Threadend"+name);
}
privatevoiddoTask()throwsInterruptedException{
Randomrandom=newRandom((newDate()).getTime());
intvalue=(int)(random.nextDouble()100);
System.out.printf("Thread%s:%d\n",Thread.currentThread().getName(),
value);
TimeUnit.SECONDS.sleep(value);
}
publicstaticvoidmain(String[]args){
System.out.println("mainthreadstart:");
//创建5个线程,并入group里面进行管理
ThreadGroupthreadGroup=newThreadGroup("Searcher");
Resultresult=newResult();
SearchTasksearchTask=newSearchTask(result);
for(inti=0;i<5;i++){
Threadthred=newThread(threadGroup,searchTask);
thred.start();
try{
TimeUnit.SECONDS.sleep(1);
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
//通过这种方法可以看group里面的所有信息
System.out.printf("NumberofThreads:%d\n",threadGroup.activeCount());
System.out.printf("InformationabouttheThreadGroup\n");
threadGroup.list();
//这样可以复制group里面的thread信息
Thread[]threads=newThread[threadGroup.activeCount()];
threadGroup.enumeratewww.baiyuewang.net(threads);
for(inti=0;i System.out.printf("Thread%s:%s\n",threads[i].getName(),
threads[i].getState());
}
waitFinish(threadGroup);
//将group里面的所有线程都给interpet
threadGroup.interrupt();
System.out.println("mainthreadend:");
}
privatestaticvoidwaitFinish(ThreadGroupthreadGroup){
while(threadGroup.activeCount()>0){
try{
TimeUnit.SECONDS.sleep(1);
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
}
输出结果:
2、统一异常处理实例
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
packagecom.func.axc.threadgroup;
/
功能概要:
@authorlinbingwen
@since2016年6月11日
/
publicclassThreadGroupDemo{
publicstaticvoidmain(String[]args){
ThreadGroupthreadGroup1=
//这是匿名类写法
newThreadGroup("group1"){
//继承ThreadGroup并重新定义以下方法
//在线程成员抛出uncheckedexception
//会执行此方法
publicvoiduncaughtException(Threadt,Throwablee){
System.out.println(t.getName()+":"+e.getMessage());
}
};
//这是匿名类写法
Threadthread1=
//这个线程是threadGroup1的一员
newThread(threadGroup1,newRunnable(){
publicvoidrun(){
//抛出unchecked异常
thrownewRuntimeException("测试异常");
}
});
thread1.start();
}
}
三、源码解读
首先看其包含的变量
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
publicclassThreadGroupimplementsThread.UncaughtExceptionHandler{
privatefinalThreadGroupparent;//父亲ThreadGroup
Stringname;//ThreadGroupr的名称
intmaxPriority;//线程最大优先级
booleandestroyed;//是否被销毁
booleandaemon;//是否守护线程
booleanvmAllowSuspension;//是否可以中断
intnUnstartedThreads=0;//还未启动的线程
intnthreads;//ThreadGroup中线程数目
Threadthreads[];//ThreadGroup中的线程
intngroups;//线程组数目
ThreadGroupgroups[];//线程组数组
从源码中可以看出,其包含的变量并不是很多。这里需要注意
(1)线程组也可以包含其他线程组。如上面的groups[].
(2)线程组构成一棵树,在树中,除了初始线程组外,每个线程组都有一个父线程组
构造函数:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
//私有构造函数
privateThreadGroup(){
this.name="system";
this.maxPriority=Thread.MAX_PRIORITY;
this.parent=null;
}
//默认是以当前ThreadGroup传入作为parentThreadGroup,新线程组的父线程组是目前正在运行线程的线程组。
publicThreadGroup(Stringname){
this(Thread.currentThread().getThreadGroup(),name);
}
//构造函数
publicThreadGroup(ThreadGroupparent,Stringname){
this(checkParentAccess(parent),parent,name);
}
//私有构造函数
privateThreadGroup(Voidunused,ThreadGroupparent,Stringname){
this.name=name;
this.maxPriority=parent.maxPriority;
this.daemon=parent.daemon;
this.vmAllowSuspension=parent.vmAllowSuspension;
this.parent=parent;
parent.add(this);
}
其终的调用构造函数只有一个,父线程组的checkAccess方法在checkParentAccess中会调用:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
//检查parentThreadGroup
privatestaticVoidcheckParentAccess(ThreadGroupparent){
parent.checkAccess();
returnnull;
}
未捕获异常设置:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
publicvoiduncaughtException(Threadt,Throwablee){
if(parent!=null){
parent.uncaughtException(t,e);//父线程组不为空,设置到父线程组
}else{
Thread.UncaughtExceptionHandlerueh=
Thread.getDefaultUncaughtExceptionHandler();
if(ueh!=null){
ueh.uncaughtException(t,e);
}elseif(!(einstanceofThreadDeath)){
System.err.print("Exceptioninthread\""
+t.getName()+"\"");
e.printStackTrace(System.err);
}
}
}
如果父线程组存在,则调用它的uncaughtException方法.
如果父线程组不存在,但指定了默认处理器(下节中的Asthedefaulthandlerfortheapplication),则调用默认的处理器
如果默认处理器没有设置,则写错误日志.但如果exception是ThreadDeath实例的话,忽略
线程组复制:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
//此线程组及其子组中的所有活动线程复制到指定数组中。
publicintenumerate(ThreadGrouplist[]){
checkAccess();
returnenumerate(list,0,true);
}
//此线程组及其子组中的所有活动线程复制到指定数组中。
publicintenumerate(ThreadGrouplist[],booleanrecurse){
checkAccess();
returnenumerate(list,0,recurse);
}
//此线程组中的所有活动线程复制到指定数组中。如果recurse标志为true,则还包括对此线程的子组中的所有活动线程的引用。如果数组太小而无法保持所有线程,则//忽略额外的线程。
privateintenumerate(ThreadGrouplist[],intn,booleanrecurse){
intngroupsSnapshot=0;
ThreadGroup[]groupsSnapshot=null;
synchronized(this){
if(destroyed){
return0;
}
intng=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(inti=0;i n=groupsSnapshot[i].enumerate(list,n,true);
}
}
returnn;
}
|
|