Java多线程编程7--拾遗增补--线程组

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

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

1、线程对象关联线程组:1级关联

所谓的1级关联就是父对象中有子对象,但并不创建子孙对象。这种情况经常出现在开发中,比如创建一些线程时,为了有效地对这些线程进行组织管理,通常的情况下是创建一个线程组,然后再将部分线程归属到该组中。这样的处理可以对零散的线程对象进行有效的组织与规划。

public class MyThread1 extends Thread {
    @Override
    public void run() {
        try{
            while(!Thread.currentThread().isInterrupted()) {
                System.out.println("ThreadName="
                        + Thread.currentThread().getName());
                Thread.sleep(4000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class MyThread2 extends Thread{
    @Override
    public void run() {
        try{
            while(!Thread.currentThread().isInterrupted()) {
                System.out.println("ThreadName="
                        + Thread.currentThread().getName());
                Thread.sleep(4000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class Run {
    public static void main(String[] args) throws InterruptedException {
        MyThread1 t1 = new MyThread1();
        MyThread2 t2 = new MyThread2();
        ThreadGroup group = new ThreadGroup("lcw的线程组");

        Thread aThread = new Thread(group, t1);
        Thread bThread = new Thread(group, t2);
        aThread.start();
        bThread.start();

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

ThreadName=Thread-3

ThreadName=Thread-2

线程组的名称为:lcw的线程组

ThreadName=Thread-3

ThreadName=Thread-2

ThreadName=Thread-3

ThreadName=Thread-2

......

控制台中打印的信息表示线程组中有两个线程,并且打印出了线程组的名称。另外,两个线程一直无限地并且每隔3秒打印日志。

2、线程对象关联线程组:多级关联

所谓的多级关联就是父对象中有子对象,子对象中再创建子对象,也就是出现子孙对象的效果了。但是此种写法在开发中不太常见,如果线程树结构设计得非常复杂反而不利于线程对象的管理,但JDK却提供了支持多级关联的线程树结构。

/**
 * 在main组中添加一个线程组A,然后在这个A组中添加线程对象X和Y
 * 方法activeGroupCount()和activeCount()的值不是固定的,
 * 是系统中环境的一个快照
 */
public class Run {
    public static void main(String[] args) throws InterruptedException {
        ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
        //ThreadGroup(父线程组,子线程组名)
        ThreadGroup group = new ThreadGroup(mainGroup, "AA");

        Runnable runnable = new Runnable() {
            public void run() {
                try {
                    System.out.println("runMethod!");
                    Thread.sleep(1000); //线程必须在运行状态才可以受组管理
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        Thread newThread = new Thread(group, runnable);
        newThread.setName("X");
        newThread.start(); //线程必须启动然后才归到组A中

        Thread newThread2 = new Thread(group, runnable);
        newThread2.setName("Y");
        newThread2.start(); //线程必须启动然后才归到组A中

        ///
        ThreadGroup[] listGroup = new ThreadGroup[Thread.currentThread()
                .getThreadGroup().activeGroupCount()];
        Thread.currentThread().getThreadGroup().enumerate(listGroup);
        System.out.println("main线程中有多少个子线程组:" + listGroup.length
                +", 名字为:" +listGroup[0].getName()
                +",这个子线程组有多少个线程:" + listGroup[0].activeCount());

        Thread[] listThread = new Thread[listGroup[0].activeCount()];
        listGroup[0].enumerate(listThread);
        System.out.println(listThread[0].getName());
        System.out.println(listThread[1].getName());
    }
}
main线程中有多少个子线程组:1, 名字为:AA,这个子线程组有多少个线程:2

X

Y

runMethod!

runMethod!

本程序代码的结构就是main组创建一个新组,然后又在该新组中添加了线程。

3、线程组自动归属特性

自动归属就是自动归到当前线程组中。

/**
 * 方法activeGroupCount()取得当前线程组对象中的子线程组数量
 * 方法enumerate()的作用是将线程组中的子线程以复数的形式
 *     拷贝到ThreadGroup[]数组对象中
 */
public class Run {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("A处线程名:" + Thread.currentThread().getName()
                + ",所属的线程组名为:"+Thread.currentThread().getThreadGroup().getName()
                + ", 中有线程组数量:"+Thread.currentThread().getThreadGroup().activeGroupCount());
        ThreadGroup group = new ThreadGroup("新的组"); //自动加到main组中
        System.out.println("B处线程名:" + Thread.currentThread().getName()
                + ",所属的线程组名为:"+Thread.currentThread().getThreadGroup().getName()
                + ", 中有线程组数量:"+Thread.currentThread().getThreadGroup().activeGroupCount());

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

        System.out.println("第一个线程组名称为:" +threadGroups[0].getName());
    }
}
A处线程名:main,所属的线程组名为:main, 中有线程组数量:0

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

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

本实验要证明的是,在实例化一个ThreadGroup线程组x时如果不指定所属的线程组,则x线程组自动归到当前线程对象所属的线程组中,也就是隐式地在一个线程组中添加了一个子线程组,所以在控制台中打印的线程组数量值由0变成了1.

4、获取根线程组

public class Run {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("线程:"+Thread.currentThread().getName()
                +",所在的线程组名为:"+Thread.currentThread().getThreadGroup().getName());

        System.out.println("main线程所在的线程组的父线程组的名称是:"
                +Thread.currentThread().getThreadGroup().getParent().getName());

        System.out.println("main线程所有的线程组的父线程组的你线程组的名称是:"
                +Thread.currentThread().getThreadGroup().getParent().getParent().getName());
    }
}
线程:main,所在的线程组名为:main

main线程所在的线程组的父线程组的名称是:system

Exception in thread "main" java.lang.NullPointerException

运行结果说明JVM的根线程组就是system,再取其父线程组则出现空异常。

5、线程组里加线程组

public class Run {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("线程组名称:"
                + Thread.currentThread().getThreadGroup().getName());
        System.out.println("线程组中活动的线程数量:"
                +Thread.currentThread().getThreadGroup().activeCount());
        System.out.println("线程组中线程组的数据--加之前:"
                +Thread.currentThread().getThreadGroup().activeGroupCount());

        ThreadGroup newGroup = new ThreadGroup(Thread.currentThread()
                .getThreadGroup(), "newGroup");
        System.out.println("线程组中线程组的数量--加之后:"
                +Thread.currentThread().getThreadGroup().activeGroupCount());
        System.out.println("父线程组名称:"
                +Thread.currentThread().getThreadGroup().getParent().getName());
    }
}
线程组名称:main

线程组中活动的线程数量:2

线程组中线程组的数据--加之前:0

线程组中线程组的数量--加之后:1

父线程组名称:system

6、组内的线程批量停止

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

    @Override
    public void run() {
        System.out.println("ThreadName=" + Thread.currentThread().getName()
                +",准备开始死循环了");
        while(!this.isInterrupted()){
        }
        System.out.println("ThreadName=" + Thread.currentThread().getName()
                +",结束了");
    }
}
public class Run {
    public static void main(String[] args) throws InterruptedException {
        ThreadGroup group = new ThreadGroup("myThreadGroup");
        for (int i=0; i<3; i++) {
            MyThread thread = new MyThread(group, "线程"+(i+1));
            thread.start();
        }
        Thread.sleep(1000);
        group.interrupt();
        System.out.println("调用了interrupt方法");
    }
}
ThreadName=线程1,准备开始死循环了

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

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

调用了interrupt方法

ThreadName=线程3,结束了

ThreadName=线程1,结束了

ThreadName=线程2,结束了

7、递归与非递归取得组内对象

public class Run {
    public static void main(String[] args) throws InterruptedException {
        ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
        ThreadGroup groupA = new ThreadGroup(mainGroup, "AA");

        Runnable runnable = new Runnable() {
            public void run() {
                try {
                    System.out.println("runMethod!");
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        ThreadGroup groupB = new ThreadGroup(groupA, "BB");
        //分配空间,但不一定全部用完
        ThreadGroup[] listGroup1 = new ThreadGroup[Thread.currentThread()
                .getThreadGroup().activeGroupCount()];
        //传入true是递归取得子组及子孙组
        Thread.currentThread().getThreadGroup().enumerate(listGroup1, true);
        for (int i=0; i<listGroup1.length; i++) {
            if (listGroup1[i] != null){
                System.out.println("--"+listGroup1[i].getName());
            }
        }
        ThreadGroup[] listGroup2 = new ThreadGroup[Thread.currentThread()
                .getThreadGroup().activeGroupCount()];
        Thread.currentThread().getThreadGroup().enumerate(listGroup2, false);
        for (int i=0; i<listGroup2.length; i++) {
            if (listGroup2[i] != null){
                System.out.println("**" +listGroup2[i].getName());
            }
        }
    }
}
--AA

--BB

**AA

时间: 2024-08-28 12:54:16

Java多线程编程7--拾遗增补--线程组的相关文章

Java多线程编程7--拾遗增补--线程的状态(new,runnable,terminated,timed_waiting,waiting,blocked)

线程对象在不同的运行时期有不同的状态,状态信息就存在于Thread内部类的State枚举类中 public enum State { /** * new状态是线程实例化后还从未执行start()方法时的状态 */ NEW, /** * runnable状态是线程进人运行的状态 */ RUNNABLE, /** * blocked状态出现在某一个线程在等待锁的时候. */ BLOCKED, /** * waiting是线程执行了Object.wait()方法后所处的状态 */ WAITING, /

java多线程编程(1) 线程的基本知识

在前面研究过多线程与进程的区别. 这里在稍微总结一下: 进程:程序动态的一次执行过程. 线程:可以只是程序员的一部分的执行过程 每个进程有多个线程组成,在java程序中,至少两个线程一个是垃圾回收线程和main线程. 线程占有的资源更少,早java中就是每个线程都有自己的工作区,就是有自己独立的栈空间.多个线程共享一些内存资源,堆是共享的. 多线程的力度小,并发度高,这样系统的吞吐量就很大,只有好处吗?调度和执行线程是需要资源的,就是像是数据库中的索引和数据库中的锁一个道理,并发会带来什么问题呢

“全栈2019”Java多线程第十三章:线程组ThreadGroup详解

难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多线程第十三章:线程组ThreadGroup详解 下一章 "全栈2019"Java多线程第十四章:线程与堆栈详解 学习小组 加入同步学习小组,共同交流与进步. 方式一:关注头条号Gorhaf,私信"Java学习小组". 方式二:关注公众号Gorhaf,回复"Ja

java多线程编程--如何开始一个线程

如何开始一个线程 1. java多线程的实现方式 1.1 继承Thread类 定义类如下: public SubThread extends Thread { @override public void run() { ... } } 使用时: Thread subThread = new SubThread(); subThread.start(); 可以使用Thread类已有的函数进行操作. 1.2 实现Runnable接口 定义类如下: public SubThread implement

Java多线程(十一):线程组

线程组 线程组可以批量管理线程和线程组对象. 一级关联 例子如下,建立一级关联. public class MyThread43 implements Runnable{ public void run() { try { while (!Thread.currentThread().isInterrupted()) { System.out.println("ThreadName = " + Thread.currentThread().getName()); Thread.slee

java多线程编程--如何终止一个线程

1. Thread.stop()函数 stop()函数终止线程就像是强行拔掉电源线关机一样,可能会带来未知风险,因此目前不再推荐使用这种方式.请忘记它吧~~ 2. 改变标志变量状态 通常我们会在线程中使用一个标志变量来控制线程的运行,如: public class TestCallable implements Runnable { private boolean running = true; public void stop() { this.running = false; } publi

Java多线程编程(三)线程的优先级、同步与死锁

线程的优先级: 线程的优先级分为三种,分别是: 1-MIN_PRIORITY 10-MAX_PRIORITY 5-NORM_PRIORITY 如果什么都不设置默认值是5 线程的优先级可以影响线程的执行顺序,当然这里指的是有可能影响,不会一定影响.在默认状态下(比如说主线程)它的默认值是5 具体代码演示: package com.yeqc.thread; class ThRun implements Runnable{ @Override public void run() { for(int i

Java多线程编程基础之线程对象

在进入java平台的线程对象之前,基于基础篇(一)的一些问题,我先插入两个基本概念. [线程的并发与并行] 在单CPU系统中,系统调度在某一时刻只能让一个线程运行,虽然这种调试机制有多种形式(大多数是时间片轮巡为主),但无论如何,要通过不断切换需要运行的线程让其运行的方式就叫并发(concurrent).而在多CPU系统中,可以让两个以上的线程同时运行,这种可以同时让两个以上线程同时运行的方式叫做并行(parallel). 在上面包括以后的所有论述中,请各位朋友谅解,我无法用最准确的词语来定义储

Java多线程编程详解

线程的同步 由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题.Java语言提供了专门机制以解决这种冲突,有效避免了同一个数据对象被多个线程同时访问. 由于我们可以通过 private 关键字来保证数据对象只能被方法访问,所以我们只需针对方法提出一套机制,这套机制就是 synchronized 关键字,它包括两种用法:synchronized 方法和 synchronized 块. 1. synchronized 方法:通过在方法声明中加入 synch