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

本章主要对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.总结
关于多线程优先级的作用,我总认为自己理解不够透彻。如果谁有更好的见解,请多指教,谢谢!

 

posted @ 2021-08-12 15:30  姚春辉  阅读(457)  评论(0编辑  收藏  举报