默认情况下, 新的线程都会被加入到main线程所在的group中, main线程的group名字同线程名。 如同线程存在父子关系一样,ThreadGroup同样也存在父子关系。
创建ThreadGroup
- public ThreadGroup(String name)
- public ThreadGroup(ThreadGroup parent, String nmae)
public class ThreadGroupCreator {
public static void main(String[] args) {
// 获取当前线程的ThreadGroup
ThreadGroup currentGroup = Thread.currentThread().getThreadGroup();
// 定义一个新的group
ThreadGroup group1 = new ThreadGroup("Group1");
// 输出为true
System.out.println(group1 == currentGroup);
// 定义group2, 指定group1为其父group
ThreadGroup group2 = new ThreadGroup(group1,"group2");
// 输出为true
System.out.println(group2.getParent() == group1);
}
}
复制Thread数组
ThreadGroup中的两个方法
- public int enumerate(Thread[] list)
- public int enumerate(Thread[] list, boolean recurse)
上面两个方法,会将ThreadGroup中的active线程全部复制到Thread数组中,其中recurse参数如果为true,则该方法会将所以子group中的active线程都递归到Thread数组中。enumerate(Thread[] list)实际上等价于enumerate(Thread[] list, true)。
public class ThreadGroupEnumerateThreads {
public static void main(String[] args) throws InterruptedException {
// 创建一个ThreadGroup
ThreadGroup myGroup = new ThreadGroup("MyGroup");
// 创建线程传入threadGroup
Thread thread = new Thread(myGroup, () -> {
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "MyThread");
thread.start();
TimeUnit.MILLISECONDS.sleep(2);
ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
Thread[] list = new Thread[mainGroup.activeCount()];
int recurseSize = mainGroup.enumerate(list);
System.out.println(recurseSize);
recurseSize = mainGroup.enumerate(list, false);
System.out.println(recurseSize);
}
}
上面代码运行之后,最后一个输出会比第一个小1, 那是因为代码中将递归recurse设置为了false, MyGroup中的线程将不会包含在内。
复制ThreadGroup数组
ThreadGroup中的两个方法
- public int enumerate(ThreadGroup[] list)
- public int enumerate(ThreadGroup [] list, boolean recurse)
public class ThreadGroupEnumerateThreadGroups {
public static void main(String[] args) throws InterruptedException {
ThreadGroup myGroup1 = new ThreadGroup("MyGroup1");
ThreadGroup myGroup2 = new ThreadGroup(myGroup1,"mygroup2");
TimeUnit.MILLISECONDS.sleep(2);
ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
ThreadGroup[] list = new ThreadGroup[mainGroup.activeGroupCount()];
int recurseSize = mainGroup.enumerate(list);
System.out.println(recurseSize);
recurseSize = mainGroup.enumerate(list, false);
System.out.println(recurseSize);
}
}
myGroup1的匀group为mainGroup, 而myGroup2的父group为myGroup1, 因此上述的代码运行之后,递归复制的结果为2, 不递归的情况下为1 。
ThreadGroup操作
- activeCount() 获取group中活跃的线程
- activeGroupCount() 获取group中活跃的子group
- getMaxPriority() 获取group的优先级
- getName 获取group的名字
- getParent() 获取group的父group
- list() 该方法没有返回值, 执行该方法会将group中所有活跃的线程信息打印到控制台
- parentOf(ThreadGroup g) 判断当前group是不是给定group的父group
- setMaxPriority(int pri) 设置group的最大优先级, 最大优先级不能超过父group的最大优先级, 执行该方法不仅会改变当前group的最大优先级, 还会改变所有子group的最大优先级。
public class ThreadGroupBasic {
public static void main(String[] args) throws InterruptedException {
ThreadGroup group = new ThreadGroup("group1");
Thread thread = new Thread(group, ()-> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.setDaemon(true);
thread.start();
TimeUnit.MILLISECONDS.sleep(1);
ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
System.out.println("activeCount=" + mainGroup.activeCount());
System.out.println("activeGroupCount="+ mainGroup.activeGroupCount());
System.out.println("getMaxPriority=" + mainGroup.getMaxPriority());
System.out.println("getName=" + mainGroup.getName());
System.out.println("getParent=" + mainGroup.getParent());
mainGroup.list();
System.out.println("---------------");
System.out.println("partOf=" + mainGroup.parentOf(group));
System.out.println("parentOf=" + mainGroup.parentOf(mainGroup));
}
}
如果把一个高优先级的线程,加入一个线程组以后, 再改变组的优先级小于线程的优先级,会怎样?
import java.util.concurrent.TimeUnit;
public class ThreadGroupPriority {
public static void main(String[] args) {
ThreadGroup group = new ThreadGroup("group1");
Thread thread = new Thread(group, ()->{
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "thread");
thread.setDaemon(true);
thread.start();
System.out.println("group.getMaxPriority()" + group.getMaxPriority());
System.out.println("thread.getPriority()" + thread.getPriority());
// 改变group的最大值
group.setMaxPriority(3);
System.out.println("group.getMaxPriority()" + group.getMaxPriority());
System.out.println("thread.getPriority()" + thread.getPriority());
}
}
打印
group.getMaxPriority()10
thread.getPriority()5
group.getMaxPriority()3
thread.getPriority()5
Process finished with exit code 0
改低组的最大优先组后, 已加入的线程的优先级不变, 后面加入的线程不会大于组的优先级
ThreadGroup的interrupt
interrupt一个group会导致该group中所有active线程都被interrupt, 也就是说该group中每一个线程的interrupt标识都被设置了。
import java.util.concurrent.TimeUnit;
public class ThreadGroupInterrupt {
public static void main(String[] args) throws InterruptedException {
ThreadGroup group = new ThreadGroup("TestGroup");
new Thread(group, ()-> {
while (true) {
try {
TimeUnit.MILLISECONDS.sleep(2);
} catch (InterruptedException e) {
break;
}
}
System.out.println("t1 will exit");
}, "t1").start();
new Thread(group, () -> {
while (true) {
try {
TimeUnit.MILLISECONDS.sleep(1);
} catch (InterruptedException e) {
break;
}
}
System.out.println("t2 will exit");
}, "t2").start();
TimeUnit.MILLISECONDS.sleep(2);
group.interrupt();
}
}
打印
t2 will exit
t1 will exit
ThreadGroup的destroy
destroy用于销毁ThreadGroup, 该方法只是针对一个没有任何active线程的group进行一次destroy标记, 调用该方法的直接结果是在父group中将自已移除。
public class ThreadGroupDestroy {
public static void main(String[] args) {
ThreadGroup group = new ThreadGroup("TestGroup");
ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
System.out.println("group.isDestroyed="+ group.isDestroyed());
mainGroup.list();
group.destroy();
System.out.println("group.isDestroyed="+ group.isDestroyed());
mainGroup.list();
}
}
打印
group.isDestroyed=false
java.lang.ThreadGroup[name=main,maxpri=10]
Thread[main,5,main]
Thread[Monitor Ctrl-Break,5,main]
java.lang.ThreadGroup[name=TestGroup,maxpri=10]
group.isDestroyed=true
java.lang.ThreadGroup[name=main,maxpri=10]
Thread[main,5,main]
Thread[Monitor Ctrl-Break,5,main]
守护ThreadGroup
线程可以设置为守护线程, ThreadGroup也可以设为守护ThreadGroup, 但是若将一个ThreadGroup设置为daemon, 也并不会影响线程的daemon属性, 如果一个ThreadGroup的daemon被设置为true, 那么在group中没有任何active线程的时候该group将自动destroy
import java.util.concurrent.TimeUnit;
public class ThreadGroupDaemon {
public static void main(String[] args) throws InterruptedException {
ThreadGroup group1 = new ThreadGroup("Group1");
new Thread(group1, () -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "group1-thread").start();
ThreadGroup group2 = new ThreadGroup("Group2");
new Thread(group2, () -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "group2-thread2").start();
group2.setDaemon(true);
TimeUnit.SECONDS.sleep(3);
System.out.println(group1.isDestroyed());
System.out.println(group2.isDestroyed());
}
}
打印
false
true