在below code listings
中,Statement 1和Statement 2线程是否安全?他们正在使用VolatileIntWrapper
。
如果它们不是线程安全的,哪些语句需要包装在synchronized块中?
public class Demo {
public static void main(String[] args) {
VolatileIntWrapper volatileIntWrapper = new VolatileIntWrapper() ;
for(int i = 1 ; i <= 5 ; ++i){
new ModifyWrapperIntValue(volatileIntWrapper).start() ;
}
}
}
class VolatileIntWrapper{
public volatile int value = 0 ;
}
class ModifyWrapperIntValue extends Thread{
private VolatileIntWrapper wrapper ;
private int counter = 0 ;
public ModifyWrapperIntValue(VolatileIntWrapper viw) {
this.wrapper = viw ;
}
@Override
public void run() {
//randomly increments or decrements VolatileIntWrapper primitive int value
//we can use below statement also, if value in VolatileIntWrapper is private
// wrapper.getValue() instead of wrapper.value
//but, as per my understanding, it will add more complexity to logic(might be requires additional synchronized statements),
//so, for simplicity, we declared it public
//Statement 1
while(wrapper.value > -1500 && wrapper.value < 1500){
++counter ;
int randomValue = (int) (Math.random() * 2) ;
//Statement 2
wrapper.value += (randomValue == 0) ? 1 : -1 ;
}
System.out.println("Executed " + counter + " times...");
}
}
答案 0 :(得分:4)
volatile
keyword为读取和写入字段提供了内存屏障。这意味着多个线程可以访问该字段并保证读取最新值,并保证其他线程可以看到它们的写入。
不所做的volatile
提供了围绕操作顺序的任何保证 - 尤其是当您有多个读写语句时。在您的代码中,您正在访问循环中的几个位置volatile int
:
while(wrapper.value > -1500 && wrapper.value < 1500){
...
wrapper.value += (randomValue == 0) ? 1 : -1 ;
}
此处无法保证操作顺序。在线程A测试value > -1500
之后,另一个线程可能会在线程A可以测试value < 1500
之前将其更改为。或者线程A可以执行两个测试,然后线程B可以执行两个测试,然后线程A将分配值,然后线程B将分配值。这就是multithreading race conditions的性质。
while
循环是我怀疑会被视为有错误的代码部分,除非您同步它。您应该执行以下操作。在同步该部分后,synchronized
关键字会提供内存屏障,因此不需要volatile
关键字。
synchronized (wrapper) {
while (...) {
...
}
}
答案 1 :(得分:2)
使用一次且仅一次的易失性场是安全的。 (读取和写入计为两次)
您正在使用该字段共四次,因此您有三个竞争条件的位置。
这个例子的问题是单线程执行起来更快更简单,所以你用多线程方式处理它会显得不自然和低效。
答案 2 :(得分:0)
这个问题需要以下解释:
您正在使用的线程是安全的,您正在按原样阅读原始值。
在基本字段上使用同步块有一个特定术语,但您需要执行以下操作:
答案 3 :(得分:0)
Java In Concurrencty
表示需要满足以下标准:挥发变量:
1. Writes to the variable do not depend on its current value, or you can ensure that only a single thread ever updates the value; 2. The variable does not participate in invariants with other state variables; and 3. Locking is not required for any other reason while the variable is being accessed.