我们的项目用到了ThreadGroup 把thread放到了threadGroup中,名称统一起来了;

    private static final ExecutorService EXECUTOR_SERVICE = new ThreadPoolExecutor(, ,
5L, TimeUnit.MINUTES,
new ArrayBlockingQueue<>(), new ThreadFactory() { private final ThreadGroup threadGroup = new ThreadGroup("fileTemplateMethodThreadGroup"); private final AtomicInteger threadNumber = new AtomicInteger(); @Override
public Thread newThread(Runnable r) {
return new Thread(threadGroup, r, "fileTemplateMethod-thread-pool-" + threadNumber.getAndIncrement());
}
}, (r, executor) -> {
if (!executor.isShutdown()) {
/* 丢弃队列最老的数据 */
if (executor.getQueue().poll() != null) {
Cat.logMetricForCount(CatConstant.METRIC_DISCARD_FILE_TASK_COUNT);
}
executor.execute(r);
}
});

ThreadGroup 可以把thread的名字统一起来。一起处理catch。

ThreadGroup是Java提供的一种对线程进行分组管理的手段,可以对所有线程以组为单位进行操作,如设置优先级、守护线程等。

线程组也有父子的概念,如下图:

线程组的创建 

public class ThreadGroupCreator {                                              

    public static void main(String[] args) {
//获取当前线程的group
ThreadGroup currentGroup = Thread.currentThread().getThreadGroup();
//在当前线程执行流中新建一个Group1
ThreadGroup group1 = new ThreadGroup("Group1");
//Group1的父线程,就是main线程所在Group
System.out.println(group1.getParent() == currentGroup);
//定义Group2, 指定group1为其父线程
ThreadGroup group2 = new ThreadGroup(group1, "Group2");
System.out.println(group2.getParent() == group1);
}
}

ThreadGroup是位于java.lang包下的一个类,用于统一的线程管理.一旦一个线程加入到一个线程组后,就不能更换线程所在的线程组

将当前线程加入到线程组中

public class ThreadGroupCreator {                                              

    public static void main(String[] args) {
//获取当前线程的group
ThreadGroup currentGroup = Thread.currentThread().getThreadGroup();
//在当前线程执行流中新建一个Group1
ThreadGroup group1 = new ThreadGroup("Group1");
//Group1的父线程,就是main线程所在Group
System.out.println(group1.getParent() == currentGroup);
//定义Group2, 指定group1为其父线程
ThreadGroup group2 = new ThreadGroup(group1, "Group2");
System.out.println(group2.getParent() == group1);
}
}

将ThreadGroup中活跃的线程引用复制到线程组

Thread[] threads = new Thread[num];
threadGroup.enumerate(threads);
for (Thread t : threads) {
System.out.println("线程名-" + t.getName());
}

测试源代码如下

