gpt4 book ai didi

java - 如果在java中线程A先于线程B启动,那么A将在B之前被操作系统调度?

转载 作者:搜寻专家 更新时间:2023-10-31 19:32:14 25 4
gpt4 key购买 nike

我正在阅读《理解 JVM 高级特性和最佳实践》,其中有一段代码解释了 java 中的 happens-before 规则。我无法理解。代码如下:

private int value = 0;
//executed by Thread A
public void setValue(int value){
this.value = value;
}
//executed by Thread B
public void getValue(){
return value;
}

假设在代码中线程A 在线程B 之前启动。我可以理解为我们不知道线程B中getValue()返回的结果,因为它不是线程安全的。但是书上说如果给函数setValue()getValue()加上synchronized关键字,那么就不存在线程安全问题和方法getValue() 将返回正确的值。书中解释说,因为 synchronized 符合 happens-before 规则。所以我通过下面的代码有两个问题。

public class VolatileDemo3 {
private volatile int value = 0;
public static void main(String[] args) {
VolatileDemo3 v = new VolatileDemo3();
Thread A = new Thread(v.new Test1());// Thread A
Thread B = new Thread(v.new Test2());//Thread B
A.start();
B.start();
}
public void setValue(int value){
this.value = value;
}
public int getValue(){
return this.value;
}

public class Test1 implements Runnable {
@Override
public void run() {
setValue(10);
}
}
public class Test2 implements Runnable {
@Override
public void run() {
int v = getValue();
System.out.println(v);
}
}
}
  1. 尽管 A.start()B.start() 之前运行并且值为 volatile,但我们不能确保线程 B 可以打印出10,对吧?因为线程 B 可能首先由 JVM 调度,然后线程 B 将打印 0 而不是 10。
  2. 即使线程A被JVM调度在线程B之前,但我们也不能保证指令this.value = valuereturn this.value 之前由 JVM 执行,因为 JVM 将再次对指令进行排序。我的理解对吗?请帮助我。

最佳答案

“之前发生”的问题不是它导致线程 A 在线程 B 之前设置值。而是尽管线程 A 可能会到达 this.value = value按时间顺序,在线程 B 开始运行 getValue 之前,B 看到的值可能仍然是旧值。

也就是说,在线程环境下,即使两条指令按时间顺序执行,也不意味着一条指令的结果会被另一条指令看到。

如果线程 B 刚好先调用该方法,它总是会得到旧值。但是如果恰好是第二次调用该方法,则不知道它获取的是旧值还是新值。

因此,您必须使用手段来确保“之前发生”规则,然后您知道“之前发生”的结果被“之后发生”看到。

因此,如果 value 是易变的,例如,它确保如果线程 A 在线程 B 之前调用 setValue(),则线程 B 将看到新值.

╔═════════════════════╤════════════════════════╤═════════════════════╗║ Order of operations │ Are we using           │ What value of value ║║                     │ volatile/synchronized? │ will B see?         ║╠═════════════════════╪════════════════════════╪═════════════════════╣║ A runs setValue(10) │ N                      │ Unknown             ║║ B runs getValue()   ├────────────────────────┼─────────────────────╢║                     │ Y                      │ 10                  ║╟─────────────────────┼────────────────────────┼─────────────────────╢║ B runs getValue()   │ N                      │ 0                   ║║ A runs setValue(10) ├────────────────────────┼─────────────────────╢║                     │ Y                      │ 0                   ║╚═════════════════════╧════════════════════════╧═════════════════════╝

关于你的两个问题:

  1. 是的。你不知道他们中的哪一个先得到那个指令。这不仅仅是先调度哪个线程的问题。线程可能运行在不同的 CPU 上,一个 CPU 可能需要长时间的内存获取,另一个只需要很短的内存获取,所以它比另一个慢。此外,可能是为代码准备的机器指令的长度不同。通常,您根本不知道幕后发生了什么,而且 Java 不保证线程运行的顺序。
  2. 在这种特殊情况下不太可能重新安排说明,因为这些方法非常短。同样,您无法判断发生了什么,因为它取决于特定的 JVM、CPU 数量、CPU 类型、调度程序和内存安排——您无法保证。

关于java - 如果在java中线程A先于线程B启动,那么A将在B之前被操作系统调度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39051965/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com