Java多线程:线程组

线程组

可以把线程归属到某一个线程组中,线程组中可以有线程对象,也可以有线程组,组中还可以有线程,这样的组织结构有点类似于树的形式,如图所示:

线程组的作用是:可以批量管理线程或线程组对象,有效地对线程或线程组对象进行组织。

线程关联线程组:1级关联

所谓1级关联就是父对象中有子对象,但并不创建孙对象。这种情况在开发中很常见,比如创建一些线程时,为了有效对这些线程进行阻止管理,通常情况下是创建一个线程组,然后再将部分线程归属到该组中,以此来对零散的线程对象进行有效的管理。

看一下简单的1级关联的例子:

public class MyThread49 implements Runnable {

        public void run() {

            try {

                while (!Thread.currentThread().isInterrupted()) {

                    System.out.println("ThreadName = " + Thread.currentThread().getName());

                    Thread.sleep(3000);

                }

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        }

    }

    public static void main(String[] args) {

        MyThread49 mt0 = new MyThread49();

        MyThread49 mt1 = new MyThread49();

        ThreadGroup tg = new ThreadGroup("新建线程组1");

        Thread t0 = new Thread(tg, mt0);

        Thread t1 = new Thread(tg, mt1);

        t0.start();

        t1.start();

        System.out.println("活动的线程数为:" + tg.activeCount());

        System.out.println("线程组的名称为:" + tg.getName());

    }

看一下运行结果:

活动的线程数为:2

ThreadName = Thread-1

ThreadName = Thread-0

线程组的名称为:新建线程组1

ThreadName = Thread-1

ThreadName = Thread-0

ThreadName = Thread-1

ThreadName = Thread-0

ThreadName = Thread-1

ThreadName = Thread-0

...

控制台上打印出的信息表示线程组中有两个线程,并且打印出了线程组的名称。另外,两个线程无限隔3秒打印,也符合代码预期

线程关联线程组:多级关联

所谓的多级关联就是父对象中有子对象,子对象中再创建子对象买也就出现了子孙的效果了。但是这种写法在开发中不太常见,因为线程树如果涉及得复杂反而不利于线程对象的管理,不过JDK确实提供了多级关联的线程树结构。

多级关联的代码就不写了,简单看一下怎么使用关机关联,查看下JDK API的ThreadGroup构造方法:

注意一下第二个,假如要使用多级关联一般就是用第二个构造函数。第一个参数表示新线程组的父线程组,第二个参数表示新线程组的名称,有了父线程组和新线程组的名称,自然可以构造出一个新的线程组来了。

当然用第一个构造方法也是可以的,下一部分就会提到。

另外注意一点,线程必须启动后才能归到指定线程组中。

线程组自动归属特性

自动归属的意思就是自动归到当前线程组中,看一下例子:

public static void main(String[] args) {

        System.out.println(
            "A处线程:" + Thread.currentThread().getName() + ", 所属线程:" + Thread.currentThread().getThreadGroup().getName() +

                ", 组中有线程组数量:" + Thread.currentThread().getThreadGroup().activeGroupCount());

        ThreadGroup group = new ThreadGroup("新的组");

        System.out.println(
            "B处线程:" + Thread.currentThread().getName() + ", 所属线程:" + Thread.currentThread().getThreadGroup().getName() +

                ", 组中有线程组数量:" + Thread.currentThread().getThreadGroup().activeGroupCount());

        ThreadGroup[] tg = new ThreadGroup[Thread.currentThread().getThreadGroup().activeGroupCount()];

        Thread.currentThread().getThreadGroup().enumerate(tg);

        for (int i = 0; i < tg.length; i++)

            System.out.println("第一个线程组名称为:" + tg[i].getName());

    }

看一下运行结果:

A处线程:main, 所属线程:main, 组中有线程组数量:0

B处线程:main, 所属线程:main, 组中有线程组数量:1

第一个线程组名称为:新的组

从结果看,实例化了一个group出来,没有指定线程组,那么自动归到当前线程所属的线程组中,也就是隐式地在一个线程组中添加了一个子线程组。

根线程组

看一下根线程组: 

public static void main(String[] args) {

        System.out.println(Thread.currentThread().getThreadGroup().getParent().getName());

        System.out.println(Thread.currentThread().getThreadGroup().getParent().getParent().getName());

    }

看一下运行结果:

system

Exception in thread "main" java.lang.NullPointerException

at com.xrq.example.e49.TestMain49.main(TestMain49.java:11)

运行结果可以得出两个结论:

1、根线程组就是系统线程组system

2、抛空指针异常是因为系统线程组上已经没有线程组了,所以system的getParent()方法返回的是null,对null调用getName()方法自然是NullPointerException

关于根线程组,看一下ThreadGroup的源码:

/**

* Creates an empty Thread group that is not in any Thread group.

* This method is used to create the system Thread group.

*/

private ThreadGroup() { // called from C code

this.name = "system";

this.maxPriority = Thread.MAX_PRIORITY;

}

一个私有构造方法,说明不是对开发者开放的。注释上已经写得很清楚了,这是C代码调用的,用于构建系统线程组。

批量停止组内线程

使用线程组自然是要对线程做批量管理的,到目前为止我们似乎都没有看见如何对线程组内的线程做批量操作,最后来看一下批量操作线程组内的线程:

public class MyThread50 extends Thread {

