Java线程优先级对线程调度的影响
- 基本原理:
- 在Java中,线程的优先级是一个整数,范围从1(
Thread.MIN_PRIORITY
)到10(Thread.MAX_PRIORITY
),默认优先级为5(Thread.NORM_PRIORITY
)。
- 线程调度器倾向于优先调度优先级较高的线程。当有多个线程处于可运行状态时,调度器会优先选择优先级高的线程来执行。
- 然而,线程调度器是基于操作系统的,不同操作系统对线程优先级的支持和实现可能有所不同。例如,在某些操作系统中,可能只有少数几个优先级级别,而不是完全按照Java定义的1 - 10级来实现。
- 调度策略:
- 常见的调度策略有两种:抢占式调度和时间片轮转调度。在抢占式调度中,如果一个高优先级的线程进入可运行状态,它可能会抢占正在运行的低优先级线程的CPU资源,使低优先级线程暂停执行,直到高优先级线程执行完毕或进入等待状态。在时间片轮转调度中,每个线程被分配一个时间片来执行,当时间片用完后,即使线程没有执行完,也会被暂停,调度器会选择另一个可运行的线程执行。高优先级线程通常会获得更长的时间片或更频繁的调度机会。
线程优先级设置的局限性
- 操作系统依赖:
- 如前文所述,Java线程优先级的实现依赖于底层操作系统。不同操作系统对线程优先级的映射和处理方式不同,这使得在Java中设置的优先级在不同操作系统上可能有不同的表现。例如,在Windows系统和Linux系统上,同样的Java线程优先级设置可能导致不同的调度结果。
- 不确定性:
- 即使设置了线程优先级,也不能保证高优先级线程一定会先于低优先级线程执行。线程调度器的行为是不确定的,可能会受到系统负载、其他进程活动等多种因素的影响。例如,在一个负载很高的系统中,即使高优先级线程不断请求CPU资源,也可能因为其他进程占用大量系统资源而无法及时得到调度。
- 优先级反转:
- 当一个高优先级线程等待一个低优先级线程释放锁时,就会发生优先级反转。在这种情况下,高优先级线程会被阻塞,而低优先级线程却可以继续执行,导致高优先级线程无法按照预期优先执行。例如,低优先级线程T1持有锁,高优先级线程T2需要获取该锁才能继续执行,此时T2就会被阻塞,直到T1释放锁,这期间T1可能会因为其他任务而长时间占用CPU,使得T2长时间无法执行。
设置线程优先级达不到预期效果的情况举例
- 系统负载过高:
- 假设有两个线程,线程A优先级为8,线程B优先级为5。在一个系统负载很高的环境中,大量其他进程和线程在竞争CPU资源。尽管线程A优先级较高,但由于系统资源紧张,可能出现线程B和线程A交替执行,甚至线程B执行时间比线程A还长的情况。因为系统调度器需要平衡所有活动线程和进程的资源分配,不能仅仅根据线程优先级来调度。
- 优先级反转:
public class PriorityInversionExample {
private static final Object lock = new Object();
public static void main(String[] args) {
Thread lowPriorityThread = new Thread(() -> {
synchronized (lock) {
System.out.println("Low priority thread acquired lock.");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Low priority thread released lock.");
}
});
lowPriorityThread.setPriority(Thread.MIN_PRIORITY);
Thread highPriorityThread = new Thread(() -> {
synchronized (lock) {
System.out.println("High priority thread acquired lock.");
}
});
highPriorityThread.setPriority(Thread.MAX_PRIORITY);
lowPriorityThread.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
highPriorityThread.start();
}
}
- 在上述代码中,低优先级线程
lowPriorityThread
先获取锁并睡眠10秒,在这期间高优先级线程highPriorityThread
需要获取锁但被阻塞,尽管highPriorityThread
优先级高,却无法执行,直到lowPriorityThread
释放锁,这就体现了优先级反转导致设置优先级达不到预期效果。