Java并发09:Thread的基本方法(6)-线程优先级priority相关说明与操作

[超级链接:Java并发学习系列-绪论]

本章主要对Java中Thread类的基本方法进行学习。

1.序言

Thread类作为线程的基类,提供了一系列方法,主要有:

  • Thread.sleep(long):强制线程睡眠一段时间。
  • Thread.activeCount():获取当前程序中存活的线程数。
  • thread.start():启动一个线程。
  • Thread.currentThread():获取当前正在运行的线程。
  • thread.getThreadGroup():获取线程所在线程组。
  • thread.getName():获取线程的名字。
  • thread.getPriority():获取线程的优先级。
  • thread.setName(name):设置线程的名字。
  • thread.setPriority(priority):设置线程的优先级。
  • thread.isAlive():判断线程是否还存活着。
  • thread.isDaemon():判断线程是否是守护线程。
  • thread.setDaemon(true):将指定线程设置为守护线程。
  • thread.join():在当前线程中加入指定线程,使得这个指定线程等待当前线程,并在当前线程结束前结束。
  • thread.yield():使得当前线程退让出CPU资源,把CPU调度机会分配给同样线程优先级的线程。
  • thread.interrupt():使得指定线程中断阻塞状态,并将阻塞标志位置为true。
  • object.wai()、object.notify()、object.notifyAll():Object类提供的线程等待和线程唤醒方法。

为了便于阅读,将以上所有方法,放在5篇文章中进行学习。

本章主要学习绿色字体标记的方法,其他方法请参加其他章节。

2.线程优先级简介

直接看Thread中的源码:

/**
 * 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;

/**
 * Returns this thread's priority.
 */
public final int getPriority() {
    return priority;
}

/**
 * Changes the priority of this thread.
 * ...
 * @param newPriority priority to set this thread to
 * @exception  IllegalArgumentException  If the priority is not in the
 *               range <code>MIN_PRIORITY</code> to
 *               <code>MAX_PRIORITY</code>.
 * ...
 */
public final void setPriority(int newPriority) {
    ThreadGroup g;
    checkAccess();
    if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
        throw new IllegalArgumentException();
    }
    if((g = getThreadGroup()) != null) {
        if (newPriority > g.getMaxPriority()) {
            newPriority = g.getMaxPriority();
        }
        setPriority0(priority = newPriority);
    }
}

总结:

  • java多线程的优先级范围:[1~10]
  • 通过thread.setPriority(int)设置线程的优先级时,超出[1~10]的范围,会抛出一个IllegalArgumentException异常。
  • 最大的线程优先级为Thread.MAX_PRIORITY = 10。
  • 最小的线程优先级为Thread.MIN_PRIORITY = 1。
  • 默认的线程优先级为Thread.NORM_PRIORITY = 5。
  • 通过thread.getPriority()、thread.setPriority()分别能够获取和设置线程的优先级。
  • 线程的优先级具有继承传递性。子线程的优先级与父线程优先级一致。
  • 虽然线程优先级有10个级别,但是推荐只使用内置的三个等级。

3.实例代码与结果分析

那优先级的作用是什么呢?很多人以为:高优先级的线程会一定最先启动,高优先级的线程一定会最先运行完。
其实我也一直很困惑,然后我就查了查JDK的源码注释,看到下面一段话:

/**
 * ...
 * <p>
 * Every thread has a priority. Threads with higher priority are
 * executed in preference to threads with lower priority. Each thread
 * may or may not also be marked as a daemon. When code running in
 * some thread creates a new <code>Thread</code> object, the new
 * thread has its priority initially set equal to the priority of the
 * creating thread, and is a daemon thread if and only if the
 * creating thread is a daemon.
 * <p>
 * ...
 * @since   JDK1.0
 */
public
class Thread implements Runnable {...}

这段话翻译过来就是:

  • 每个线程都有一个优先级。
  • 优先级较高的线程比优先级低的线程优先执行
  • 每个线程可能会与可能不会被标记为守护线程。
  • 当运行中的某个线程,创建了一个新的线程时,这个新线程的初识优先级与创建它的线程一致。

