Java 多线程 - 为什么创建一个线程就开销大了?和创建一个普通 Java 对象有什么差别?

频繁创建新线程有什么缺点?

1.不受控风险

系统资源有限,每个人针对不同业务都可以手动创建线程,并且创建标准不一样(比如线程没有名字)。当系统运行起来,所有线程都在疯狂抢占资源,无组织无纪律,内存很容易被无情榨干耗尽。

另外,过多的线程自然也会引起上下文切换的开销。

 

2.频繁创建开销大

new Thread() 在操作系统层面并没有创建新的线程;

真正转换为操作系统层面创建一个线程,还要调用操作系统内核的API,然后操作系统要为该线程分配一系列的资源。

 

2.1 new Object() 过程

Object obj = new Object();

当我需要【对象】时,我就会给自己 new 一个(不知你是否和我一样),这个过程你应该很熟悉了:

  1. 分配一块内存 M
  2. 在内存 M 上初始化该对象
  3. 将内存 M 的地址赋值给引用变量 obj

就是这么简单

 

2.2 new Thread() 过程

上面已经提到了,创建一个线程还要调用操作系统内核API。为了更好的理解创建并启动一个线程的开销,我们需要看看 JVM 在背后帮我们做了哪些事情:

  1. 它为一个线程栈分配内存,该栈为每个线程方法调用保存一个栈帧
  2. 每一栈帧由一个局部变量数组、返回值、操作数堆栈和常量池组成
  3. 一些支持本机方法的 jvm 也会分配一个本机堆栈
  4. 每个线程获得一个程序计数器,告诉它当前处理器执行的指令是什么
  5. 系统创建一个与Java线程对应的本机线程
  6. 将与线程相关的描述符添加到JVM内部数据结构中
  7. 线程共享堆和方法区域

这段描述稍稍有点抽象,用数据来说明创建一个线程(即便不干什么)需要多大空间呢?答案是大约 1M 左右

 
java -XX:+UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=summary -XX:+PrintNMTStatistics -version

 

 

上图是我用 Java8 的测试结果,19个线程,预留和提交的大概都是19000+KB,平均每个线程大概需要 1M 左右的大小(Java11的结果完全不同,这个大家自行测试吧)

相信到这里你已经明白了,对于性能要求严苛的现在,频繁手动创建/销毁线程的代价是非常巨大的,解决方案自然也是你知道的线程池了

参考文献

作者:日拱一兵
链接:https://juejin.cn/post/6844904134324256775
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

posted on 2021-09-13 13:43  frank_cui  阅读(1330)  评论(0编辑  收藏  举报

导航

levels of contents