您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

什么是线程组?你学会了吗?

时间:2023-12-11 13:05:48  来源:微信公众号  作者:Java极客技术

一、简介

在之前的多线程系列文章中,我们陆陆续续的介绍了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



Tags:线程组   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
什么是线程组?你学会了吗?
一、简介在之前的多线程系列文章中,我们陆陆续续的介绍了Thread线程类相关的知识和用法,其实在Thread类上还有一层ThreadGroup类,也就是线程组。今天我们就一起来简单的聊聊线...【详细内容】
2023-12-11  Search: 线程组  点击:(155)  评论:(0)  加入收藏
Jmeter各类线程组详解
Jmeter各类线程组详解作者:牛刘源了解JMeter的朋友都知道,它不仅能做简单的接口测试、还支持性能测试,接口类型不仅支持Rest、SOAP,也可扩展WebSocket、Socket等。无论你用Jmete...【详细内容】
2020-04-02  Search: 线程组  点击:(349)  评论:(0)  加入收藏
▌简易百科推荐
即将过时的 5 种软件开发技能!
作者 | Eran Yahav编译 | 言征出品 | 51CTO技术栈(微信号:blog51cto) 时至今日,AI编码工具已经进化到足够强大了吗?这未必好回答,但从2023 年 Stack Overflow 上的调查数据来看,44%...【详细内容】
2024-04-03    51CTO  Tags:软件开发   点击:(5)  评论:(0)  加入收藏
跳转链接代码怎么写?
在网页开发中,跳转链接是一项常见的功能。然而,对于非技术人员来说,编写跳转链接代码可能会显得有些困难。不用担心!我们可以借助外链平台来简化操作,即使没有编程经验,也能轻松实...【详细内容】
2024-03-27  蓝色天纪    Tags:跳转链接   点击:(12)  评论:(0)  加入收藏
中台亡了,问题到底出在哪里?
曾几何时,中台一度被当做“变革灵药”,嫁接在“前台作战单元”和“后台资源部门”之间,实现企业各业务线的“打通”和全域业务能力集成,提高开发和服务效率。但在中台如火如荼之...【详细内容】
2024-03-27  dbaplus社群    Tags:中台   点击:(8)  评论:(0)  加入收藏
员工写了个比删库更可怕的Bug!
想必大家都听说过删库跑路吧,我之前一直把它当一个段子来看。可万万没想到,就在昨天,我们公司的某位员工,竟然写了一个比删库更可怕的 Bug!给大家分享一下(不是公开处刑),希望朋友们...【详细内容】
2024-03-26  dbaplus社群    Tags:Bug   点击:(5)  评论:(0)  加入收藏
我们一起聊聊什么是正向代理和反向代理
从字面意思上看,代理就是代替处理的意思,一个对象有能力代替另一个对象处理某一件事。代理,这个词在我们的日常生活中也不陌生,比如在购物、旅游等场景中,我们经常会委托别人代替...【详细内容】
2024-03-26  萤火架构  微信公众号  Tags:正向代理   点击:(10)  评论:(0)  加入收藏
看一遍就理解:IO模型详解
前言大家好,我是程序员田螺。今天我们一起来学习IO模型。在本文开始前呢,先问问大家几个问题哈~什么是IO呢?什么是阻塞非阻塞IO?什么是同步异步IO?什么是IO多路复用?select/epoll...【详细内容】
2024-03-26  捡田螺的小男孩  微信公众号  Tags:IO模型   点击:(8)  评论:(0)  加入收藏
为什么都说 HashMap 是线程不安全的?
做Java开发的人,应该都用过 HashMap 这种集合。今天就和大家来聊聊,为什么 HashMap 是线程不安全的。1.HashMap 数据结构简单来说,HashMap 基于哈希表实现。它使用键的哈希码来...【详细内容】
2024-03-22  Java技术指北  微信公众号  Tags:HashMap   点击:(11)  评论:(0)  加入收藏
如何从头开始编写LoRA代码,这有一份教程
选自 lightning.ai作者:Sebastian Raschka机器之心编译编辑:陈萍作者表示:在各种有效的 LLM 微调方法中,LoRA 仍然是他的首选。LoRA(Low-Rank Adaptation)作为一种用于微调 LLM(大...【详细内容】
2024-03-21  机器之心Pro    Tags:LoRA   点击:(12)  评论:(0)  加入收藏
这样搭建日志中心,传统的ELK就扔了吧!
最近客户有个新需求,就是想查看网站的访问情况。由于网站没有做google的统计和百度的统计,所以访问情况,只能通过日志查看,通过脚本的形式给客户导出也不太实际,给客户写个简单的...【详细内容】
2024-03-20  dbaplus社群    Tags:日志   点击:(4)  评论:(0)  加入收藏
Kubernetes 究竟有没有 LTS?
从一个有趣的问题引出很多人都在关注的 Kubernetes LTS 的问题。有趣的问题2019 年,一个名为 apiserver LoopbackClient Server cert expired after 1 year[1] 的 issue 中提...【详细内容】
2024-03-15  云原生散修  微信公众号  Tags:Kubernetes   点击:(5)  评论:(0)  加入收藏
站内最新
站内热门
站内头条