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