java线程优先级没有影响

gzjq41n4  于 2021-06-29  发布在  Java
关注(0)|答案(12)|浏览(457)

这是一个关于线程优先级的测试。代码来自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。有关系吗?

chhqkbe1

chhqkbe11#

我相信操作系统可以随意忽略java线程优先级。

q3qa4bjr

q3qa4bjr2#

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

ttygqcqt

ttygqcqt3#

线程优先级是一个提示(可以忽略),这样当你有100%的cpu时,操作系统就知道你想选择一些线程而不是其他线程。线程优先级必须在线程启动之前设置,否则可以忽略它。
在windows上,您必须是管理员才能设置线程优先级。

mepcadol

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线程的数量)。

xcitsw88

xcitsw885#

您必须了解,不同的操作系统处理线程优先级的方式不同。例如,windows使用了一个基于抢占时间片的调度程序,它将更大的时间片提供给高优先级线程,而与其他一些操作系统(非常旧的操作系统)一样,它使用非抢占式调度程序,其中高优先级线程在低优先级线程之前完全执行,除非高优先级线程进入睡眠状态或执行某些io操作等。
这就是为什么不能保证高优先级线程完全执行的原因,它实际上比低优先级线程执行的时间要长,这就是为什么输出是以这种方式排序的。
要了解windows如何处理多线程,请参阅以下链接:
https://docs.microsoft.com/en-us/windows/win32/procthread/multitasking

vtwuwzda

vtwuwzda6#

java线程优先级没有影响
线程优先级是高度特定于操作系统的,在许多操作系统上通常影响很小。优先级有助于对仅在运行队列中的线程进行排序,并且不会改变线程以任何主要方式运行的频率,除非您在每个线程中使用大量cpu。
您的程序看起来使用了大量的cpu,但是除非您的核心数少于线程数,否则通过设置线程优先级,您可能看不到输出顺序的任何变化。如果有一个空闲的cpu,那么即使是低优先级的线程也会被安排运行。
而且,线程永远不会饿死。在这种情况下,即使是优先级较低的线程也有时间经常运行。您应该看到,高优先级线程会被分配时间来更频繁地运行,但这并不意味着低优先级线程会等待它们完成后再运行自己。
即使优先级确实有助于给一个线程提供比其他线程更多的cpu,线程程序也会受到竞争条件的影响,这有助于为它们的执行注入大量的随机性。但是,您应该看到的是,最大优先级线程更有可能抛出其 0 比其他人更频繁地传递信息。如果您将优先级添加到 println() ,这一点应该在多次跑步中变得明显。
同样重要的是要注意 System.out.println(...)synchronized 方法来编写io,这将极大地影响线程之间的交互以及不同线程之间的阻塞。此外, Thread.yield(); 根据操作系统执行线程调度的方式,可以是无操作。
但随机结果(每次运行时都会发生变化):
正确的。线程程序的输出很少是“完美的”,因为根据定义,线程是异步运行的。我们希望输出是随机的,因为我们希望线程彼此独立地并行运行。这就是他们的力量。如果您希望得到一些精确的输出,那么就不应该使用线程。

um6iljoc

um6iljoc7#

高优先级线程在完成之前不会停止低优先级线程。高优先级也不能让事情变得更快,如果它做到了,我们总是把每件事都放在高优先级。低优先级不会让事情变慢,或者我们永远不会使用它。
据我所知,您误解了系统的其余部分应该是空闲的,而只是让最高优先级的线程工作,而系统的其余容量被浪费了。

bgibtngc

bgibtngc8#

有些操作系统没有为线程优先级提供适当的支持。

zysjyyx4

zysjyyx49#

需要考虑以下几点:
线程优先级是有害的,在大多数情况下不应使用它们:http://www.codinghorror.com/blog/2006/08/thread-priorities-are-evil.htmll
你明确地屈服了,这可能使你的测试无效
你检查过生成的字节码了吗?你确定你的 volatile 变量的行为与您期望的一样?易变变量仍可能发生重新排序。

ojsjcaue

ojsjcaue10#

线程优先级只是os任务调度器的一个提示。任务调度器只会尝试将更多的资源分配给具有更高优先级的线程,但是没有明确的保证。
事实上,它不仅与java或jvm相关。大多数非实时操作系统仅以暗示的方式使用线程优先级(托管或非托管)。
jeffatwood在这个主题上有一个很好的帖子:“线程优先级是邪恶的”
问题来了。如果有人在低优先级线程(生产者)上开始使“cond”为真的工作,然后程序的计时是这样的:发出这种旋转的高优先级线程(消费者)得到调度,消费者将使生产者完全饥饿。这是一场经典的比赛。即使有一个明确的睡眠在那里,发出它不允许生产者被安排,因为它在一个较低的优先级。消费者将永远旋转,除非打开一个空闲的cpu,否则生产者将永远不会生产。哎呀!

ogq8wdun

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年。
简而言之,不要依赖线程优先级。

bvjxkvbb

bvjxkvbb12#

线程优先级取决于实现。尤其是在windows中:
当所有线程都在争夺cpu时,线程优先级就没有什么意义了((来源)
《实践中的java并发性》一书也提到
避免使用线程优先级的诱惑,因为它们增加了对平台的依赖性,并可能导致活跃性问题。大多数并发应用程序可以对所有线程使用默认优先级。

相关问题