线程的优先级

在操作系统中,线程可以划分优先级,优先级较高的线程得到的CPU资源较多,也就是CPU优先执行优先级较高的线程对象中的任务。

设置优先级

设置线程优先级有助于帮“线程规划器”确定在下一次选择哪一个线程来优化执行。
设置线程的优先级使用setPriority()方法,此方法在JDK的源代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
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这10个等级,如果小于1或大于10,则JDK抛出异常throw new IllegalArgumentException()。

JDK中使用3个常量来预置定义优先级的值,代码如下:

1
2
3
public final static int MIN_PRIORITY=1;
public final static int NORM_PRIORITY=5;
public final static int MAX_PRIORITY=10;

线程优先级的继承特性

在Java中,线程的优先级具有继承性,比如A线程启动B线程,则B线程的优先级与A是一样的。
代码清单1 线程优先级的继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class PriorityThread extends Thread {
@Override
public void run() {
System.out.println("PriorityThread run priority=" + this.getPriority());
PriorityThread2 thread2 = new PriorityThread2();
thread2.start();
}
}
public class PriorityThread2 extends Thread {
@Override
public void run() {
System.out.println("PriorityThread2 run priority="+this.getPriority());
}
}
public class PriorityRun {
public static void main(String[] args) {
System.out.println("main thread begin priority=" + Thread.currentThread().getPriority());
//Thread.currentThread().setPriority(6);
System.out.println("main thread begin priority=" + Thread.currentThread().getPriority());
PriorityThread thread = new PriorityThread();
thread.start();
}
}

程序运行后效果如图1所示。



图1 优先级被继承

将代码//Thread.currentThread().setPriority(6);前的注释符号去掉,再次运行,显示如图2所示。
程序运行后效果如图1所示。



图2 优先级被更改在继续继承

优先级具有规划性

虽然使用setPriority()方法可以设置线程的优先级,但还没有看到设置优先级所带来的效果。
代码清单2 优先级规划性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public class PanningThread extends Thread {
@Override
public void run() {
long beginTime = System.currentTimeMillis();
long addResult = 0;
for (int j = 0; j < 10; j++) {
for (int i = 0; i < 50000; i++) {
Random random = new Random();
random.nextInt();
addResult = addResult + i;
}
}
long endTime=System.currentTimeMillis();
System.out.println("***** thread 1 use time ="+(endTime-beginTime));
}
}
public class PanningThread2 extends Thread {
@Override
public void run() {
long beginTime = System.currentTimeMillis();
long addResult = 0;
for (int j = 0; j < 10; j++) {
for (int i = 0; i < 50000; i++) {
Random random = new Random();
random.nextInt();
addResult = addResult + i;
}
}
long endTime=System.currentTimeMillis();
System.out.println("***** thread2 use time ="+(endTime-beginTime));
}
}
public class PanningRun {
public static void main(String[] args) {
for(int i=0;i<5;i++){
PanningThread thread1=new PanningThread();
thread1.setPriority(10);
thread1.start();
PanningThread2 thread2=new PanningThread2();
thread1.setPriority(1);
thread2.start();
}
}
}

高优先级的线程相对总数先执行完,如图3所示。



图3 运行结果

从图3中可以发现,高优先级的线程总是大部分先执行完,但不代表高优先级的线程全部执行完。另外,不要以为PanningThread线程先被main线程所调用就会先执行完,出现这些的结果全是因为PanningThread线程的优先级是最高值为10所造成的。当线程优先级的等级差距很大时,谁先执行完和代码的调用顺序无关。为了验证这个结论,继续实验,改变PanningRun方法,代码如下。
代码清单3 修改PanningRun()中优先级

1
2
3
4
5
6
7
8
9
10
11
12
13
public class PanningRun {
public static void main(String[] args) {
for(int i=0;i<5;i++){
PanningThread thread1=new PanningThread();
thread1.setPriority(1);
thread1.start();
PanningThread2 thread2=new PanningThread2();
thread1.setPriority(10);
thread2.start();
}
}
}

大部分的thread2先执行完,也就验证了线程的优先级与代码执行的顺序无关,出现这样的结果是因为PanningThread2的优先级是最高的,说明线程额优先级具有一定的规划性,也就是CPU尽量将执行资源让给优先级比较高的线程。



图4 大部分thread2先执行完

优先级具有随机性

前面案例介绍了线程的优先级较高则优先执行完run()方法中的任务。但这个结果不能说得太肯定,因为线程的优先级还具有“随机性”,也就是优先级较高的线程不一定每一次都先执行完。
代码清单4 随机性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class RandomThread extends Thread {
@Override
public void run() {
long beginTime = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
Random random = new Random();
random.nextInt();
}
long endTime = System.currentTimeMillis();
System.out.println("***** thread 1 use time =" + (endTime - beginTime));
}
}
public class RandomThread2 extends Thread {
@Override
public void run() {
long beginTime = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
Random random = new Random();
random.nextInt();
}
long endTime = System.currentTimeMillis();
System.out.println("***** thread 2 use time =" + (endTime - beginTime));
}
}
public class RandomRun {
public static void main(String[] args) {
for(int i=0;i<5;i++){
RandomThread thread1=new RandomThread();
thread1.setPriority(5);
thread1.start();
RandomThread2 thread2=new RandomThread2();
thread2.setPriority(6);
thread2.start();
}
}
}

执行上面代码6次,结果如下。



图5 运行6次后的结果

不要把线程的优先级与运行结果的顺序作为衡量的标准,优先级较高的线程并不一定每一次都先执行完run()方法中的任务,也就是说,线程优先级与打印的顺序无关,不要将这两者的关系相关联,它们的关系具有不确定性和随机性。

看谁运行得快

相同情况下,不同优先级下,比较运行快慢。
代码清单5 比较运行速度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class CountThreadA extends Thread {
private int count = 0;
public int getCount() {
return count;
}
@Override
public void run() {
while (true) {
count++;
}
}
}
public class CountThreadB extends Thread {
private int count = 0;
public int getCount() {
return count;
}
@Override
public void run() {
while (true) {
count++;
}
}
}
public class CountRun {
public static void main(String[] args) {
try {
CountThreadA a = new CountThreadA();
a.setPriority(Thread.NORM_PRIORITY - 3);
a.start();
CountThreadB b = new CountThreadB();
b.setPriority(Thread.NORM_PRIORITY + 3);
b.start();
Thread.sleep(20000);
a.stop();
b.stop();
System.out.println("a= " + a.getCount());
System.out.println("b= " + b.getCount());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}



图6 优先级高运行得快

Java多线程编程核心技术源代码

Adhere to the original technology to share, your support will encourage me to continue to create!