核心六:线程的各个属性

6、核心六:线程的各个属性

在这里插入图片描述

6.1 ID

线程ID不能修改。从1开始ID自增,JVM运行起来之后,我们自己创建的线程ID早已不是0

public class Id {
    public static void main (String[] args) {
        Thread thread = new Thread();
        System.out.println(Thread.currentThread().getId());//1
        System.out.println(thread.getId());//16
    }
}

调试一下为什么是16:JVM为我们自动创建了很多线程

在这里插入图片描述

源码

/*
* Thread ID
*/
private final long tid;

/* For generating thread ID */
private static long threadSeqNumber;

private static synchronized long nextThreadID() {
    return ++threadSeqNumber;
}

public long getId() {
    return tid;
}

private Thread(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) {
        /* Determine if it's an applet or not */

        /* If there is a security manager, ask the security manager
               what to do. */
        if (security != null) {
            g = security.getThreadGroup();
        }

        /* If the security manager doesn't have a strong opinion
               on the matter, use the parent thread group. */
        if (g == null) {
            g = parent.getThreadGroup();
        }
    }

    /* checkAccess regardless of whether or not threadgroup is
           explicitly passed in. */
    g.checkAccess();

    /*
         * Do we have the required permissions?
         */
    if (security != null) {
        if (isCCLOverridden(getClass())) {
            security.checkPermission(
                SecurityConstants.SUBCLASS_IMPLEMENTATION_PERMISSION);
        }
    }

    g.addUnstarted();

    this.group = g;
    this.daemon = parent.isDaemon();
    this.priority = parent.getPriority();
    if (security == null || isCCLOverridden(parent.getClass()))
        this.contextClassLoader = parent.getContextClassLoader();
    else
        this.contextClassLoader = parent.contextClassLoader;
    this.inheritedAccessControlContext =
        acc != null ? acc : AccessController.getContext();
    this.target = target;
    setPriority(priority);
    if (inheritThreadLocals && parent.inheritableThreadLocals != null)
        this.inheritableThreadLocals =
        ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
    /* Stash the specified stack size in case the VM cares */
    this.stackSize = stackSize;

    /* Set thread ID */
    this.tid = nextThreadID();//重点
}

6.2 名字

名字一旦确定,以后可以改变。但是一旦线程启动起来,我们没有办法修改

源码

private volatile String name;
/* For autonumbering anonymous threads. */
private static int threadInitNumber;

private static synchronized int nextThreadNum() {
    return threadInitNumber++;
}

public final String getName() {
    return name;
}
public Thread() {
    this(null, null, "Thread-" + nextThreadNum(), 0);
}

6.3 守护线程

作用:给用户线程(我们自己编写的线程)提供服务

特性:

  • 线程类型默认继承自父线程(守护线程创建的线程就是守护线程,用户线程创建的线程就是用户线程)
  • 通常所有的守护线程都是被JVM自动启动,不是用户启动的。JVM启动的线程除了main线程是非守护线程,其他都是守护线程
  • 不影响JVM退出。JVM而言,想要退出只看用户线程不看守护线程。比如说,如果所有的用户线程全部退出但还有三个守护线程没有结束,JVM也会自动退出。守护线程直接对JVM说:“老大,你不需要等我退出”

守护线程和普通线程的区别:💟

  • 整体上没有太大的区别。虽然他们名字不同,但是他们都是线程,都在执行代码。只不过他们代码的任务不同。
  • 唯一的区别就是在于是否影响JVM的离开。用户线程会影响,而守护线程不会。
  • 他们的作用也不同:用户线程是执行我们逻辑的,守护线程是服务于我们的

6.4 面试题

守护线程和普通线程的区别

我们是否需要给线程设置为守护线程?

首先不是需不需要而是应不应该。我们不应该将自己的线程设置为守护线程。一旦设置成守护线程会变得非常危险。比如,我们这个线程是用来访问文件的,一旦设置成守护线程,有可能发生线程还在访问文件JVM就关了的现象。导致线程被强行停止,如果线程在改变数据,就会导致数据不一致。我们自己开发过程中没有必要设置为守护线程。因为JVM提供的守护线程已经足够服务于我们了

6.5 线程优先级

10个级别,默认是5。子线程如果没有指定优先级,默认继承父线程的

public static final int MIN_PRIORITY = 1;

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

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

注意:我们的程序设计不应依赖于优先级

  • 不同OS不一样:Java会将优先级映射到OS中的优先级。我们Java优先级是10,但是windowsOS中只有7个
  • 优先级会被OS改变:哪怕程序始终运行在windowsOS中,OS中有一个特定的线程推进器,它会自动执行努力线程不管他的优先级多少。所以,间接的改变了优先级。
  • 线程可能出现被饿死的现象:如果这个线程的优先级设置过低

总结:

在这里插入图片描述

6.6 面试题

什么时候我们需要设置守护线程?

首先不是需不需要而是应不应该。==我们不应该将自己的线程设置为守护线程。==一旦设置成守护线程会变得非常危险。比如,我们这个线程是用来访问文件的,一旦设置成守护线程,有可能发生线程还在访问文件JVM就关了的现象。导致线程被强行停止,如果线程在改变数据,就会导致数据不一致。我们自己开发过程中没有必要设置为守护线程。因为JVM提供的守护线程已经足够服务于我们了

我们应该如何应用线程优先级来帮助程序运行?有哪些禁忌?

我们不应该使用优先级来帮助程序运行

  • 不同OS不一样:Java会将优先级映射到OS中的优先级。我们Java优先级是10,但是windowsOS中只有7个
  • 优先级会被OS改变:哪怕程序始终运行在windowsOS中,OS中有一个特定的线程推进器,它会自动执行努力线程不管他的优先级多少。所以,间接的改变了优先级。
  • 线程可能出现被饿死的现象:如果这个线程的优先级设置过低
  • 16
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值