多线程系列(十七) -线程组先容

  金牌会员 | 2024-5-13 20:33:50 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 872|帖子 872|积分 2616

一、简介

在之前的多线程系列文章中,我们陆陆续续的先容了Thread线程类相干的知识和用法,其着实Thread类上还有一层ThreadGroup类,也就是线程组。
本日我们就一起来简单的聊聊线程组相干的知识和用法。
二、什么是线程组

线程组,简单来说就是多个线程的聚集,它的出现重要是为了更方便的管理线程。
从结构角度看,线程组与线程之间其实是一个父子结构,一个线程组可以拥有几个线程,同时也可以拥有几个线程组。整个组织结构像一棵树一样,每个线程一定有一个线程组,线程组可能又有一个父线程组,追溯到根节点就是一个体系线程组。
线程组与线程之间的关系,可以用如下图来形貌。

比如,我们通常创建的main方法,对应的是main线程,它所属的是main线程组,main线程组的父级是是system体系线程组。
  1. public static void main(String[] args) {
  2.     Thread currentThread = Thread.currentThread();
  3.     ThreadGroup currentThreadGroup = currentThread.getThreadGroup();
  4.     ThreadGroup systemThreadGroup = currentThreadGroup.getParent();
  5.     System.out.println("currentThread:" + currentThread.getName());
  6.     System.out.println("currentThreadGroup:" + currentThreadGroup.getName());
  7.     System.out.println("systemThreadGroup:" + systemThreadGroup.getName());
  8. }
复制代码
输出结果如下:
  1. currentThread:main
  2. currentThreadGroup:main
  3. systemThreadGroup:system
复制代码
此中system线程组就是根节点,再上一层就没有了,如果调用会抛空指针异常。
线程组最重要的作用是:可以实现批量管理线程或者线程组,有效的对线程或者线程组对象举行检查、尝试中断等操作。
下面我们就一起来看看ThreadGroup的常用方法和使用技巧。
三、线程组用法详解

3.1、构造方法先容

ThreadGroup提供了两个构造方法,内容如下:
方法形貌ThreadGroup(String name)根据线程组名称创建线程组,其父线程组为main线程组ThreadGroup(ThreadGroup parent, String name)根据线程组名称创建线程组,其父线程组为指定的 parent 线程组此中支持指定父级线程组的方法,在现实的使用中比较常见。
下面,我们演示一下这两个构造函数的用法:
  1. public static void main(String[] args) {
  2.     ThreadGroup subThreadGroup1 = new ThreadGroup("sub1");
  3.     ThreadGroup subThreadGroup2 = new ThreadGroup(subThreadGroup1, "sub2");
  4.     System.out.println("sub1 parent thread group name:" + subThreadGroup1.getParent().getName());
  5.     System.out.println("sub2 parent thread group name:" + subThreadGroup2.getParent().getName());
  6. }
复制代码
输出结果如下:
  1. sub1 parent thread group name:main
  2. sub2 parent thread group name:sub1
复制代码
3.2、焦点方法先容

ThreadGroup提供了许多有效的方法,下面整理了一些方法的扼要先容,内容如下:
方法形貌public final String getName()返回此线程组的名称public final ThreadGroup getParent()返回此线程组的父级public final boolean parentOf(ThreadGroup g)测试此线程组是线程组参数还是其父级线程组之一public int activeCount()返回此线程组及其子组中运动线程的数量的估计值,递归遍历该线程组中所有的子组,此方法重要用于调试和监视目的public int activeGroupCount ()返回此线程组及其子组中运动组的数量的估计值。递归遍历该线程组中的所有子群,此方法重要用于调试和监视目的public final void checkAccess()确定当前运行的线程是否具有修改此线程组的权限public int enumerate(Thread[] list)将这个线程组复制到它所在的组及其子组中public final void destroy()烧毁此线程组及其所有子组,当线程组还要子线程或者子线程组,会抛异常public boolean isDestroyed()测试此线程组是否已被烧毁public final int getMaxPriority()返回此线程组的最大优先级public final void setMaxPriority(int pri)设置组的最大优先级。线程组中具有较高优先级的线程不会受到影响public final boolean isDaemon()测试此线程组是否是保卫线程组public final void setDaemon(boolean daemon)修改此线程组的保卫进程状态public final void interrupt()尝试中断此线程组中的所有线程public void list()将此线程组的信息打印到标准输出。此方法仅用于调试下面我们抽取几个比较常见的方法,举行演示先容。
3.2.1、activeCount 方法

activeCount()方法用于返回此线程组及其子组中运动线程的数量的估计值,因为线程的数量是动态发生变革的,返回的值只是一个估计值。
我们看一个简单的例子就知道了。
  1. public class MyThread extends Thread{
  2.     public MyThread(ThreadGroup group, String name) {
  3.         super(group, name);
  4.     }
  5.     @Override
  6.     public void run() {
  7.         try {
  8.             Thread.sleep(500);
  9.         } catch (InterruptedException e) {
  10.             e.printStackTrace();
  11.         }
  12.     }
  13. }