综合上面的注释,我认为线程的优先级的作用如下:

  • 在同一时刻,优先级高的线程优先启动。
  • 在多线程运行中,优先级高的线程能得到更多的计算资源。
  • 优先级高的线程并不一定最先运行结束,这取决于这个线程所处理的内容。
  • 优先级低的线程并不是非要等到优先级高的线程运行完再运行,因为多线程本来指的就是线程之间的来回切换与调度。

3.1.实例代码与运行结果

下面编写代码验证一下:

线程类:

static class SleepThread extends Thread {
    /**
     * <p>重写Thread类的构造器,用以给线程命名</br>
     * 此种方式无需定义name变量以指定线程名,因为父类Thread中已有。</p>
     * @author hanchao 2018/3/8 22:59
     **/
    public SleepThread(String name) {
        super(name);
    }

    /**
     * <p>业务代码写在run()方法中,此方法无返回值</p>
     * @author hanchao 2018/3/8 22:55
     **/
    @Override
    public void run(){
        Integer interval = RandomUtils.nextInt(100000,2000000);
        System.out.println(System.nanoTime() + " : 线程[" + super.getName() + "]正在运行,预计运行" + interval + "...");
        try {
            Thread.sleep(interval);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            System.out.println(System.nanoTime() + " : 线程[" + super.getName() + "]运行结束");
        }
    }
}

测试方法:

int num = 9;
Thread[] threads = new Thread[num];
//优先级与线程的执行顺序
//注意多核CPU与单核CPU
for (int i = 0; i < num; i++) {
    //部分线程设置为高级线程
    if ( i < (num / 3)){
        threads[i] = new SleepThread("高优先级线程-" + i);
        threads[i].setPriority(Thread.MAX_PRIORITY);
    }else if(i >= (num / 3) && i < (num / 3) * 2){//部分线程设置为中级线程
        threads[i] = new SleepThread("中优先级线程-" + i);
        threads[i].setPriority(Thread.NORM_PRIORITY);
    }else{//其余线程设置为低级线程
        threads[i] = new SleepThread("低优先级线程-" + i);
        threads[i].setPriority(Thread.MIN_PRIORITY);
    }
}
//统一运行线程
for(int i = 0; i < num; i++) {
    threads[i].start();
}
System.out.println("=====================================");

结果分析:

=====================================
8848521183215 : 线程[高优先级线程-2]正在运行,预计运行327224...
8848521300084 : 线程[高优先级线程-0]正在运行,预计运行281455...
8848521177918 : 线程[高优先级线程-1]正在运行,预计运行252035...
8848522412158 : 线程[中优先级线程-4]正在运行,预计运行474837...
8848521330211 : 线程[中优先级线程-3]正在运行,预计运行442771...
8848523015705 : 线程[中优先级线程-5]正在运行,预计运行310583...
8848524692921 : 线程[低优先级线程-6]正在运行,预计运行457768...
8848530180789 : 线程[低优先级线程-7]正在运行,预计运行152680...
8848530739971 : 线程[低优先级线程-8]正在运行,预计运行338034...
9001210393973 : 线程[低优先级线程-7]运行结束
9100557081471 : 线程[高优先级线程-1]运行结束
9129977265872 : 线程[高优先级线程-0]运行结束
9159106026490 : 线程[中优先级线程-5]运行结束
9175745463719 : 线程[高优先级线程-2]运行结束
9186564876256 : 线程[低优先级线程-8]运行结束
9291293550927 : 线程[中优先级线程-3]运行结束
9306292909308 : 线程[低优先级线程-6]运行结束
9323360172767 : 线程[中优先级线程-4]运行结束

这个结果显示:高优先级的线程会优先运行,但是高优先级的线程未必会最先运行完。

3.3.其他结果

其实,在验证线程优先级作用的过程中,产生过各种各样的结果,很多结果看起来与优先级的作用相违背。产生这些结果可能的原因有:

  • 运行日志无法完美展示JVM的运行过程,写日志也会消耗资源。
  • 多核处理器的影响。在多核处理器上运行多线程,不仅会产生并发效果,也会产生并行效果。
  • 线程进入JVM的时间不同。JVM并不是在同一时刻启动所有的线程,线程本身的启动也有先后顺序。

4.总结

关于多线程优先级的作用,我总认为自己理解不够透彻。如果谁有更好的见解,请多指教,谢谢!

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值