        public MyThread50(ThreadGroup tg, String name) {

            super(tg, name);

        }

        public void run() {

            System.out.println("ThreadName = " + Thread.currentThread().getName() +

                "准备开始死循环了");

            while (!this.isInterrupted()) {
            }

            System.out.println("ThreadName = " + Thread.currentThread().getName() +

                "结束了");

        }

    }

    开3个线程:

    public static void main(String[] args) throws InterruptedException {

        ThreadGroup tg = new ThreadGroup("我的线程组");

        MyThread50 mt = null;

        for (int i = 0; i < 3; i++) {

            mt = new MyThread50(tg, "线程" + i);

            mt.start();

        }

        Thread.sleep(5000);

        tg.interrupt();

        System.out.println("调用了interrupt()方法");

    }

看一下运行结果:

ThreadName = 线程0准备开始死循环了

ThreadName = 线程2准备开始死循环了

ThreadName = 线程1准备开始死循环了

调用了interrupt()方法

ThreadName = 线程2结束了

ThreadName = 线程1结束了

ThreadName = 线程0结束了

看到调用了ThreadGroup中的interrupt()方法批量中断了线程组内的线程,这就是ThreadGroup的作用。更多线程组的操作可以查看JDK API。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/7583.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

电脑清理怎么做?5个方法帮你解决电脑空间不足的问题!

案例&#xff1a;电脑清理怎么做&#xff1f; 【求一个电脑清理的好方法&#xff01;电脑垃圾文件太多了又不敢随意删除&#xff0c;怕误删重要的文件&#xff01;哪位友友可以帮我出出主意呀&#xff1f;到底应该怎么清理电脑呢&#xff1f;】 电脑使用的时间长了都会慢慢变…

(链表)合并两个排序的链表

文章目录前言&#xff1a;问题描述&#xff1a;解题思路&#xff1a;代码实现&#xff1a;总结&#xff1a;前言&#xff1a; 此篇是针对链表的经典练习。 问题描述&#xff1a; 输入两个递增的链表&#xff0c;单个链表的长度为n&#xff0c;合并这两个链表并使新链表中的节…

用队列实现栈和用栈实现队列

目录用队列实现栈创建栈实现入栈实现出栈判空取栈顶元素释放用栈实现队列创建队列入队出队返回队列开头的元素判空释放前面我们实现了栈和队列&#xff0c;其实栈和队列之间是可以相互实现的 下面我们来看一下 用 队列实现栈 和 用栈实现队列 用队列实现栈 使用两个队列实现一…

Windows创建用户,添加到管理员组,添加到远程桌面组、RDP

原因&目的 在获得反弹shell后无法得到明文密码&#xff0c;无法远程桌面登录 在目标机器创建新的账号&#xff0c;且为管理员账号&#xff0c;可以远程桌面登录 cmd /c net user gesila 123 /add cmd /c net localgroup Administrators gesila /add cmd /c net localgro…

优思学院 | 质量工程师的职责有哪些?

质量工程师&#xff0c;是一位肩负着质量管理、质量控制和质量改进使命的职业人员。他们身负使命&#xff0c;不断探究、发现、改进&#xff0c;为企业打造出更加卓越、可靠的产品和服务。 在大多数企业中&#xff0c;质量工程师是一个非常重要的职位&#xff0c;他们的职责在…

智能立体车库plc以太网无线应用

一、项目背景 此项目为平面移动类智能停车库&#xff0c;是以传感器网络为支撑的物联网智能停车管理系统。比较于传统的停车场模式&#xff0c;智能立体车库不仅占地少&#xff0c;空间利用率高&#xff0c;智能化程度高&#xff0c;采用集约化系统化的车位管理、收费管理&…

Vue3 集成Element3、Vue-router、Vuex实战

第一步&#xff1a;使用Vite快速搭建Vue 3项目 基础操作总结&#xff1a; npm init vite-app 项目名称cd 项目名称npm installnpm run dev 温馨提示&#xff1a;如果还是Vue 2 环境请参考&#xff1a;Vue 2 升级Vue3 &#xff0c;并且使用vsCode 搭建Vue3 开发环境 Vue 3 …

ARM uboot 启动 Linux 内核

一、编译厂商提供的 uboot 此处&#xff0c;我使用的是九鼎提供的 uboot &#xff1a; 二、烧录 uboot 到 SD 卡 进入 uboot 的 sd_fusing 目录&#xff0c;执行命令烧写 uboot &#xff1a; ./sd_fusing.sh /dev/sdb。 三、将 SD 卡插入开发板&#xff0c;进入 uboot 按任意…

操作系统-内存管理

一、总论 1.1 硬件术语 ​ 为了不让读者懵逼&#xff08;主要是我自己也懵逼&#xff09;&#xff0c;所以特地整理一下在后面会用到术语。 ​ 我们电脑上有个东西叫做内存&#xff0c;他的大小比较小&#xff0c;像我的电脑就是 16 GB 的。它是由 ROM 和 RAM 组成的&#x…

RK3588平台开发系列讲解(同步与互斥篇)信号量介绍

平台内核版本安卓版本RK3588Linux 5.10Android 12文章目录 一、信号量介绍二、信号量API1、结构体2、API三、函数调用流程沉淀、分享、成长,让自己和他人都能有所收获!😄 📢上一章我们看了自旋锁的原理,本章我们一起学习下信号量的用法。 一、信号量介绍 和自旋锁一样,…

渗透测试综合实验(迂回渗透,入侵企业内网并将其控制为僵尸网络)

第1节 实验概述 1.1 实验背景概述 本实验为模拟真实企业环境搭建的漏洞靶场&#xff0c;通过网络入侵Web服务器&#xff0c;拿到控制权限后发现有内网网段&#xff0c;建立隧道做内网穿透&#xff0c;接着进一步扫描内网主机&#xff0c;并进行漏洞利用&#xff0c;最终通过域…

java登录页面验证码的生成以及展示

1、代码示例 后端返回前端一个字节数组。 2、gif图面展示 网页中一张图片可以这样显示&#xff1a; <img src“http://www.jwzzsw.com/images/log.gif”/>也可以这样显示&#xff1a; <img src“data:image/gif;base64,R0lGODlhAgACAIAAAP///wAAACwAAAAAAgACAAACAo…

聚会Party

前言 加油 原文 聚会常用会话 ❶ He spun his partner quickly. 他令他的舞伴快速旋转起来。 ❷ She danced without music. 她跳了没有伴乐的舞蹈。 ❸ The attendants of the ball are very polite. 舞会的服务员非常有礼貌。 ❶ Happy birthday to you! 祝你生日快乐!…

Linux--高级IO--poll--0326

1. poll #include <poll.h> int poll(struct pollfd *fds, nfds_t nfds, int timeout); poll只负责等。 参数介绍 fds 是一个结构体类型的地址&#xff0c;相比于select中的fd_set类型,pollfd结构体可以内部封装一些遍历&#xff0c;解决需要关系那些文件描述符&#…

ES6新特性保姆级别教程【建议收藏】

文章目录1、ECMAScript 6 简介1.1、ECMAScript 和 JavaScript 的关系1.2、ES6 与 ECMAScript 2015 的关系1.3、ECMAScript 的历史2、let 和 const 命令2.1、let 命令2.1.1、基本用法2.1.2、不存在变量提升2.1.3、不允许重复声明2.1.4、暂时性死区2.2、const 命令2.2.1、基本用法…

cuda学习4-6

4. Hardware Implementation NVIDIA GPU架构是围绕一系列可扩展的多线程流式多处理器&#xff08;SM&#xff09;构建的。当主机CPU上的CUDA程序调用内核网格时&#xff0c;网格的块将被枚举并分配给具有可用执行能力的多处理器。线程块的线程在一个多处理器上并发执行&#x…

C++内存管理详解

大家好&#xff0c;这里是bang_bang&#xff0c;今天来分享下内存管理的知识。 目录 1.C/C内存分布 2.C内存管理方式 2.1new/delete操作内置类型 2.2new/delete操作自定义类型 3.operator new与operator delete函数 3.1operator new 3.2operator delete 4.new和delete的实现…

367. 有效的完全平方数 ——【Leetcode每日一题】

367. 有效的完全平方数 给你一个正整数 num 。如果 num 是一个完全平方数&#xff0c;则返回 tru &#xff0c;否则返回 false 。 完全平方数 是一个可以写成某个整数的平方的整数。换句话说&#xff0c;它可以写成某个整数和自身的乘积。 不能使用任何内置的库函数&#xf…

Mybatis框架源码笔记(九)之反射工具类解析

1 反射工具类 Java中的反射功能虽然强大&#xff0c;但是代码编写起来比较复杂且容易出错。Mybatis框架提供了专门的反射包&#xff0c;对常用的反射操作进行了简化封装&#xff0c;提供了更简单方便的API给调用者进行使用&#xff0c;主要的反射包代码结果如下&#xff1a; …

React 组件的 children 数据使用

children 属性表示该组件的子节点&#xff0c;只要组件内部有子节点&#xff0c;props 就有该属性&#xff0c;是自动带上的&#xff0c;不需要开发者添加。 children 可以是 普通文本、普通标签元素、函数、JSX … 案例一&#xff1a;普通文本 import React from "rea…
最新文章