public class MyThread implements Runnable {

@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " -> start");
TimeUnit.SECONDS.sleep();
//随机发生异常
if (ThreadLocalRandom.current().nextInt() > ) {
throw new RuntimeException(Thread.currentThread().getName() + "发生异常");
}
System.out.println(Thread.currentThread().getName() + " -> end");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public class ThreadGroupTest {
public static void main(String[] args) {
int num = ;
ThreadGroup threadGroup = new ThreadGroup("test-group") {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("ThreadGroup捕获到线程异常 - " + e.getMessage());
}
}; List<Thread> threadList = new ArrayList<>();
for (int i = ; i < num; i++) {
Thread thread = new Thread(threadGroup, new MyThread(), "threadname-" + i);
threadList.add(thread);
} System.out.println("运行前线程组中活跃线程数 -> " + threadGroup.activeCount());
System.out.println("开始运行所有线程...");
for (Thread t : threadList) {
t.start();
}
//获取线程组中所有[活动]线程
Thread[] threads = new Thread[num];
threadGroup.enumerate(threads);
for (Thread t : threads) {
System.out.println("线程名-" + t.getName());
}
System.out.println("所有线程运行后,线程组中活跃线程数-" + threadGroup.activeCount());
//不断的查看线程组中活跃的线程数
Thread thread = new Thread(() -> {
int num1;
try {
while ((num1 = threadGroup.activeCount()) > ) {
System.out.println("当前线程组活跃线程数为 -> " + num1);
TimeUnit.SECONDS.sleep();
}
System.out.println("All Thread HAS FINISHED");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.start();
}
}

运行结果如下

运行前线程组中活跃线程数 -> 0
开始运行所有线程...

threadname- -> start
threadname- -> start
threadname- -> start
threadname- -> start
threadname- -> start
threadname- -> start
threadname- -> start
threadname- -> start
threadname- -> start
线程名-threadname-
threadname- -> start
线程名-threadname-
线程名-threadname-
线程名-threadname-
线程名-threadname-
线程名-threadname-
线程名-threadname-
线程名-threadname-
线程名-threadname-
线程名-threadname-
所有线程运行后,线程组中活跃线程数-
当前线程组活跃线程数为 ->
当前线程组活跃线程数为 ->
当前线程组活跃线程数为 ->
当前线程组活跃线程数为 ->
当前线程组活跃线程数为 ->
当前线程组活跃线程数为 ->
当前线程组活跃线程数为 ->
当前线程组活跃线程数为 ->
当前线程组活跃线程数为 ->
当前线程组活跃线程数为 ->
threadname- -> end
threadname- -> end
ThreadGroup捕获到线程异常 - threadname-7发生异常
ThreadGroup捕获到线程异常 - threadname-2发生异常
threadname- -> end
ThreadGroup捕获到线程异常 - threadname-3发生异常
ThreadGroup捕获到线程异常 - threadname-9发生异常
ThreadGroup捕获到线程异常 - threadname-1发生异常
threadname- -> end
threadname- -> end
All Thread HAS FINISHED
---------------------

线程组的基本操作

注意:后添加进线程组的线程,其优先级不能大于线程组的优先级

public class ThreadGroupBasic {                                                      

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

        ThreadGroup group = new ThreadGroup("group1");
Thread thread = new Thread(group, () -> {
while(true) {
try {
TimeUnit.SECONDS.sleep();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "thread");
thread.setDaemon(true);
thread.start(); TimeUnit.MILLISECONDS.sleep(); ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
//递归获取mainGroup中活跃线程的估计值
System.out.println("activeCount = " + mainGroup.activeCount());
//递归获mainGroup中的活跃子group
System.out.println("activeGroupCount = " + mainGroup.activeGroupCount());
//获取group的优先级, 默认为10
System.out.println("getMaxPriority = " + mainGroup.getMaxPriority());
//获取group的名字
System.out.println("getName = " + mainGroup.getName());
//获取group的父group, 如不存在则返回null
System.out.println("getParent = " + mainGroup.getParent());
//活跃线程信息全部输出到控制台
mainGroup.list();
System.out.println("----------------------------");
//判断当前group是不是给定group的父线程, 如果两者一样,也会返回true
System.out.println("parentOf = " + mainGroup.parentOf(group));
System.out.println("parentOf = " + mainGroup.parentOf(mainGroup)); } }

线程组的Interrupt 

public class ThreadGroupInterrupt {                                                     

    public static void main(String[] args) throws InterruptedException {
ThreadGroup group = new ThreadGroup("TestGroup");
new Thread(group, () -> {
while(true) {
try {
TimeUnit.MILLISECONDS.sleep();
} catch (InterruptedException e) {
//received interrupt signal and clear quickly
System.out.println(Thread.currentThread().isInterrupted());
break;
}
}
System.out.println("t1 will exit");
}, "t1").start();
new Thread(group, () -> {
while(true) {
try {
TimeUnit.MILLISECONDS.sleep();
} catch (InterruptedException e) {
//received interrupt signal and clear quickly
System.out.println(Thread.currentThread().isInterrupted());
break;
}
}
System.out.println("t2 will exit");
}, "t2").start();
//make sure all threads start
TimeUnit.MILLISECONDS.sleep(); group.interrupt();
} }

线程组的destroy 

public class ThreadGroupDestroy {                                             

    public static void main(String[] args) {
ThreadGroup group = new ThreadGroup("TestGroup");
ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
//before destroy
System.out.println("group.isDestroyed=" + group.isDestroyed());
mainGroup.list(); group.destroy();
//after destroy
System.out.println("group.isDestroyed=" + group.isDestroyed());
mainGroup.list();
} }

线程组设置守护线程组

线程组设置为守护线程组,并不会影响其线程是否为守护线程,仅仅表示当它内部没有active的线程的时候,会自动destroy

public class ThreadGroupDaemon {                                               

    public static void main(String[] args) throws InterruptedException {
ThreadGroup group1 = new ThreadGroup("group1");
new Thread(group1, () -> {
try {
TimeUnit.SECONDS.sleep();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "group1-thread1").start();
ThreadGroup group2 = new ThreadGroup("group2");
new Thread(group2, () -> {
try {
TimeUnit.SECONDS.sleep();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "group1-thread2").start();
group2.setDaemon(true); TimeUnit.SECONDS.sleep();
System.out.println(group1.isDestroyed());
System.out.println(group2.isDestroyed());
}
}
 

ThreadGroup解读的更多相关文章

  1. java.lang.Thread、java.lang.ThreadGroup和java.lang.ThreadLocal<T>详细解读

    一.Thread类 public class Thread extends Object  impments Runnable 线程是程序中的 执行线程.java虚拟机允许应用程序并发地运行多个执行线 ...

  2. JVM源码分析之堆外内存完全解读

    JVM源码分析之堆外内存完全解读   寒泉子 2016-01-15 17:26:16 浏览6837 评论0 阿里技术协会 摘要: 概述 广义的堆外内存 说到堆外内存,那大家肯定想到堆内内存,这也是我们 ...

  3. 对threading模块源码文件的解读(不全)

    # -*- coding: utf-8 -*- #python 27 #xiaodeng #对threading模块源码文件的解读(不全) import threading #类 #Thread() ...

  4. SDWebImage源码解读之SDWebImageDownloaderOperation

    第七篇 前言 本篇文章主要讲解下载操作的相关知识,SDWebImageDownloaderOperation的主要任务是把一张图片从服务器下载到内存中.下载数据并不难,如何对下载这一系列的任务进行设计 ...

  5. SDWebImage源码解读 之 NSData+ImageContentType

    第一篇 前言 从今天开始,我将开启一段源码解读的旅途了.在这里先暂时不透露具体解读的源码到底是哪些?因为也可能随着解读的进行会更改计划.但能够肯定的是,这一系列之中肯定会有Swift版本的代码. 说说 ...

  6. SDWebImage源码解读 之 UIImage+GIF

    第二篇 前言 本篇是和GIF相关的一个UIImage的分类.主要提供了三个方法: + (UIImage *)sd_animatedGIFNamed:(NSString *)name ----- 根据名 ...

  7. SDWebImage源码解读 之 SDWebImageCompat

    第三篇 前言 本篇主要解读SDWebImage的配置文件.正如compat的定义,该配置文件主要是兼容Apple的其他设备.也许我们真实的开发平台只有一个,但考虑各个平台的兼容性,对于框架有着很重要的 ...

  8. SDWebImage源码解读_之SDWebImageDecoder

    第四篇 前言 首先,我们要弄明白一个问题? 为什么要对UIImage进行解码呢?难道不能直接使用吗? 其实不解码也是可以使用的,假如说我们通过imageNamed:来加载image,系统默认会在主线程 ...

  9. SDWebImage源码解读之SDWebImageCache(上)

    第五篇 前言 本篇主要讲解图片缓存类的知识,虽然只涉及了图片方面的缓存的设计,但思想同样适用于别的方面的设计.在架构上来说,缓存算是存储设计的一部分.我们把各种不同的存储内容按照功能进行切割后,图片缓 ...

随机推荐

  1. 好用的开源库(一)——MaterialEditText

    GIthub地址:https://github.com/rengwuxian/MaterialEditText#features 使用文档: 在android新推出的Material Design中对 ...

  2. Spring Boot 整合 docker

    一.什么是docker ? 简介 Docker是一个开源的引擎,可以轻松的为任何应用创建一个轻量级的.可移植的.自给自足的容器.开发者在笔记本上编译测试通过的容器可以批量地在生产环境中部署,包括VMs ...

  3. 页面内容不够高footer始终位于页面的最底部

    相信很多前端工程师在开发页面时会遇到这个情况:当整个页面高度不足以占满显示屏一屏,页脚不是在页面最底部,用户视觉上会有点不好看,想让页脚始终在页面最底部,我们可能会想到用: 1.min-height来 ...

  4. 前端入门10-JavaScript语法之对象

    声明 本系列文章内容全部梳理自以下几个来源: <JavaScript权威指南> MDN web docs Github:smyhvae/web Github:goddyZhao/Trans ...

  5. git操作+一个本地项目推到github上+注意

    git init 创建新文件夹,打开,然后执行以创建新的 git 仓库. git config --global user.name "xxx" git config --glob ...

  6. offic|集成|协同OA|移动办公|

    随着互联网时代的日新月异,移动通讯技术的飞速发展,移动网络技术的更新换代,手机.平板电脑等移动设备越来越智能化.越来越多样化,人们对移动办公的需求也在日益增长.在此背景下北京博信施科技有限公司自主研发 ...

  7. Pycharm使用技巧(转载)

    Pycharm使用技巧(转载) 转载自:http://www.cnblogs.com/cloudtj/articles/5980666.html pycharm使用技巧 https://python. ...

  8. 【重新发布,代码开源】FPGA设计千兆以太网MAC(1)——通过MDIO接口配置与检测PHY芯片

    原创博客,转载请注明出处:[重新发布,代码开源]FPGA设计千兆以太网MAC(1)——通过MDIO接口配置与检测PHY芯片 - 没落骑士 - 博客园 https://www.cnblogs.com/m ...

  9. Redis学习笔记(5)——Redis数据持久化

    出处http://www.cnblogs.com/xiaoxi/p/7065328.html 一.概述 Redis的强大性能很大程度上都是因为所有数据都是存储在内存中的,然而当Redis重启后,所有存 ...

  10. Redis学习笔记(3)——Redis的命令大全

    Redis是一种nosql数据库,常被称作数据结构服务器,因为值(value)可以是 字符串(String), 哈希(Map), 列表(list), 集合(sets) 和 有序集合(sorted se ...