Java线程优先级不起作用

这是一个关于线程优先级的testing。 代码来自Thinking in Java p.809

import java.util.concurrent.*; public class SimplePriorities implements Runnable { private int countDown = 5; private volatile double d; // No optimization private int priority; public SimplePriorities(int priority) { this.priority = priority; } public String toString() { return Thread.currentThread() + ": " + countDown; } public void run() { Thread.currentThread().setPriority(priority); while (true) { // An expensive, interruptable operation: for (int i = 1; i < 10000000; i++) { d += (Math.PI + Math.E) / (double) i; if (i % 1000 == 0) Thread.yield(); } System.out.println(this); if (--countDown == 0) return; } } public static void main(String[] args) { ExecutorService exec = Executors.newCachedThreadPool(); for (int i = 0; i < 5; i++) exec.execute(new SimplePriorities(Thread.MIN_PRIORITY)); exec.execute(new SimplePriorities(Thread.MAX_PRIORITY)); exec.shutdown(); } } 

我想知道为什么我不能得到一个正常的结果,如:

 Thread[pool-1-thread-6,10,main]: 5 Thread[pool-1-thread-6,10,main]: 4 Thread[pool-1-thread-6,10,main]: 3 Thread[pool-1-thread-6,10,main]: 2 Thread[pool-1-thread-6,10,main]: 1 Thread[pool-1-thread-3,1,main]: 5 Thread[pool-1-thread-2,1,main]: 5 Thread[pool-1-thread-1,1,main]: 5 Thread[pool-1-thread-5,1,main]: 5 Thread[pool-1-thread-4,1,main]: 5 ... 

但随机的结果(每次我运行它的变化):

 Thread[pool-1-thread-2,1,main]: 5 Thread[pool-1-thread-3,1,main]: 5 Thread[pool-1-thread-4,1,main]: 5 Thread[pool-1-thread-2,1,main]: 4 Thread[pool-1-thread-3,1,main]: 4 Thread[pool-1-thread-1,1,main]: 5 Thread[pool-1-thread-6,10,main]: 5 Thread[pool-1-thread-5,1,main]: 5 ... 

我用Win 7 64位JDK 7使用i3-2350M 2C4T CPU。这有什么关系吗?

Java线程优先级不起作用

线程优先级在大多数操作系统上都能正常工作,但是通常影响很小。 优先级有助于对运行队列中的线程进行sorting,并且不会更改线程在任何主要线程中运行的频率,除非在每个线程中执行大量的CPU。

你的程序看起来使用了大量的CPU,但是除非你有比线程更less的内核,否则通过设置你的线程优先级,你可能看不到输出顺序的任何改变。 如果有一个空闲的CPU,那么即使是一个较低优先级的线程也将被安排运行。

另外,线程永远不会饿死。 即使是较低优先级的线程也会在这种情况下经常运行。 你应该看到更高优先级的线程被赋予时间片更频繁的运行,但并不意味着更低优先级的线程将等待它们在运行之前完成。

即使优先级确实有助于为一个线程提供比其他线程更多的CPU,线程化程序也会受到竞争条件的影响 ,从而有助于为执行注入大量的随机性。 然而,你应该看到的是,最高优先级的线程比其他的更容易吐出它的0消息。 如果您将优先级添加到println() ,那么在多次运行中应该会显而易见。

注意到System.out.println(...)是一个正在写入IO的synchronized方法,这将极大地影响线程如何交互以及不同的线程彼此阻塞,这也是很重要的。 另外, Thread.yield(); 可以是一个无操作,取决于操作系统如何进行线程调度。

但随机的结果(每次我运行它的变化):

对。 线程程序的输出很less,如果是“完美的”,因为根据定义,线程是asynchronous运行的。 我们希望输出是随机的,因为我们希望线程彼此独立并行运行。 这是他们的力量。 如果你期待一些精确的输出,那么你不应该使用线程。

线程优先级取决于实现。 特别是在Windows中:

当所有线程都竞争CPU时,线程优先级并不是很有意义。 ( 来源 )

“Java实践中的并发”一书也表示

避免使用线程优先级的诱惑,因为它们增加了平台依赖性,并可能导致活跃性问题。 大多数并发应用程序可以使用所有线程的默认优先级。

线程优先级不保证执行顺序。 它在资源有限的情况下发挥作用。 如果系统由于内存或CPU而遇到约束,则优先级较高的线程将首先运行。 假设你有足够的系统资源(我假设你是为了一个简单的程序和你发布的系统资源),那么你将不会有任何系统的限制。 这里是一篇博文(不是我的文章),我发现它提供了更多关于它的信息: 为什么线程优先级很重要 。

让我们保持简单,直接去源…

每个线程都有优先权。 当竞争处理资源时,优先级较高的线程通常优先于较低优先级的线程执行。 然而,这种优先select并不是保证最高优先级的线程总是运行 ,并且不能使用线程优先级来可靠地实现互斥。

  • Java语言规范(第二版)第 445页。

还…

尽pipeJava中存在线程优先级,许多引用声明JVM将始终select最高优先级的线程之一进行调度[52,56,89],但目前Java语言或虚拟机规范并不能保证这一点[53,90] 。 优先级只是调度器的提示 [127,第227页]。

  • testing并发Java组件(PhD Thesis,2005) p。 62。

  • (摘自上面的摘录)来自1998年Addison Wesley的Component Software:Beyond Object-Oriented Programming(by C. Szyperski)。

总之, 不要依赖线程的优先级

线程优先级只是OS任务调度器的一个提示。 任务调度程序只会尝试为更高优先级的线程分配更多的资源,但是没有明确的保证。

实际上,它不仅与Java或JVM有关。 大多数非实时操作系统只是以暗示的方式使用线程优先级(托pipe或非托pipe)。

杰夫·阿特伍德在这个话题上有一个很好的post:“ 线程优先级是邪恶的 ”

这是问题。 如果有人开始在较低优先级的线程(生产者)上使'cond'为真的工作,然后程序的时间是这样的,发出这个旋转(消费者)的更高优先级的线程被调度,消费者将完全扼杀制片人。 这是一场经典的比赛。 即使有一个明确的睡眠在那里,发出它不允许生产者被安排,因为它在一个较低的优先级。 消费者将永远旋转,除非有一个免费的CPU打开,生产者将永远不会生产。 哎呀!

正如其他答案中所提到的,线程优先级比严格规则的定义更重要。

这就是说,即使优先考虑严格(呃),你的testing设置也不会导致你所描述的结果是“预期的”。 您将首先创build5个具有同等优先级的线程和一个具有高优先级的线程。

  • 你使用的CPU(i3)有4个本地线程。 因此,即使高优先级暗示线程运行没有中断(这是不正确的),低优先级的线程将获得3/4的CPU功率(鉴于没有其他任务正在运行)。 这个CPU能力被分配给5个线程,因此低优先级线程将以高优先级线程的速度的4 * 3/4 * 1/5 = 3/5运行。 高优先级线程完成后,低优先级线程以高优先级线程速度的4/5运行。

  • 您将在高优先级线程之前启动低优先级线程。 因此他们早一点开始。 我预计在大多数系统中,“优先级”不会落实到纳秒级。 所以操作系统将允许一个线程运行“更长一点”,直到它切换到另一个线程(以减less切换成本的影响)。 因此,结果很大程度上取决于如何实现这种转换以及这个任务有多大。 如果任务很小,则可能不会发生切换,在您的示例中,所有低优先级的线程都会先完成。

  • 这些计算假设解释为极端情况下的优先级和低优先级。 事实上,优先事项就像是“在n个案例中更喜欢这个”,variables为n和m。

  • 你的代码中有一个Thread.yield! 这会将执行传递给另一个线程。 如果你经常这样做,将导致所有线程获得相同的CPU功率。

因此,我不希望你的问题中提到的输出,即高优先级的线程先完成,然后低优先级的线程完成。

事实上:线程Thread.yield我有每个线程得到相同的CPU时间的结果。 如果没有Thread.yield行,并且将计算次数增加10倍,并且将低级prio线程的数量增加10倍,那么我会得到一个预期的结果,即高级prio线程以一个因子取决于本地CPU线程的数量)。

我相信操作系统可以自由地忽略Java线程的优先级。

线程优先级是一个提示(可以忽略),当你有100%的CPU时,操作系统知道你想要一些线程优于其他线程。 线程优先级必须在线程启动之前设置,否则可以忽略。

在Windows上,您必须是pipe理员才能设置线程优先级。

几件事情要考虑:

  • 线程的优先级是邪恶的,在大多数情况下,他们不应该使用: http : //www.codinghorror.com/blog/2006/08/thread-priorities-are-evil.htmll

  • 你明确地屈服,这可能会使你的testing失效

  • 你有没有检查生成的字节码? 你确定你的volatilevariables是否按照你的预期行事? 对于易失性variables,重新sorting仍然可能发生 。

某些操作系统不能为线程优先级提供适当的支持。