复制代码
  1. public class MyThreadMainTest {
  2.     public static void main(String[] args) throws Exception {
  3.         ThreadGroup tg = new ThreadGroup("group1");
  4.         MyThread t1 = new MyThread (tg, "t1");
  5.         MyThread t2 = new MyThread (tg, "t2");
  6.         t1.start();
  7.         t2.start();
  8.         System.out.println("线程组的名称:" +  tg.getName() + ",活动的线程数:" +  tg.activeCount());
  9.         Thread.sleep(1000);
  10.         System.out.println("线程组的名称:" +  tg.getName() + ",活动的线程数:" +  tg.activeCount());
  11.     }
  12. }
复制代码
输出结果如下:
  1. 线程组的名称:group1,活动的线程数:2
  2. 线程组的名称:group1,活动的线程数:0
复制代码
第一次检查线程都处于运行状态,因此运动的线程数为 2;过 1 秒之后,线程运行结束,运动的线程数为 0。
3.2.2、isDaemon 方法

setDaemon()方法用于测试此线程组是否是保卫线程组。
需要注意的是:后台线程组和后台线程是两个概念,后台线程组的特性是末了一个线程实行完或末了一个线程被烧毁时,后台线程组主动烧毁,线程组只是为了同一管理线程的一个方式,跟后台线程有区别!
例子如下:
  1. public class MyThread extends Thread{
  2.     public MyThread(ThreadGroup group, String name) {
  3.         super(group, name);
  4.     }
  5.     @Override
  6.     public void run() {
  7.         System.out.println("当前线程:" + Thread.currentThread().getName() + ",是否后台线程:" +  Thread.currentThread().isDaemon());
  8.         System.out.println("当前线程组:" + Thread.currentThread().getThreadGroup().getName() + ",是否后台线程组:" +  Thread.currentThread().getThreadGroup().isDaemon());
  9.     }
  10. }
复制代码
  1. public class MyThreadMainTest4 {
  2.     public static void main(String[] args) throws Exception {
  3.         ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
  4.         new MyThread(mainGroup, "t1").start();
  5.         Thread.sleep(100);
  6.         // 设置守护线程组
  7.         ThreadGroup tg = new ThreadGroup("group1");
  8.         tg.setDaemon(true);
  9.         new MyThread(tg,"t2").start();
  10.     }
  11. }
复制代码
输出结果如下:
  1. 当前线程:t1,是否后台线程:false
  2. 当前线程组:main,是否后台线程组:false
  3. 当前线程:t2,是否后台线程:false
  4. 当前线程组:group1,是否后台线程组:true
复制代码
3.2.3、interrupt 方法

interrupt()方法用于尝试中断此线程组中的所有线程。如果正在运行的线程没有进入壅闭,是无法中断的。
例子如下:
  1. public class MyThreadA extends Thread{
  2.     public MyThreadA(ThreadGroup group, String name) {
  3.         super(group, name);
  4.     }
  5.     @Override
  6.     public void run() {
  7.         System.out.println("线程:" + Thread.currentThread().getName() + ",开始运行");
  8.         String t;
  9.         for (int i = 0; i < 1000000000; i++) {
  10.             t = i + "";
  11.         }
  12.         System.out.println("线程:" + Thread.currentThread().getName() + ",停止运行");
  13.     }
  14. }
复制代码
  1. public class MyThreadB extends Thread{
  2.     public MyThreadB(ThreadGroup group, String name) {
  3.         super(group, name);
  4.     }
  5.     @Override
  6.     public void run() {
  7.         System.out.println("线程:" + Thread.currentThread().getName() + ",开始运行");
  8.         while (!Thread.interrupted()){
  9.         }
  10.         System.out.println("线程:" + Thread.currentThread().getName() + ",停止运行");
  11.     }
  12. }
复制代码
  1. public class MyThreadC extends Thread{
  2.     public MyThreadC(ThreadGroup group, String name) {
  3.         super(group, name);
  4.     }
  5.     @Override
  6.     public void run() {
  7.         System.out.println("线程:" + Thread.currentThread().getName() + ",开始运行");
  8.         try {
  9.             Thread.sleep(1000);
  10.         } catch (Exception e){
  11. //            e.printStackTrace();
  12.         }
  13.         System.out.println("线程:" + Thread.currentThread().getName() + ",停止运行");
  14.     }
  15. }
复制代码
  1. public class MyThreadMainTest {
  2.     public static void main(String[] args) throws Exception {
  3.         ThreadGroup tg = new ThreadGroup("group1");
  4.         new MyThreadA(tg,"t1").start();
  5.         new MyThreadB(tg,"t2").start();
  6.         new MyThreadC(tg,"t3").start();
  7.         // 尝试中断线程组里面的线程
  8.         tg.interrupt();
  9.     }
  10. }
复制代码
输出结果如下:
  1. 线程:t1,开始运行
  2. 线程:t2,开始运行
  3. 线程:t2,停止运行
  4. 线程:t3,开始运行
  5. 线程:t3,停止运行
复制代码
线程t1只有等它运行结束,通过interrupt()不能中断步伐!
四、小结

本文重要围绕线程组的一些根本概念以及常用方法,并联合了一些简单示例举行先容。
线程组的出现更多的是便于有组织的管理线程,比如 Java 的线程池就用到了线程组,更多的线程知识,我们在后续的文章中会举行先容。
如果有形貌不对的地方,欢迎网友留言指出。
五、参考

1、https://www.cnblogs.com/xrq730/p/4856072.html
2、https://cloud.tencent.com/developer/article/1633465

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表