每个线程都具有各自的优先级,线程的优先级可以表明该线程在程序中的重要性,如果有很多线程处于就绪状态,那么系统会根据优先级来决定首先使哪个线程进入运行状态。但这并不意味着低优先级的线程得不到运行,而只是它运行的概率比较小,如垃圾回收线程的优先级就较低。
Thread 类中包含的成员变量代表了线程的某些优先级,比如:
Thread.MIN_PRIORITY(常数 1);
Thread.MAX_PRIORITY(常数 10);
Thread.NORM_PRIORITY(常数 5)。
其中,每个线程的优先级都在 Thread.MIN_PRIORITY~Thread.MAX_PRIORITY,在默认情况下其优先级都是 Thread.NORM_ PRIORITY。每个新产生的线程都继承了父线程的优先级。
在多任务操作系统中,每个线程都会得到一小段 CPU 时间片运行,在时间结束时,将轮换另一个线程进入运行状态,这时系统会选择与当前线程优先级相同的线程予以运行。系统始终选择就绪状态下优先级较高的线程进入运行状态。
处于各个优先级状态下的线程的运行顺序如下图所示:
图 1 处于各个优先级状态下的线程的运行顺序
在图 1 中,优先级为 5 的线程 A 首先得到 CPU 时间片;当该时间结束后,轮换到与线程 A 相同优先级的线程 B;当线程 B 的运行时间结束后,会继续轮换到线程 A,直到线程 A 与线程 B 都执行完毕,才会轮换到线程 C;当线程 C 结束后,才会轮换到线程 D。
线程的优先级可以使用 setPriority() 方法进行调整,如果使用该方法设置的优先级不是 1~10,则将产生 IllegalArgumentException 异常。
【实例】创建 PriorityTest 类并实现 Runnable 接口,在 run() 方法中执行 5 万次字符串拼接。在主方法中以 PriorityTest 对象为参数创建 4 个线程,并分配不同的优先级,然后启动这些线程。
public class PriorityTest implements Runnable {
String name;
public PriorityTest(String name) {
this.name = name;
}
@Override
public void run() {
String tmp = "";
for (int i = 0; i < 50000; i++) {
tmp += i; //完成5万次字符串拼接
}
System.out.println(name + "线程完成任务");
}
public static void main(String[] args) {
Thread a = new Thread(new PriorityTest("A"));
a.setPriority(1); //A线程优先级最小
Thread b = new Thread(new PriorityTest("B"));
b.setPriority(3);
Thread c = new Thread(new PriorityTest("C"));
c.setPriority(7);
Thread d = new Thread(new PriorityTest("D"));
d.setPriority(10); //D线程优先级最大
a.start();
b.start();
c.start();
d.start();
}
}
由于线程的执行顺序是由 CPU 决定的,即使线程设定了优先级也是作为 CPU 的参考数据,因此真实的运行结果可能并不一定按照优先级排序,例如笔者运行的结果如下:
D线程完成任务
B线程完成任务
C线程完成任务
A线程完成任务
从这个结果中可以看出,优先级最大的 D 线程是第一个完成的,优先级最小的 A 线程是最后一个完成的。但是,C 线程的优先级比B线程大,却仍然在 B 线程之后才完成,这是 CPU 的真实运行结果。