一、线程的命名
在构造线程的时候可以为线程起一个有特殊意义的名字,这也是一种比较好的做法,有助于排查问题。
没有提供线程命名参数的构造函数:
- Thread()
- Thread(Runnable target)
- Thread(ThreadGroup group,Runnable target)
如果没有为线程显式的指定一个名字,那么线程将会以"Thread-"作为前缀于自增数字进行组合,这个数字在JVM中不断自增。
提供了指定线程名称的构造函数:
- Thread(Runnable target,String name)
- Thread(String name)
- Thread(ThreadGroup group,Runnable target,String name)
- Thread(ThreadGroup group,Runnable target,String name,long stackSize)
- Thread(ThreadGroup group,String name)
二、Thread与ThreadGroup
1.main线程所在的ThreadGroup称为main
2.构造一个线程的时候如果没有显式的指定ThreadGroup,那么他将会和父线程同属于一个ThreadGroup
三、JVM内存结构
1.程序计数器
程序计数器在JVM中所起的作用就是用于存放当前线程接下来将要执行的字节码指令、分支、循环、跳转、异常处理等信息。每条线程都具有一个独立的程序计数器,各个线程之间互不影响,程序计数器是线程私有的。
2.Java虚拟机栈
Java虚拟机栈也是线程私有的,它的生命周期和线程相同,是在JVM运行时所创建的。在线程中,方法在执行的时候都会创建一个名为栈帧的数据结构,主要用于存放局部变量表、操作栈、动态链接、方法出口等信息。虚拟机栈的大小可以通过-xss来配置,同等的虚拟机栈如果局部变量表等内存越小则可被压入的栈帧就会越多。
3.本地方法栈
Java中提供了调用本地方法的接口,也就是C/C++程序,JVM为本地方法所划分的内存区域便是本地方法栈,也是线程私有的内存区域。
4.堆内存
堆内存是JVM中最大的一块内存区域,被所有的线程所共享,Java在运行期间创建的所有对象几乎都在该内存区域,该区域也是垃圾回收器重点照顾的区域,又称“GC堆”。
5.方法区
方法区也是被多个线程共享的内存区域,它主要用于存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器(JIT)编译后的代码等数据。
6.Java 8 元空间
JDK1.8版本起,JVM的内存区域发生了一些改变,持久代内存被彻底删除,取而代之的是元空间。元空间是堆内存的一部分,JVM可以减少内存碎片,节省GC扫描和压缩的时间。
四、Thread与虚拟机栈
虚拟机栈内存与线程的创建、运行、销毁等关系密切,虚拟机栈内存是线程私有的,堆内存固定,栈内存越大,JVM可创建的线程数量越小。堆内存的增大对线程数量的影响也是反比关系,但是并没有像栈内存那样明显。
线程数量=(最大地址空间-JVM堆内存-ReservedOsMemory)/ThreadStackSize(XSS)
注1:操作系统中一个进程的内存大小是有限制的,这个限制称为地址空间。
注2:ReservedOsMemory是系统保留内存,一般在136MB左右。
五、守护线程
守护线程是一类比较特殊的线程,一般用于处理一些后台的工作,比如JDK的垃圾回收线程。守护线程具备自动结束生命周期的特性,适合执行一些后台任务,在退出JVM进程的时候,线程可以自动关闭。
设置守护线程的方法很简单,调用setDaemon方法即可,true代表守护线程,false代表正常线程。线程是否为守护线程跟他的父线程有关系,父线程是正常线程,则子线程也是正常线程,反之亦然。另外,setDaemon方法只在线程启动之前才能生效。