Thread构造方法

Thread 构造方法都会调用一个 init() 方法。会发现新创建的每一个线程都会有一个父线程。main 函数 所在的线程是由 JVM 创建的,也就是 main线程 。在 java 程序中所有线程的父线程都是 main 线程。
【注意】:如果在Thread的构造方法中没有显式的指定线程组等属性,则子线程会默认和父线程同属一个 线程组,此外,还有相同的 线程优先级 守护线程daemon 等。

  1. public class Thread implements Runnable {
  2. private void init(ThreadGroup g, Runnable target, String name,
  3. long stackSize, AccessControlContext acc,
  4. boolean inheritThreadLocals) {
  5. if (name == null) {
  6. throw new NullPointerException("name cannot be null");
  7. }
  8. this.name = name;
  9. /** 每一个子线程都有一个父线程 */
  10. Thread parent = currentThread();
  11. SecurityManager security = System.getSecurityManager();
  12. if (g == null) {
  13. if (security != null) {
  14. g = security.getThreadGroup();
  15. }
  16. if (g == null) {
  17. /** 如果没有指定线程组,会默认加入父线程的线程组 */
  18. g = parent.getThreadGroup();
  19. }
  20. }
  21. ......
  22. }
  23. }

Thread与JVM

1.JDK1.7的内存结构图

image.png
虚拟机栈Stack:方法的执行区,存储局部变量(无初始值)。是一种 先进后出结构
堆内存heap:存储 new 实例化对象,基本数据类型初始值为默认值,引用数据类型初始值为null,是一种 完全二叉树结构
方法区:分为 class 区和 static 区

  • class区:类加载 的时候会把相关的 .class字节码文件 加载到class区中
  • static区:**类加载 的时候会把 static关键字 **修饰的东西存入静态区

image.png

2.Thread的stackSize参数

Thread 构造函数中的 stackSize 指的是单个线程占有的栈内存大小。默认为 0,由于单个java进程内存大小是有限制的,其值称为地址空间。

计算公式:**java进程内存大小 = 堆内存大小 + 线程数量 × 虚拟机栈内存**大小
有公式可知:

  • 堆内存一定时,线程数量虚拟机栈内存大小反比:stackSize 值越大,线程内方法调用递归的深度就越深;stackSize 值越小,能够创建的线程数量就越多。
  • 堆内存大小的值属于公式中的 常数

守护线程的概念

守护线程,又称后台线程,具备自动结束生命周期的特性。比如 垃圾回收线程
使用场景:当你希望关闭某些线程,或者退出JVM进程的时候,一些线程可以自动关闭。此时就可以考虑将这些线程设置为守护线程。

  1. public class Thread implements Runnable {
  2. /** 将当前线程设置为守护线程,但是必须在start()方法之前执行才能生效 */
  3. public final void setDaemon(boolean on) {
  4. checkAccess();
  5. if (isAlive()) {
  6. throw new IllegalThreadStateException();
  7. }
  8. daemon = on;
  9. }
  10. /** 判断当前线程是不是守护线程 */
  11. public final boolean isDaemon() {
  12. return daemon;
  13. }
  14. }