auto.js停止所有线程_Java并发编程 - 线程组的概念和使用

一.概念

Java中使用ThreadGroup类来代表线程组,表示一组线程的集合,可以对一批线程和线程组进行管理。可以把线程归属到某一个线程组中,线程组中可以有线程对象,也可以有线程组,组中还可以有线程,这样的组织结构有点类似于树的形式,如图所示。

4769fdb4322edc6a5882634c39315c20.png

线程组


用户创建的所有线程都属于指定线程组,如果没有显式指定属于哪个线程组,那么该线程就属于默认线程组(即main线程组)。默认情况下,子线程和父线程处于同一个线程组。
此外,只有在创建线程时才能指定其所在的线程组,线程运行中途不能改变它所属的线程组,也就是说线程一旦指定所在的线程组就不能改变。

二.为什么要使用线程组

1.安全

同一个线程组的线程是可以相互修改对方的数据的。但如果在不同的线程组中,那么就不能“跨线程组”修改数据,可以从一定程度上保证数据安全。

2.批量管理

可以批量管理线程或线程组对象,有效地对线程或线程组对象进行组织或控制。

三. ThreadGroup类

1.字段

private final ThreadGroup parent;// 线程组的线程组,final 表名 线程组 不可以随便变更String name; //名字int maxPriority;//这个线程组 的元素 例如 线程 线程组的最大优先级,具体实现是 当线程或者线程组自身设定优先级的时候,总是取  自己父线程组的优先级和要设定的优先级的最小值boolean destroyed;//判断是否销毁了boolean daemon;//当守护进程线程组的最后一个线程停止或最后一个线程组被销毁时,将自动销毁该线程组。int nUnstartedThreads = 0;int nthreads;//这个线程组  里面的线程数量Thread threads[];//线程数组 ,持有 线程的引用int ngroups;//这个线程组  里面的线程组数量ThreadGroup groups[];//线程组数组 ,持有线程组的引用

2.构造函数

//创建不在任何线程组中的空线程组。//此方法用于创建系统线程组。private ThreadGroup()//创建一个新线程组。这个新组的父线程组是指定的线程组parent。线程组的 名字 就是name会对 parent 调用checkAccess() 确定当前运行的线程是否具有修改此线程组的权限(比如 设置setDaemon)。有可能会抛出SecurityException异常public ThreadGroup(ThreadGroup parent, String name)//构造一个新线程组。这个新组的父线程组是当前运行线程的线程组。 就是调用上面的方法public ThreadGroup(String name) {    this(Thread.currentThread().getThreadGroup(), name);}

3.公共方法

public final String getName()//返回线程组名字//返回父线程组  parent 调用checkAccess() 确定当前运行的线程是否具有修改此线程组的权限。//有可能会抛出SecurityException异常public final ThreadGroup getParent()public final int getMaxPriority() //返回线程组优先级//测试此线程组是否是守护进程线程组。当守护进程线程组的最后一个线程停止或最后一个线程组被销毁时,将自动销毁该线程组。public final boolean isDaemon() public synchronized boolean isDestroyed()//测试该线程组是否已被销毁。 public final void setDaemon(boolean daemon)//将线程组设置成守护线程组 ,会检查 当前线程是否具有权限 修改线程组 //设定当前线程组以及子线程组的 优先级,取pri和当前线程组的父线程组的优先级的较小值为准。  //这个之所以会限制 Thread的最大优先级  //具体实现是 当线程或者线程组自身设定优先级的时候,总是取  自己父线程组的优先级和要设定的优先级的最小值 //会检查 当前线程是否具有权限 修改线程组public final void setMaxPriority(int pri) //测试,当前这个线程组是否是 g线程组的父线程 或者参数public final boolean parentOf(ThreadGroup g) //检查 当前线程是否具有权限 修改线程组  比如在当前线程中 用线程组自己本身调用它自己的一些方法 ,都会检查public final void checkAccess()//返回此线程组及其子线程组中活动线程数量的估计值。递归地遍历此线程组中的所有子组。 如果当前线程组已经destroyed,返回0 public int activeCount()//将线程组的中线程 活动线程放入list[]里面 会自动扩大这个数组,如果{@code recurse}为{@code true},则此方法递归枚举此线程组的所有子组,并引用这些子组中的每个活动线程                                             //注意这个声明数组的方式public int enumerate(Thread list[], boolean recurse)//和上面方法类似  只不过 下面这个 ThreadGrouppublic int enumerate(ThreadGroup list[])public int enumerate(ThreadGroup list[], boolean recurse) //返回此线程组及其子组中活动组的数量的估计值。递归地遍历此线程组中的所有子组。public int activeGroupCount()//interrupt此线程组中的所有线程。包括 子线程组中的线程public final void interrupt()

4.一个特殊方法

public void uncaughtException(Thread t, Throwable e)

这个方法呢,作用很简单 使 t 线程 抛出一个 Throwable e的异常。这个e 异常 也可以是你自己定义的异常。
如果给线程设置了默认未捕获异常处理程序,那么,在上面自定义的Throwable 会被这个捕获,如果没有设置,就打印标注错误流。对这个方法,存在的意义比较困惑。

Thread.setDefaultUncaughtExceptionHandler((t, e) -> {            System.out.println("默认的  "+t.getName());            System.out.println("默认的  "+e);   });   ThreadGroup threadGroup = new ThreadGroup("father");   Thread two = new Thread(threadGroup,"two");   threadGroup.uncaughtException(two,new IllegalAccessException("ssss"));

