多线程系列(十七) -线程组介绍

这篇具有很好参考价值的文章主要介绍了多线程系列(十七) -线程组介绍。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、简介

在之前的多线程系列文章中,我们陆陆续续的介绍了Thread线程类相关的知识和用法,其实在Thread类上还有一层ThreadGroup类,也就是线程组。

今天我们就一起来简单的聊聊线程组相关的知识和用法。

二、什么是线程组

线程组,简单来说就是多个线程的集合,它的出现主要是为了更方便的管理线程。

从结构角度看,线程组与线程之间其实是一个父子结构,一个线程组可以拥有几个线程,同时也可以拥有几个线程组。整个组织结构像一棵树一样,每个线程一定有一个线程组,线程组可能又有一个父线程组,追溯到根节点就是一个系统线程组。

线程组与线程之间的关系,可以用如下图来描述。

多线程系列(十七) -线程组介绍

比如,我们通常创建的main方法,对应的是main线程,它所属的是main线程组,main线程组的父级是是system系统线程组。

public static void main(String[] args) {
    Thread currentThread = Thread.currentThread();
    ThreadGroup currentThreadGroup = currentThread.getThreadGroup();
    ThreadGroup systemThreadGroup = currentThreadGroup.getParent();
    System.out.println("currentThread:" + currentThread.getName());
    System.out.println("currentThreadGroup:" + currentThreadGroup.getName());
    System.out.println("systemThreadGroup:" + systemThreadGroup.getName());
}

输出结果如下:

currentThread:main
currentThreadGroup:main
systemThreadGroup:system

其中system线程组就是根节点,再上一层就没有了,如果调用会抛空指针异常。

线程组最主要的作用是:可以实现批量管理线程或者线程组,有效的对线程或者线程组对象进行检查、尝试中断等操作。

下面我们就一起来看看ThreadGroup的常用方法和使用技巧。

三、线程组用法详解

3.1、构造方法介绍

ThreadGroup提供了两个构造方法,内容如下:

方法 描述
ThreadGroup(String name) 根据线程组名称创建线程组,其父线程组为main线程组
ThreadGroup(ThreadGroup parent, String name) 根据线程组名称创建线程组,其父线程组为指定的 parent 线程组

其中支持指定父级线程组的方法,在实际的使用中比较常见。

下面,我们演示一下这两个构造函数的用法:

public static void main(String[] args) {
    ThreadGroup subThreadGroup1 = new ThreadGroup("sub1");
    ThreadGroup subThreadGroup2 = new ThreadGroup(subThreadGroup1, "sub2");
    System.out.println("sub1 parent thread group name:" + subThreadGroup1.getParent().getName());
    System.out.println("sub2 parent thread group name:" + subThreadGroup2.getParent().getName());
}

输出结果如下:

sub1 parent thread group name:main
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()方法用于返回此线程组及其子组中活动线程的数量的估计值,因为线程的数量是动态发生变化的,返回的值只是一个估计值。

我们看一个简单的例子就知道了。

public class MyThread extends Thread{

    public MyThread(ThreadGroup group, String name) {
        super(group, name);
    }

