Thread构造方法
Thread 构造方法都会调用一个 init()
方法。会发现新创建的每一个线程都会有一个父线程。main 函数 所在的线程是由 JVM 创建的,也就是 main线程
。在 java 程序中所有线程的父线程都是 main 线程。
【注意】:如果在Thread的构造方法中没有显式的指定线程组等属性,则子线程会默认和父线程同属一个 线程组,此外,还有相同的 线程优先级 和 守护线程daemon 等。
public class Thread implements Runnable {
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name;
/** 每一个子线程都有一个父线程 */
Thread parent = currentThread();
SecurityManager security = System.getSecurityManager();
if (g == null) {
if (security != null) {
g = security.getThreadGroup();
}
if (g == null) {
/** 如果没有指定线程组,会默认加入父线程的线程组 */
g = parent.getThreadGroup();
}
}
......
}
}
Thread与JVM
1.JDK1.7的内存结构图
虚拟机栈Stack:方法的执行区,存储局部变量(无初始值)。是一种 先进后出结构
。
堆内存heap:存储 new 实例化对象,基本数据类型初始值为默认值,引用数据类型初始值为null,是一种 完全二叉树结构
。
方法区:分为 class 区和 static 区
- class区:类加载 的时候会把相关的 .class字节码文件 加载到class区中
- static区:**类加载 的时候会把 static关键字 **修饰的东西存入静态区
2.Thread的stackSize参数
Thread 构造函数中的 stackSize 指的是单个线程占有的栈内存大小。默认为 0,由于单个java进程内存大小是有限制的,其值称为地址空间。
计算公式:**java进程内存大小 = 堆内存大小 + 线程数量 × 虚拟机栈内存**大小
有公式可知:
- 堆内存一定时,
线程数量
和虚拟机栈内存大小
成 反比:stackSize 值越大,线程内方法调用递归的深度就越深;stackSize 值越小,能够创建的线程数量就越多。 - 堆内存大小的值属于公式中的 常数 。
守护线程的概念
守护线程,又称后台线程,具备自动结束生命周期的特性。比如 垃圾回收线程
。
使用场景:当你希望关闭某些线程,或者退出JVM进程的时候,一些线程可以自动关闭。此时就可以考虑将这些线程设置为守护线程。
public class Thread implements Runnable {
/** 将当前线程设置为守护线程,但是必须在start()方法之前执行才能生效 */
public final void setDaemon(boolean on) {
checkAccess();
if (isAlive()) {
throw new IllegalThreadStateException();
}
daemon = on;
}
/** 判断当前线程是不是守护线程 */
public final boolean isDaemon() {
return daemon;
}
}