运行结果

2850f374a6832e18e38f2f986f653743.png

四.线程组使用示例

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

所谓一级关联就是父对象中有子对象,但并不创建孙对象。比如创建一个线程组,然后将创建的线程归属到该组中,从而对这些线程进行有效的管理。代码示例如下:

public class ThreadGroupTest {    public static void main(String[] args) {        ThreadGroup rootThreadGroup = new ThreadGroup("root线程组");        Thread thread0 = new Thread(rootThreadGroup, new MRunnable(), "线程A");        Thread thread1 = new Thread(rootThreadGroup, new MRunnable(), "线程B");        thread0.start();        thread1.start();    }}class MRunnable implements Runnable {    @Override    public void run() {        while (!Thread.currentThread().isInterrupted()) {            System.out.println("线程名: " + Thread.currentThread().getName() + ", 所在线程组: " + Thread.currentThread().getThreadGroup().getName()) ;            try {                Thread.sleep(1000);            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}

执行结果如下:

线程名: 线程A, 所在线程组: root线程组线程名: 线程B, 所在线程组: root线程组

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

所谓的多级关联就是父对象中有子对象,子对象中再创建孙对象也就出现了子孙的效果了。比如使用下图第二个构造方法,将子线程组归属到某个线程组,再将创建的线程归属到子线程组,这样就会有线程树的效果了。

ea16fc2a2992a9bcd08d451c40c6105a.png

代码示例如下:

public class ThreadGroupTest {    public static void main(String[] args) {        ThreadGroup rootThreadGroup = new ThreadGroup("root线程组");        Thread thread0 = new Thread(rootThreadGroup, new MRunnable(), "线程A");        Thread thread1 = new Thread(rootThreadGroup, new MRunnable(), "线程B");        thread0.start();        thread1.start();        ThreadGroup threadGroup1 = new ThreadGroup(rootThreadGroup, "子线程组");        Thread thread2 = new Thread(threadGroup1, new MRunnable(), "线程C");        Thread thread3 = new Thread(threadGroup1, new MRunnable(), "线程D");        thread2.start();        thread3.start();    }}class MRunnable implements Runnable {    @Override    public void run() {        while (!Thread.currentThread().isInterrupted()) {            System.out.println("线程名: " + Thread.currentThread().getName()                    + ", 所在线程组: " + Thread.currentThread().getThreadGroup().getName()                    + ", 父线程组: " + Thread.currentThread().getThreadGroup().getParent().getName());            try {                Thread.sleep(1000);            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}

执行结果如下:

线程名: 线程A, 所在线程组: root线程组, 父线程组: main线程名: 线程B, 所在线程组: root线程组, 父线程组: main线程名: 线程C, 所在线程组: 子线程组, 父线程组: root线程组线程名: 线程D, 所在线程组: 子线程组, 父线程组: root线程组

3.批量管理组内线程

使用线程组自然是要对线程进行批量管理,比如可以批量中断组内线程,代码示例如下:

public class ThreadGroupTest {    public static void main(String[] args) throws  Exception{        ThreadGroup rootThreadGroup = new ThreadGroup("root线程组");        Thread thread0 = new Thread(rootThreadGroup, new MRunnable("线程A"), "线程A");        Thread thread1 = new Thread(rootThreadGroup, new MRunnable("线程B"), "线程B");        thread0.start();        thread1.start();        ThreadGroup threadGroup1 = new ThreadGroup(rootThreadGroup, "子线程组");        Thread thread2 = new Thread(threadGroup1, new MRunnable("线程C"), "线程C");        Thread thread3 = new Thread(threadGroup1, new MRunnable("线程D"), "线程D");        thread2.start();        thread3.start();        Thread.sleep(1000);        rootThreadGroup.interrupt();        System.out.println("批量中断组内线程");    }    static class MRunnable implements Runnable {        private String name;        public MRunnable(String name){            this.name = name;        }        @Override        public void run() {            while (!Thread.currentThread().isInterrupted()) {                System.out.println("线程名: " + Thread.currentThread().getName()                        + ", 所在线程组: " + Thread.currentThread().getThreadGroup().getName()                        + ", 父线程组: " + Thread.currentThread().getThreadGroup().getParent().getName());                try {                    Thread.sleep(1000);                } catch (InterruptedException e) {                    //e.printStackTrace();                    System.err.println("线程名:" + this.name +", 异常信息:" + e.getMessage());                    break;                }            }            try {                Thread.sleep(1000);            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println(Thread.currentThread().getName() + "执行结束");        }    }}

执行结果如下:

线程名: 线程D, 所在线程组: 子线程组, 父线程组: root线程组线程名: 线程C, 所在线程组: 子线程组, 父线程组: root线程组线程名: 线程B, 所在线程组: root线程组, 父线程组: main线程名: 线程A, 所在线程组: root线程组, 父线程组: main批量中断组内线程线程名:线程A, 异常信息:sleep interrupted线程名:线程B, 异常信息:sleep interrupted线程名:线程C, 异常信息:sleep interrupted线程名:线程D, 异常信息:sleep interrupted线程B执行结束线程D执行结束线程A执行结束线程C执行结束

本文只是对Java中的ThreadGroup类进行了简单的介绍和使用示范,更多线程组的操作可以查看JDK API。
----------------------------------------------------


转载自:
https://www.jianshu.com/p/6902ae30f0f2

https://blog.csdn.net/a1064072510/article/details/87455525

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值