六. 线程属性

本文详细介绍了Java线程的主要属性,包括线程ID的唯一性,线程名称的设定及其作用,守护线程的概念以及如何设置,以及线程优先级的工作原理和在不同操作系统中的差异。强调了不应依赖线程优先级来保证程序执行顺序,并指出守护线程适用于服务其他线程且非必要运行的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

六. 线程属性

线程各属性纵览

在这里插入图片描述

ID

每次程序运行唯一、自增、不可被修改

代码

    public static void main(String[] args) throws IOException {
        Thread main = Thread.currentThread();
        System.out.println(main.getName() + ">>" + Thread.currentThread().getId());
        new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ">>" + Thread.currentThread().getId());
        },
                "println").start();
        System.in.read();
    }
	//java.lang.Thread#nextThreadID
	//全局自增,因为是++所以从1开始
    private static synchronized long nextThreadID() {
        return ++threadSeqNumber;
    }

println睡眠时

在这里插入图片描述

printlln关闭后
在这里插入图片描述

在这里插入图片描述

可以看到除了VM线程,只剩下11个了,这些线程除main外都是是JVM启动时创建的,用于GC,代码编译,finalizer方法执行等等处理.

name

用于更清晰的判断线程的功能(给程序员和用户使用,使得在开发和调试过程中,更容易分辨线程的功能),JVM并不限制存在相同名称的线程.

    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }
    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize) {
        init(g, target, name, stackSize, null, true);
    }
    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;
        ...
    }
    public final String getName() {
        return name;
    }

可以看到默认情况下是通过"Thread-"加上当前线程ID.

如果自定义线程名称,通过set方法,当status!=0也就是运行起来后,还会通过native方法给运行的线程名称更新值.

	//java.lang.Thread#setName    
	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);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "sleep");
        System.out.println(thread.getName());
        thread.start();
        TimeUnit.SECONDS.sleep(5);
        thread.setName("sleep+0");
        System.out.println(thread.getName());
    }
sleep
sleep+0

daemon

给用户线程(默认new thread)提供服务,当系统中只存在守护线程时,JVM会直接关闭守护线程并退出.

在线程start前,可以通过thread.setDaemon设置

    /* Whether or not the thread is a daemon thread. */
    private boolean     daemon = false;   
/*
   	Marks this thread as either a daemon thread or a user thread. The Java Virtual Machine 		exits when the only threads running are all daemon threads.
	This method must be invoked before the thread is started.
   */
    public final void setDaemon(boolean on) {
        checkAccess();
        if (isAlive()) {
            throw new IllegalThreadStateException();
        }
        daemon = on;
    }
	public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+">>"+LocalTime.now());
        },"sleep");
        thread.setDaemon(true);
        System.out.println(Thread.currentThread().getName()+">>"+LocalTime.now());
        thread.start();
        TimeUnit.SECONDS.sleep(5);
        System.out.println(Thread.currentThread().getName()+">>"+LocalTime.now());
    }

thread.setDaemon(true);

main>>20:47:30.435
main>>20:47:35.442

thread.setDaemon(false);//默认为false

main>>20:48:07.395
main>>20:48:12.397
sleep>>20:48:17.402

程序启动自带的一些线程都是守护线程,用于给main线程和之后new的daemon为false的线程提供服务.

  //java.lang.ref.Reference
	static {
        ThreadGroup tg = Thread.currentThread().getThreadGroup();
        for (ThreadGroup tgn = tg;
             tgn != null;
             tg = tgn, tgn = tg.getParent());
        Thread handler = new ReferenceHandler(tg, "Reference Handler");
        /* If there were a special system-only priority greater than
         * MAX_PRIORITY, it would be used here
         */
        handler.setPriority(Thread.MAX_PRIORITY);
        //守护线程
        handler.setDaemon(true);
        handler.start();

        // provide access in SharedSecrets
        SharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() {
            @Override
            public boolean tryHandlePendingReference() {
                return tryHandlePending(false);
            }
        });
    }
	//java.lang.ref.Finalizer
    static {
        ThreadGroup tg = Thread.currentThread().getThreadGroup();
        for (ThreadGroup tgn = tg;
             tgn != null;
             tg = tgn, tgn = tg.getParent());
        Thread finalizer = new FinalizerThread(tg);
        finalizer.setPriority(Thread.MAX_PRIORITY - 2);
         //守护线程
        finalizer.setDaemon(true);
        finalizer.start();
    }

在这里插入图片描述

在这里插入图片描述

守护线程创建的线程默认就是守护线程

java.lang.Thread#init(java.lang.ThreadGroup, java.lang.Runnable, java.lang.String, long, java.security.AccessControlContext, boolean){
    ...
    		Thread parent = currentThread();
    ...
            this.daemon = parent.isDaemon();
    ...
}

priority

作用:希望某个线程多运行

默认为5,如果存在父线程,跟随父线程.

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

	java.lang.Thread#init(java.lang.ThreadGroup, java.lang.Runnable, java.lang.String, long, java.security.AccessControlContext, boolean){
	...
        this.priority = parent.getPriority();
    ...
    }

程序的设置不应该依赖优先级

因为不同的OS优先级不一样

java中有10个优先级

windows只有7个优先级

linux会忽略,所有线程优先级都是一样的

Solaris有2的32次方个优先级.

这样,优先级的设置就是不可靠的,依赖于优先级的程序也将是不可靠的

优先级会被OS改变

哪怕一直运行在一个OS中,优先级也可能被OS修改.

例如在Windows中有个优先级推进器的功能,当它发现某个线程特别想执行时,会越过优先级的设置去为这个线程分配时间片

问题

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

应用程序一般不需要设置守护线程.只有当这个线程属于服务于其它线程,且是否运行完毕都无所谓的情况下,才设置为守护线程

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

不应该通过优先级帮助程序运行,因为不同的OS对优先级处理方式不同

不同的操作系统如何处理优先级问题?

java中有10个优先级

windows只有7个优先级

linux会忽略,所有线程优先级都是一样的

Solaris有2的32次方个优先级.

这样,优先级的设置就是不可靠的,依赖于优先级的程序也将是不可靠的

优先级会被OS改变

哪怕一直运行在一个OS中,优先级也可能被OS修改.

例如在Windows中有个优先级推进器的功能,大致作用是当系统发现一个线程执行的特别频繁时,可能会越过线程优先级去为它分配执行时间,从而减少因为线程频繁切换而带来的性能损耗。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值