Java线程学习记录(八)——线程属性

线程属性

线程Id

Id从1开始,JVM运行起来之后,我们自己创建的线程ID早已不是2

public class Id {
    public static void main(String[] args) {
        Thread thread = new Thread();
        System.out.println("主线程的ID:" + Thread.currentThread().getId());
        System.out.println("子线程的ID:" + thread.getId());
    }
}

输出

主线程的ID:1
子线程的ID:11

从输出可以看到主线的Id为1,而我们自己创建的子线程Id为11,这就很奇怪了为什么线程Id不是从0开始,而且为什么我们自己创建的子线程Id就是11了呢。
可以从java的底层代码中看到,这个线程的Id初始值是0,再每一次生成Id的时候都是先自增的,所以起始值是1。

/* For generating thread ID */
    private static long threadSeqNumber;
 	private static synchronized long nextThreadID() {
        return ++threadSeqNumber;
    }

那么为什么我们自己创建的子线程Id是11呢,这个可以从Debug中查看。

在Debug下可以看到,在我们的子线程创建之前就已经有了其他线程创建了。
Signal Dispatcher是把操作系统的信号发给我们适当的程序的。
Reference Handler是和GC相关的引用线程。
Finalizer是负责执行Finalizer对象的方法。
这里其实是要说明,在我们创建自己的主/子线程的时候,JVM已经为我们创建了许多线程。

线程名字

默认名字

可以从java的源码看出,线程的默认名字是一个写死的“Thread-”加一个数字,这个数字是自增的,且加了synchronized 不会出现重复的情况。

public Thread() {
	init(null, null, "Thread-" + nextThreadNum(), 0);
}
    
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
	return threadInitNumber++;
}
手动设置名字

从java的源码中可以看到,首先是一个健康检查,然后底下的setNativeName()是native方法(C/C++层面给线程的名字做一个设置),也就是当线程启动之后,这个名字是不能修改了;但是Java内部的线程名字是可以通过setName()的方式来进行修改名字的。为什么当线程起来之后不能修改,是因为他做了一个!=0(线程的状态)的判断,为0时就是线程还没有启动的时候。

/* Java thread status for tools,
 * initialized to indicate thread 'not yet started'
*/
private volatile int threadStatus = 0;
public final synchronized void setName(String name) {
        checkAccess();
        if (name == null) {
            throw new NullPointerException("name cannot be null");
        }

        this.name = name;
        if (threadStatus != 0) {
            setNativeName(name);
        }
    }

private native void setNativeName(String name);

守护线程

作用: 给用户线程提供服务。
他守护的就是我们用户自己编写的子线程。
用户线程和守护线程分类的标准就是取决于守护线程的特性,就是这个线程是否会组织JVM的停止。
当还有用户线程在执行的时候JVM是不会停止的,如果当前只剩下了守护线程,那么守护线程会随着JVM一起停止。

特性:

  1. 线程类型默认继承自父线程
    我们自己创建的线程就是父线程,这是因为我们的父线程就是用户线程;同理守护线程创建的线程也是继承自己的父线程,也就是守护线程创建的线程还是守护线程。
    如果我们要将用户线程设置为守护线程,是需要人为的为用户线程进行设置
  2. 被谁启动
    通常而言,所有的守护线程都是由JVM启动。在JVM启动的时候有一个非守护线程,那就是main函数。
  3. 不影响 JVM退出
    对于JVM退出的时候,他只看有没有用户线程。
守护线程和普通线程区别
  1. 整体上没有区别(只是代码的任务不一样)
  2. 唯一区别在于JVM的离开(如果是用户线程会影响JVM的退出,守护线程则不会)

我们不需要给线程设设置为守护现场,因为当我们自己的线程在访问某个文件或是执行某个操作的时候,JVM发现就只剩下守护线程了,那JVM会关闭,这时候就会导致数据不一致的情况。

线程优先级

10个级别,默认5
在Java底层有以下三个,最低,默认,最高的等级。

    /**
     * The minimum priority that a thread can have.
     */
    public final static int MIN_PRIORITY = 1;

   /**
     * The default priority that is assigned to a thread.
     */
    public final static int NORM_PRIORITY = 5;

    /**
     * The maximum priority that a thread can have.
     */
    public final static int MAX_PRIORITY = 10;

程序设计不应该依赖于优先级

  1. 不同的操作系统不一样(window是7个,linux优先级有一致)
  2. 优先级会被操作系统改变
    属性总结
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值