1.建议为线程取一个名字,这样便于区分
线程默认的名称为Thread-jvm进程中自增的数字
2.自定义线程名称
public class CustomThreadName { private final static String PREFIX = "ALEX-"; public static void main(String[] args) { IntStream.range(0, 4).mapToObj(CustomThreadName::createThread).forEach(Thread::start); } private static Thread createThread(final int intName) { return new Thread(() -> System.out.println(Thread.currentThread().getName()), PREFIX + intName); } }
3.线程启动前还有一次机会对其名称进行修改,一旦线程启动,名称就不能修改了
源码:
public final synchronized void setName(String name) { checkAccess(); this.name = name.toCharArray(); if (threadStatus != 0) { //线程不是new状态,对其的修改不会生效 setNativeName(name); } }
4.线程的父子关系
(1)一个线程的创建肯定由另外一个线程完成的
(2)被创建线程的父线程是创建它的线程
5.如果子线程没有显式的指定Group,那么会默认的归属于父线程所在的线程组
public class ThreadContruction { public static void main(String[] args) { Thread t1 = new Thread("t1"); ThreadGroup group = new ThreadGroup("testGroup"); Thread t2 = new Thread(group, "t2"); ThreadGroup mainThreadGroup = Thread.currentThread().getThreadGroup(); System.out.println("main thread belong group:" + mainThreadGroup.getName()); System.out.println("t1 and main belong the same group:" + (mainThreadGroup == t1.getThreadGroup())); System.out.println("t2 thread group not belong main group:" + (mainThreadGroup == t2.getThreadGroup())); System.out.println("t2 thread group belong main testGroup:" + (group == t2.getThreadGroup())); } }
6.Thread和Stacksize
Stacksize越大则代表着正在线程内方法调用递归的深度就越深,Stacksize越小则代表创建的线程数目越多
7.jvm内存结构
程序计数器:用于存放当前线程接下来将要执行的字节码指令,分支,循环,跳转,异常处理等信息,并且每个线程都拥有独立的程序计数器
java虚拟机栈:线程私有的,jvm运行时创建,每一个线程在创建的时候,jvm都会为其创建对应的虚拟机栈,虚拟机栈的大小可以通过-xss来配置,方法的调用是栈帧被压入和弹出的过程,同等的虚拟机栈如果局部变量表占用内存越小则可被压入的栈帧就会越多,反之则可被压入的栈帧越少,一般将栈帧内存的大小成为宽度,而栈帧的数量则称为虚拟机栈的深度
本地方法栈:就是jvm调用Native修饰的c/c++的方法
堆内存:是jvm中最大的一块内存区域,被所有的线程所共享,java在运行期间创建的对象大多存放在此内存区域,有时也被称为gc堆,是垃圾回收重点照顾的对象
方法区:是被多个线程所共享的内存区域,主要用于存储已经被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据
8.守护线程
作用:一般用于处理一些后台工作,例如垃圾回收等,并且具备自动结束生命周期的特征
创建:调用setDaemon()方法