    @Override
    public void run() {
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class MyThreadMainTest {

    public static void main(String[] args) throws Exception {
        ThreadGroup tg = new ThreadGroup("group1");
        MyThread t1 = new MyThread (tg, "t1");
        MyThread t2 = new MyThread (tg, "t2");
        t1.start();
        t2.start();

        System.out.println("线程组的名称:" +  tg.getName() + ",活动的线程数:" +  tg.activeCount());
        Thread.sleep(1000);
        System.out.println("线程组的名称:" +  tg.getName() + ",活动的线程数:" +  tg.activeCount());
    }
}

输出结果如下:

线程组的名称:group1,活动的线程数:2
线程组的名称:group1,活动的线程数:0

第一次检查线程都处于运行状态,因此活动的线程数为 2;过 1 秒之后,线程运行结束,活动的线程数为 0。

3.2.2、isDaemon 方法

setDaemon()方法用于测试此线程组是否是守护线程组。

需要注意的是:后台线程组和后台线程是两个概念,后台线程组的特性是最后一个线程执行完或最后一个线程被销毁时,后台线程组自动销毁,线程组只是为了统一管理线程的一个方式,跟后台线程有区别!

例子如下:

public class MyThread extends Thread{

    public MyThread(ThreadGroup group, String name) {
        super(group, name);
    }

    @Override
    public void run() {
        System.out.println("当前线程:" + Thread.currentThread().getName() + ",是否后台线程:" +  Thread.currentThread().isDaemon());
        System.out.println("当前线程组:" + Thread.currentThread().getThreadGroup().getName() + ",是否后台线程组:" +  Thread.currentThread().getThreadGroup().isDaemon());
    }
}

public class MyThreadMainTest4 {

    public static void main(String[] args) throws Exception {
        ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
        new MyThread(mainGroup, "t1").start();

        Thread.sleep(100);

        // 设置守护线程组
        ThreadGroup tg = new ThreadGroup("group1");
        tg.setDaemon(true);
        new MyThread(tg,"t2").start();
    }
}

输出结果如下:

当前线程:t1,是否后台线程:false
当前线程组:main,是否后台线程组:false
当前线程:t2,是否后台线程:false
当前线程组:group1,是否后台线程组:true
3.2.3、interrupt 方法

interrupt()方法用于尝试中断此线程组中的所有线程。如果正在运行的线程没有进入阻塞,是无法中断的。

例子如下:

public class MyThreadA extends Thread{

    public MyThreadA(ThreadGroup group, String name) {
        super(group, name);
    }

    @Override
    public void run() {
        System.out.println("线程:" + Thread.currentThread().getName() + ",开始运行");
        String t;
        for (int i = 0; i < 1000000000; i++) {
            t = i + "";
        }
        System.out.println("线程:" + Thread.currentThread().getName() + ",停止运行");
    }
}
public class MyThreadB extends Thread{

    public MyThreadB(ThreadGroup group, String name) {
        super(group, name);
    }

    @Override
    public void run() {
        System.out.println("线程:" + Thread.currentThread().getName() + ",开始运行");
        while (!Thread.interrupted()){
        }
        System.out.println("线程:" + Thread.currentThread().getName() + ",停止运行");
    }
}
public class MyThreadC extends Thread{

    public MyThreadC(ThreadGroup group, String name) {
        super(group, name);
    }

    @Override
    public void run() {
        System.out.println("线程:" + Thread.currentThread().getName() + ",开始运行");
        try {
            Thread.sleep(1000);
        } catch (Exception e){
//            e.printStackTrace();
        }
        System.out.println("线程:" + Thread.currentThread().getName() + ",停止运行");
    }
}
public class MyThreadMainTest {

    public static void main(String[] args) throws Exception {
        ThreadGroup tg = new ThreadGroup("group1");
        new MyThreadA(tg,"t1").start();
        new MyThreadB(tg,"t2").start();
        new MyThreadC(tg,"t3").start();

        // 尝试中断线程组里面的线程
        tg.interrupt();
    }
}

输出结果如下:

线程:t1,开始运行
线程:t2,开始运行
线程:t2,停止运行
线程:t3,开始运行
线程:t3,停止运行

线程t1只有等它运行结束,通过interrupt()不能中断程序!

四、小结

本文主要围绕线程组的一些基本概念以及常用方法,并结合了一些简单示例进行介绍。

线程组的出现更多的是便于有组织的管理线程,比如 Java 的线程池就用到了线程组,更多的线程知识,我们在后续的文章中会进行介绍。

如果有描述不对的地方,欢迎网友留言指出。

五、参考

1、https://www.cnblogs.com/xrq730/p/4856072.html

2、https://cloud.tencent.com/developer/article/1633465文章来源地址https://www.toymoban.com/news/detail-838975.html

到了这里,关于多线程系列(十七) -线程组介绍的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Jmeter(二十七):BeanShell PostProcessor跨线程全局变量使用

    在性能测试中,两个相关联的接口不一定都在同一个线程组,遇见这种情况时,我们要进行跨线程组传参,此处用登录和查询配送单两个请求举例; 1、登录请求中配置json提取器,将接口返回的token保存在变量中;  2、登录请求中配置BeanShell 后置处理程序,将token保存到全局

    2024年02月11日
    浏览(30)
  • Python工具箱系列(三十七)

    二进制文件操作(上) python比较擅长与文本相关的操作。但现实世界中,对于非文本消息的处理也很普遍。例如: ◆通过有线、无线传递传感器获得的测量数据。 ◆卫星通过电磁波发送测量数据。 ◆数据中心的数万台服务器发送当前CPU的占用率信息、内存占用量等众多指标

    2024年02月11日
    浏览(29)
  • cfa一级考生复习经验分享系列(十七)

    考场经验: 1.本人在Prometric广州考试中心,提前一天在附近住下,地方比较好找,到了百汇广场北门,进去就可以看见电梯直达10楼。进去之后需要现场检查行程卡和健康码,然后会问最近你有没有发烧咳嗽等问题,然后登记你的手机号和现在居住住址。一位工作人员会给你

    2024年02月03日
    浏览(38)
  • 系列三十七、IDEA设置全局快捷键

     

    2024年01月15日
    浏览(33)
  • 数字电路硬件设计系列(十七)之上电时序控制电路

    上电时序,也叫做Power-up Sequence,是指电源时序关系。 下面 就是一系列电源的上电的先后关系: 采用不同的电容来控制上电延时时间的长短,具体的电路见下图: 这种上电时序控制的方式, 电路结构简单 ,但是 延时时间难以精确的控制 。 在FPGA的电源时序控制中,应用十

    2024年02月12日
    浏览(40)
  • 软件设计模式系列之十七——解释器模式

    解释器模式是一种行为型设计模式,它用于将一种语言或表达式解释为对象。该模式通过定义语言的文法规则,并使用解释器来解释和执行这些规则,将复杂的语言转换为对象的操作。 在软件开发中,解释器模式常用于处理类似于编程语言、查询语言、正则表达式等需要解释

    2024年02月08日
    浏览(23)
  • Oralce系列十七:Sqluldr2与Sqlldr

    Sqluldr2是灵活与强大的Oracle文本导出程序,主要参数如下: user = username/password@tnsname sql = SQL file name query = select statement field = separator string between fields record = separator string between records rows = print progress for every given rows (default, 1000000) file = output file name(default: uldrdata.txt) log = log fil

    2024年02月09日
    浏览(41)
  • Oracle系列十七:Sqluldr2与Sqlldr

    Sqluldr2是灵活与强大的Oracle文本导出程序,主要参数如下: user = username/password@tnsname sql = SQL file name query = select statement field = separator string between fields record = separator string between records rows = print progress for every given rows (default, 1000000) file = output file name(default: uldrdata.txt) log = log fil

    2024年02月13日
    浏览(28)
  • JavaScript系列从入门到精通系列第十七篇:JavaScript中的全局作用域

    文章目录 前言 1:什么叫作用域 一:全局作用域 1:全局变量的声明 2:变量声明和使用的顺序 3:方法声明和使用的顺序         可以起作用的范围         我们的作用域只有全局作用域和函数作用域。          直接编写到Script里边的代码,就是全局作用域。全局作用域

    2024年02月06日
    浏览(35)
  • 【Android从零单排系列十七】《Android视图控件——WebView》

    目录 前言 一 WebView基本介绍 二 WebView使用方法 三 WebView常见属性及方法 四 简单案例 五 总结 小伙伴们,在上文中我们介绍了Android视图组件ProgressDialog,本文我们继续盘点,介绍一下视图控件的WebView。 WebView是Android平台上的一个控件,用于在应用程序中显示Web页面 在布局文

    2024年02月11日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包