在多线程应用程序中使用带有volatile原语的条件运算符是否安全

时间:2012-07-13 05:52:07

标签: java multithreading thread-safety volatile conditional-operator

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...");
    }
}

4 个答案:

答案 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)

这个问题需要以下解释:

您正在使用的线程是安全的,您正在按原样阅读原始值。

在基本字段上使用同步块有一个特定术语,但您需要执行以下操作:

  • 使用你所在领域的getter和setter。
  • 在两个访问器中放置同步和瞧。

答案 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.