为什么我们创建线程或者线程池的时候,需要指定有意义的线程名称?

最终目的是为了方便回溯。

我们在日常开发中,一个项目中会创建很多个线程池用来资源隔离,但是如果我们没有一个好的命名的话,出问题的时候就会难以定位。

public class Demo5 {
​public static void main( String[] args ) throws IOException {new Thread(()->{System.out.println("保存用户信息..........");
​try {Thread.sleep(4000);} catch (InterruptedException e) {e.printStackTrace();}throw new NullPointerException();}).start();System.in.read();}
}

上面代码是启动一个线程来保存用户信息,然后抛出异常!

报错信息如下:

从运行错误可以分析,Thread-0 抛出了空指针,那么单从这个日志根本无法判断用户模块线程抛出的异常。我们先分析一下Thread-0是怎么来的。

我们先看下创建线程的代码:

public Thread(Runnable target) {init(null, target, "Thread-" + nextThreadNum(), 0);}private static int threadInitNumber;private static synchronized int nextThreadNum() {return threadInitNumber++;}

从上面代码可知,如果我们没有指定线程名称,内部会自动为我们创建线程名称"Thread-"+nextThreadNum()作为线程的默认名。

如果一个系统中有多个业务模块,如用户模块、订单模块、购物车模块等都使用自己的线程池,而没有指定名称,抛出的异常除非与业务内容有关,否则,根本无法判断是哪一个模块出了问题。

创建线程池时候也需要指定线程池的名称

我们可以使用threadFactory来指定线程的名称:

(1) 可以通过线程工厂给每个创建出来的线程设置更有意义的名字。线程池的命名时通过给这个factory增加组前缀来实现的。在虚拟机栈分析时,就可以知道线程任务由哪个线程工厂产生的。

(2) 使用Guava设置线程名字

new ThreadFactoryBuilder().setNameFormat("XX-task-%d").build();

(3)自定义实现:ThreadFactory

Executors静态工厂里默认的threadFactory,线程的命名规则是“pool-数字-thread-数字”。

我们看下线程池:

public class Demo6 {
​public static void main( String[] args ) throws IOException {ThreadPoolExecutor executorOne = new ThreadPoolExecutor(5, 5, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>());
​executorOne.execute(()->{System.out.println("保存用户信息");throw new NullPointerException();});System.in.read();}
}

结果:

我们看到的打印线程池名称是 pool-1-thread-1,那么怎么来的呢?

那我们看下ThreadPoolExecutor源码

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handlerthis(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,Executors.defaultThreadFactory(), handler);
}
 public static ThreadFactory defaultThreadFactory() {return new DefaultThreadFactory();}
DefaultThreadFactory() {SecurityManager s = System.getSecurityManager();group = (s != null) ? s.getThreadGroup() :Thread.currentThread().getThreadGroup();namePrefix = "pool-" +poolNumber.getAndIncrement() +"-thread-";}``````private static final AtomicInteger poolNumber = new AtomicInteger(1);

那我们怎样定义ThreadFactory呢?

public class NamedThreadFactory implements ThreadFactory {private static final AtomicInteger poolNumber = new AtomicInteger(1);private final AtomicInteger threadNumber = new AtomicInteger(1);private  String namePrefix;private final ThreadGroup group;
​public NamedThreadFactory( String name ) {this.namePrefix = namePrefix = name + "-" + poolNumber.getAndIncrement() + "-thread-";SecurityManager s = System.getSecurityManager();group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();}
​@Overridepublic Thread newThread(Runnable r) {Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);if (t.isDaemon())t.setDaemon(false);if (t.getPriority() != Thread.NORM_PRIORITY)t.setPriority(Thread.NORM_PRIORITY);return t;}
}
public class Demo6 {
​public static void main( String[] args ) throws IOException {ThreadPoolExecutor executorOne = new ThreadPoolExecutor(5, 5, 1,TimeUnit.MINUTES, new LinkedBlockingQueue<>(),new NamedThreadFactory("UserModule"));
​executorOne.execute(()->{System.out.println("保存用户信息");throw new NullPointerException();});System.in.read();}
}

结果:

我们看到,从错误栈中的线程名称,我们就可以定位到是哪个模块出现了错误。

总结

创建线程或线程池时请 指定有意义的线程名称,方便出错时回溯。

自定义线程工厂,并且根据外部特征进行分组,比如,来自同一机房的调用,把机房编号赋值给

文源网络,仅供学习之用,如有侵权,联系删除。

我将面试题和答案都整理成了PDF文档,还有一套学习资料,涵盖Java虚拟机、spring框架、Java线程、数据结构、设计模式等等,但不仅限于此。

关注公众号【java圈子】获取资料,还有优质文章每日送达。

