2010-09-03 2 views
3

Использование volatile для переменной снижает риск ошибки согласованности памяти (пожалуйста, исправьте меня, если это выявит некоторые недостатки в моем понимании любой соответствующей концепции). Таким образом, в следующем примере, даже если переменная c1 является нестабильной, до сих пор появление результатов ошибки Постоянство памяти в c1 становится 15 или иногда 14 на выходе, а затем правильный выход 16.Использование volatile по атомным переменным

class Lunch implements Runnable { 

    private volatile long c1 = 0; 
    private Object lock1 = new Object(); 
    private Object lock2 = new Object(); 
    public void inc1() { 
     // synchronized(lock1) { c1 is volatile 
      c1++; 
     // } 
    } 

    public void run() { 
     try { 
      inc1(); 
      Thread.sleep(1000); 
      inc1(); 
      Thread.sleep(1000); 
      inc1(); 
      Thread.sleep(1000); 
      inc1(); 
      inc1(); 
      Thread.sleep(1000); 
      inc1(); 
      Thread.sleep(1000); 
      inc1(); 
      Thread.sleep(1000); 
      inc1(); 
     } 
     catch(InterruptedException e) { 
      return; 
     } 
    } 
    public long value() { 
     return c1; 
    } 
    public static void main(String args[]) throws InterruptedException { 
     Lunch l = new Lunch(); 
     Thread t1 = new Thread(l); 
     Thread t2 = new Thread(l); 
     t1.start(); 
     t2.start(); 
     t1.join(); 
     t2.join(); 
     System.out.println(l.value()); 
    } 
} 
+0

Предполагается, что ++ является атомарным. Проверьте свои предположения! – nos

+2

(Я немного беспокоюсь о том, что вы используете фразу «снижает риск». Обычно цель заключается в том, чтобы не создавать никакого риска.) –

ответ

6

Вы правильно. Поскольку ++ не является атомной операцией, вы все равно можете получить противоречивые результаты, когда поток читает/увеличивает/записывает значение одновременно с другим потоком.

Рассмотрите возможность использования AtomicInteger для таких случаев.

+0

Итак, если я заменю несколько вызовов increment() в run() с другой функцией update (long c1) {this.c1 = c1}, который является частью этого класса. Тогда, поскольку c1 является volatile и ++ не участвует, результат должен быть последовательно правильным? – msk

+0

Или 'AtomicIntegerUpdater' в некоторых случаях, когда операции с манипуляцией с нагрузкой являются редкими. –

+0

@msk это было бы «правильно», поскольку в любой момент времени любому чтению чтения c1 было бы гарантировано увидеть обновленное значение c1. Полезность информации, которая установлена ​​без предварительной проверки, часто вызывает сомнения. Обычный прецедент - это логический флаг, в котором один поток сигнализирует другой (например, флаг остановки). Это почти единственный случай, когда я использую volatile. –

1

Отметьте http://www.javabeat.net/tips/169-volatile-keyword-in-java.html для понимания того, что изменчиво делает. Он избегает кэша промежуточных потоков, но в любом случае может быть потерянное обновление от чтения его значения и обновления в неатомной операции.

3

Атомность - это только часть изображения. Существует также видимость. Если изменено значение энергонезависимой (и несинхронизированной) переменной, другие потоки не гарантированно будут видеть изменение во времени или вообще.

Смежные вопросы