这是一个关于线程优先级的测试。代码来自javap.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
...
我使用i3-2350m2c4t cpu和win7 64位jdk7。有关系吗?
12条答案
按热度按时间chhqkbe11#
我相信操作系统可以随意忽略java线程优先级。
q3qa4bjr2#
线程优先级不能保证执行顺序。它在资源有限的时候发挥作用。如果系统由于内存或cpu的限制而运行,那么优先级较高的线程将首先运行。假设您有足够的系统资源(对于一个简单的程序和您发布的系统资源,我会这样假设),那么您将没有任何系统约束。我发现这里有一篇博文(不是我的博文)提供了更多关于它的信息:为什么线程优先级很少重要。
ttygqcqt3#
线程优先级是一个提示(可以忽略),这样当你有100%的cpu时,操作系统就知道你想选择一些线程而不是其他线程。线程优先级必须在线程启动之前设置,否则可以忽略它。
在windows上,您必须是管理员才能设置线程优先级。
mepcadol4#
正如在其他答案中提到的,线程优先级与其说是严格规则的定义,不如说是一种暗示。
也就是说,即使以严格的(er)方式考虑优先级,您的测试设置也不会导致您描述为“预期”的结果。您首先创建5个具有相同低优先级的线程和一个具有高优先级的线程。
您正在使用的cpu(i3)有4个本机线程。因此,即使高优先级意味着线程在不中断的情况下运行(这是不正确的),低优先级线程也将获得3/4的cpu能力(假设没有其他任务在运行)。这个cpu能力分配给5个线程,因此低优先级线程将以43/41/5=3/5倍于高优先级线程的速度运行。高优先级线程完成后,低优先级线程以高优先级线程速度的4/5运行。
在高优先级线程之前启动低优先级线程。因此,他们开始早一点。我希望在大多数系统中,“优先级”不会实现到毫微秒。因此,操作系统将允许一个线程运行“稍微长一点”,直到它切换到另一个线程(以减少切换成本的影响)。因此,结果在很大程度上取决于如何实现切换以及任务有多大。如果任务很小,则可能不会发生任何切换,在您的示例中,所有低优先级线程都首先完成。
这些计算假设高优先级和低优先级的情况被解释为极端情况。事实上,优先级与变量n和m的“in n of m cases prefer this”类似。
你的代码中有一个thread.yield!这将把执行传递给另一个线程。如果您经常这样做,它将导致所有线程获得相同的cpu能力。
因此,我不会期望您在问题中提到的输出,即高优先级线程先完成,然后低优先级线程完成。
事实上:对于thread.yield行,我得到的结果是每个线程获得相同的cpu时间。如果不使用line thread.yield,将计算数量增加10倍,将低优先级线程的数量增加10倍,我会得到一个预期的结果,即高优先级线程提前完成某个因素(这取决于本机cpu线程的数量)。
xcitsw885#
您必须了解,不同的操作系统处理线程优先级的方式不同。例如,windows使用了一个基于抢占时间片的调度程序,它将更大的时间片提供给高优先级线程,而与其他一些操作系统(非常旧的操作系统)一样,它使用非抢占式调度程序,其中高优先级线程在低优先级线程之前完全执行,除非高优先级线程进入睡眠状态或执行某些io操作等。
这就是为什么不能保证高优先级线程完全执行的原因,它实际上比低优先级线程执行的时间要长,这就是为什么输出是以这种方式排序的。
要了解windows如何处理多线程,请参阅以下链接:
https://docs.microsoft.com/en-us/windows/win32/procthread/multitasking
vtwuwzda6#
java线程优先级没有影响
线程优先级是高度特定于操作系统的,在许多操作系统上通常影响很小。优先级有助于对仅在运行队列中的线程进行排序,并且不会改变线程以任何主要方式运行的频率,除非您在每个线程中使用大量cpu。
您的程序看起来使用了大量的cpu,但是除非您的核心数少于线程数,否则通过设置线程优先级,您可能看不到输出顺序的任何变化。如果有一个空闲的cpu,那么即使是低优先级的线程也会被安排运行。
而且,线程永远不会饿死。在这种情况下,即使是优先级较低的线程也有时间经常运行。您应该看到,高优先级线程会被分配时间来更频繁地运行,但这并不意味着低优先级线程会等待它们完成后再运行自己。
即使优先级确实有助于给一个线程提供比其他线程更多的cpu,线程程序也会受到竞争条件的影响,这有助于为它们的执行注入大量的随机性。但是,您应该看到的是,最大优先级线程更有可能抛出其
0
比其他人更频繁地传递信息。如果您将优先级添加到println()
,这一点应该在多次跑步中变得明显。同样重要的是要注意
System.out.println(...)
是synchronized
方法来编写io,这将极大地影响线程之间的交互以及不同线程之间的阻塞。此外,Thread.yield();
根据操作系统执行线程调度的方式,可以是无操作。但随机结果(每次运行时都会发生变化):
正确的。线程程序的输出很少是“完美的”,因为根据定义,线程是异步运行的。我们希望输出是随机的,因为我们希望线程彼此独立地并行运行。这就是他们的力量。如果您希望得到一些精确的输出,那么就不应该使用线程。
um6iljoc7#
高优先级线程在完成之前不会停止低优先级线程。高优先级也不能让事情变得更快,如果它做到了,我们总是把每件事都放在高优先级。低优先级不会让事情变慢,或者我们永远不会使用它。
据我所知,您误解了系统的其余部分应该是空闲的,而只是让最高优先级的线程工作,而系统的其余容量被浪费了。
bgibtngc8#
有些操作系统没有为线程优先级提供适当的支持。
zysjyyx49#
需要考虑以下几点:
线程优先级是有害的,在大多数情况下不应使用它们:http://www.codinghorror.com/blog/2006/08/thread-priorities-are-evil.htmll
你明确地屈服了,这可能使你的测试无效
你检查过生成的字节码了吗?你确定你的
volatile
变量的行为与您期望的一样?易变变量仍可能发生重新排序。ojsjcaue10#
线程优先级只是os任务调度器的一个提示。任务调度器只会尝试将更多的资源分配给具有更高优先级的线程,但是没有明确的保证。
事实上,它不仅与java或jvm相关。大多数非实时操作系统仅以暗示的方式使用线程优先级(托管或非托管)。
jeffatwood在这个主题上有一个很好的帖子:“线程优先级是邪恶的”
问题来了。如果有人在低优先级线程(生产者)上开始使“cond”为真的工作,然后程序的计时是这样的:发出这种旋转的高优先级线程(消费者)得到调度,消费者将使生产者完全饥饿。这是一场经典的比赛。即使有一个明确的睡眠在那里,发出它不允许生产者被安排,因为它在一个较低的优先级。消费者将永远旋转,除非打开一个空闲的cpu,否则生产者将永远不会生产。哎呀!
ogq8wdun11#
让我们保持简单,直奔源头。。。
每个线程都有一个优先级。当存在对处理资源的竞争时,具有较高优先级的线程通常优先于具有较低优先级的线程执行。然而,这样的首选项并不能保证最高优先级的线程总是在运行,并且线程优先级不能用于可靠地实现互斥。
摘自java语言规范(第2版)p.445。
也。。。
尽管java中存在线程优先级,并且许多参考文献指出jvm总是选择一个优先级最高的线程进行调度[52、56、89],但java语言或虚拟机规范目前并不能保证这一点[53、90]。优先级只是对调度程序的提示[127,第227页]。
来自测试并发java组件(博士论文,2005)p。62
参考文献127,第227页(摘自上述摘录)摘自组件软件:超越面向对象编程(c。szyperski),addison-wesley,1998年。
简而言之,不要依赖线程优先级。
bvjxkvbb12#
线程优先级取决于实现。尤其是在windows中:
当所有线程都在争夺cpu时,线程优先级就没有什么意义了((来源)
《实践中的java并发性》一书也提到
避免使用线程优先级的诱惑,因为它们增加了对平台的依赖性,并可能导致活跃性问题。大多数并发应用程序可以对所有线程使用默认优先级。