2013-04-29 5 views
3
public class MyThread 
{ 
    volatile static int i; 

    public static class myT extends Thread 
    { 
     public void run() 
     { 
      int j = 0; 
      while(j<1000000){ 
       i++; 
       j++; 
      } 
     } 
    } 

    public static void main (String[] argv) 
    throws InterruptedException{ 
      i = 0; 

      Thread my1 = new myT(); 
      Thread my2 = new myT(); 
      my1.start(); 
      my2.start(); 

      my1.join(); 
      my2.join(); 

      System.out.println("i = "+i); 
    } 
} 

Поскольку волатильные сборки происходят до отношения, окончательное значение i должно быть строго 2000000. Однако фактический результат ничем не отличается от того, чтобы быть нестабильным для переменной i. Может ли кто-нибудь объяснить, почему он здесь не работает? Так как i объявлен volatile, он должен быть защищен от несоответствия памяти.Явная переменная volatile не работает корректно.

ответ

7

Может быть любое объяснение, почему оно здесь не работает? Так как i объявлен volatile, он должен быть защищен от несоответствия памяти.

Он защищен, но, к сожалению, i++ не является атомной операцией. Это фактически чтение/увеличение/сохранение. Таким образом, volatile не собирается спасать вас от условий гонки между потоками. Вы можете получить следующий порядок операций из программы:

  1. нить # 1 читает i, получает 10
  2. сразу после этого, нить # 2 читает i, получает 10
  3. нити # 1 приращение i к 11
  4. поток # 2 приращения i до 11
  5. поток # 1 сохраняет 11 i
  6. поток # 2 сохраняет 11 i

Как вы можете видеть, даже если приращения 2 произошли и значение было правильно синхронизировать между потоками, условие гонки означает, что значение только пошло на 1. Смотрите эту nice looking explanation. Вот еще один хороший ответ: Is a volatile int in Java thread-safe?

Что вы должны использовать, это AtomicInteger, что позволяет безопасно увеличивать количество потоков.

static final AtomicInteger i = new AtomicInteger(0); 
... 
     for (int j = 0; j<1000000; j++) { 
      i.incrementAndGet(); 
     } 
+1

Только 'i' должен быть' AtomicInteger'; 'j' является чисто локальным для потока. –

+0

Тогда в чем смысл объявлять меня изменчивым? Так как он все равно не защищен. – OneZero

+0

Спасибо @MelNicholson. Я уже обновил свой ответ. – Gray

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