创建线程池的正确姿势,请给它指定一个有意义的名字相关推荐

  1. Java多线程学习总结(7)——创建线程池的正确姿势

    一. 通过Executors创建线程池的弊端 在创建线程池的时候,大部分人还是会选择使用Executors去创建. 下面是创建定长线程池(FixedThreadPool)的一个例子,严格来说,当使用如 ...

  2. java线程池shutdown_关闭线程池的正确姿势,shutdown(), shutdownNow()和awaitTermination() 该怎么用?...

    关闭线程池的正确姿势,shutdown(), shutdownNow()和awaitTermination() 该怎么用? ExecutorService 接口提供了三个方法用于手动关闭线程池,分别是 ...

  3. 关于阿里规范禁止使用Executors创建线程池的分析

    文章目录 1.阿里规范 2.Executors主要功能 2.1 newFixedThreadPool 2.2 newSingleThreadExecutor 2.3 newCachedThreadPo ...

  4. 为什么阿里巴巴要禁用Executors创建线程池?

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 作者:何甜甜在吗 juejin.im/post/5dc41c165 ...

  5. boost创建线程池_Java并发 之 线程池系列 (1) 让多线程不再坑爹的线程池

    目录 背景 线程池的来由 什么是线程池 背景总结 用法 通过Executors创建线程池 Executors及其服务的类 Executors常用的几个方法 一个线程池的例子 任务 池子 测试 说明 总 ...

  6. java多线程-线程创建-线程池-java内存模型

    文章目录 ==多线程基础== 进程 线程 浏览器的进程和线程(案例) 线程的异步和同步 多线程的优势 ==多线程的实现方式== 第一种:继承Thread类 第二种:实现Runnable接口 第三种:通 ...

  7. Ubuntu创建新用户的正确姿势

    作者按:因为教程所示图片使用的是 github 仓库图片,网速过慢的朋友请移步<Ubuntu 创建新用户的正确姿势>原文地址.更欢迎来我的小站看更多原创内容:godbmw.com,进行&q ...

  8. 手动创建线程池 效果会更好_创建更好的,可访问的焦点效果

    手动创建线程池 效果会更好 Most browsers has their own default, outline style for the :focus psuedo-class. 大多数浏览器 ...

  9. 为什么创建线程池一定要用ThreadPoolExecutor?

    作者 | 磊哥 来源 | Java面试真题解析(ID:aimianshi666) 转载请联系授权(微信ID:GG_Stone) 在 Java 语言中,并发编程都是依靠线程池完成的,而线程池的创建方式又 ...

最新文章

  1. 再谈select, iocp, epoll,kqueue及各种I/O复用机制 - Shallway - 博客频道 - CSDN.NET
  2. Google开源库Image Captioning部署记录
  3. hyperf自定义注解类_swoole学习六hyperf注解的使用
  4. 电路知识--认识原理图(三)
  5. TensorFlow学习笔记(十四)TensorFLow 用mnist数据做classification
  6. 最稳定的Nginx绿色环境,可无限自定义PHP和mysql版本、同时运行N个版本
  7. 动态给H5页面绑定数据,基本万能无错误!
  8. void函数调用时显示不允许使用不完整的_4位数码管显示模块驱动
  9. C#异步方法调用(四大方法详解)
  10. 关于ThinkPHP框架项目在二级目录时,__PUBLIC__路径的问题
  11. SSL/TLS中的DH算法、DHE算法、 ECDHE算法介绍
  12. 网络安全实验5 证书应用和证书管理
  13. 浅谈CAN总线--- 物理层
  14. 《再贵也能卖到翻》 博客思听 2009年3月
  15. 利用阿里云服务器制作一个浪漫的表白网页
  16. 室性心律失常影响因素分析
  17. 看完这个,css中position的绝对定位相对定位就懂了
  18. 剑指Offer面试题:31.两个链表的第一个公共节点
  19. windows7 64位机上安装配置CUDA 9.1+cudnn7操作步骤
  20. 电路设计的3W原则、5W原则、3H原则、5H原则、20H原则、五五规则

热门文章

  1. better-scroll的使用
  2. 创业公司的管理工具集萃
  3. 绝地求生-对象缓冲表获取
  4. 成佩涛-站酷(ZCOOL) 刷评论漏洞
  5. thinkpad bios 设置U启动
  6. C语言时间函数(2)之time,ctime,gmtime,localtime,asctime,mktime
  7. 【用SW将三维图变成dwg格式的工程图(dwg格式可以直接用CAD打开并进行修改标注)】
  8. 笔试中题目的时间复杂度以及快读快写介绍
  9. vmware windows server2008密码忘记后重置密码
  10. IPAD 游戏开发方案,windows开发