我们的项目用到了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. Java中string.equalsIgnoreCase("0")与"0".equalsIgnoreCase(string)的区别:

    string.equalsIgnoreCase("0"):如果string为null,会抛出java.lang.NullPointerException异常. "0&qu ...

  2. 关于Skyline沿对象画boundingbox的探讨

    先来说说为什么要搞这个?项目中经常遇到的一个操作就是选定对象,以前都是通过Tint设置对象颜色来标识选定对象,但是随着图层中模型增多,模型色彩丰富,会出现选定色与对象颜色对比不明显的情况.因为看到Te ...

  3. Python开发爬虫之BeautifulSoup解析网页篇:爬取安居客网站上北京二手房数据

    目标:爬取安居客网站上前10页北京二手房的数据,包括二手房源的名称.价格.几室几厅.大小.建造年份.联系人.地址.标签等. 网址为:https://beijing.anjuke.com/sale/ B ...

  4. Rxjs常用operators

    本文使用的是angular6内置的rxjs,版本号为6.3.3 concat 通过顺序地发出多个 Observables 的值将它们连接起来,一个接一个的. 参数: 名称 类型 属性 描述 other ...

  5. Python 使用Python远程连接并操作InfluxDB数据库

    使用Python远程连接并操作InfluxDB数据库 by:授客 QQ:1033553122 实践环境 Python 3.4.0 CentOS 6 64位(内核版本2.6.32-642.el6.x86 ...

  6. C#监控指定目录的文件变化的代码

    如下的资料是关于C#监控指定目录的文件变化的代码. FileSystemWatcher watcher = new FileSystemWatcher();watcher.Path = @" ...

  7. python爬虫实战:利用scrapy,短短50行代码下载整站短视频

    近日,有朋友向我求助一件小事儿,他在一个短视频app上看到一个好玩儿的段子,想下载下来,可死活找不到下载的方法.这忙我得帮,少不得就抓包分析了一下这个app,找到了视频的下载链接,帮他解决了这个小问题 ...

  8. GitHub和75亿美金

    如果你是看到了75亿进来的,还在纳闷前面那个github的是个什么,你可以走人了?如果你进来是想看到微软两个字的,请继续. 微软以75亿美金的股票收购Github这件事情,从周六一早我爬山到香山琉璃塔 ...

  9. SQLServer之修改表值函数

    修改表值函数注意事项 更改先前通过执行 CREATE FUNCTION 语句创建的现有 Transact-SQL 或 CLR 函数,但不更改权限,也不影响任何相关的函数.存储过程或触发器. 不能用 A ...

  10. man -f/-k [keyword]在fedora 29 中报错nothing appropriate

    我们在使用 man 手册的时候,可以使用man -f [keyword]去查询keyword的在线文档,但是这时候会报错:(图来源自网络) 这是因为我们还没有建立 man 手册的索引缓存: 我们可以使 ...