频繁创建新线程有什么缺点?
1.不受控风险
系统资源有限,每个人针对不同业务都可以手动创建线程,并且创建标准不一样(比如线程没有名字)。当系统运行起来,所有线程都在疯狂抢占资源,无组织无纪律,内存很容易被无情榨干耗尽。
另外,过多的线程自然也会引起上下文切换的开销。
2.频繁创建开销大
new Thread() 在操作系统层面并没有创建新的线程;
真正转换为操作系统层面创建一个线程,还要调用操作系统内核的API,然后操作系统要为该线程分配一系列的资源。
2.1 new Object() 过程
Object obj = new Object();
当我需要【对象】时,我就会给自己 new 一个(不知你是否和我一样),这个过程你应该很熟悉了:
- 分配一块内存 M
- 在内存 M 上初始化该对象
- 将内存 M 的地址赋值给引用变量 obj
就是这么简单
2.2 new Thread() 过程
上面已经提到了,创建一个线程还要调用操作系统内核API。为了更好的理解创建并启动一个线程的开销,我们需要看看 JVM 在背后帮我们做了哪些事情:
- 它为一个线程栈分配内存,该栈为每个线程方法调用保存一个栈帧
- 每一栈帧由一个局部变量数组、返回值、操作数堆栈和常量池组成
- 一些支持本机方法的 jvm 也会分配一个本机堆栈
- 每个线程获得一个程序计数器,告诉它当前处理器执行的指令是什么
- 系统创建一个与Java线程对应的本机线程
- 将与线程相关的描述符添加到JVM内部数据结构中
- 线程共享堆和方法区域
这段描述稍稍有点抽象,用数据来说明创建一个线程(即便不干什么)需要多大空间呢?答案是大约 1M
左右
java -XX:+UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=summary -XX:+PrintNMTStatistics -version
上图是我用 Java8 的测试结果,19个线程,预留和提交的大概都是19000+KB,平均每个线程大概需要 1M 左右的大小(Java11的结果完全不同,这个大家自行测试吧)
相信到这里你已经明白了,对于性能要求严苛的现在,频繁手动创建/销毁线程的代价是非常巨大的,解决方案自然也是你知道的线程池了
参考文献
作者:日拱一兵链接:https://juejin.cn/post/6844904134324256775
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。