[英]if thread A start before thread B in java,then A will be scheduled by os before B?
我正在阅读《了解JVM高级功能和最佳实践》,其中有一段代码解释了Java中的先发生后规则。 我不明白。 代码如下:
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()
,则不存在线程安全问题,方法getValue()
将返回正确的值。 本书解释说,因为synchronized
遇到事前发生的规则。 因此,我在下面的代码中有两个问题。
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);
}
}
}
A.start()
在B.start()
之前运行并且value是volatile
,但我们不能确保线程B可以打印出10
,对吗? 因为可以由JVM首先调度线程B,所以线程B将输出0而不是10。 A
安排在线程B
之前,但我们也不能保证指令this.value = value
由JVM在return this.value
之前执行的this.value = value
,因为JVM会再次对指令进行排序。 我理解正确吗? 请帮我。 “之前发生”的问题不是因为它导致线程A在线程B之前设置了值。这是尽管线程A按时间顺序在线程B必须运行getValue
之前按顺序到达了this.value = value
, 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 ║ ╚═════════════════════╧════════════════════════╧═════════════════════╝
关于您的两个问题:
将同步添加到函数setValue/getValue
意味着,要执行该代码段的任何线程都必须首先获取(或等待)该对象的锁。
如果我们假设在线程A调用setValue / getValue之前没有持有任何锁,则线程A将立即获得该锁。 但是,在此期间,如果线程B调用setValue/getValue
,则它必须等待线程A放弃锁才能执行该方法。
但是,如果两个线程都在等待对象的锁定,则我们不能保证操作系统会首先选择哪个线程。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.