2013-07-18 2 views
3

Я читаю «Java Concurrency in Practice» и пытаюсь написать фрагмент кода, который покажет, что класс, представленный в качестве примера в главе 3.5.1, может действительно ввести проблемы.Кодирование доказательства потенциальной проблемы параллелизма

public class Holder { 
    public int n; 

    public Holder(int n) { 
     this.n = n; 
    } 

    public void assertSanity() { 
     if (n != n) { 
      throw new AssertionError("sanity check failed!!"); 
     } 
    } 
} 

Он сказал, что если используется следующим образом (я считаю, что это о том, что поле является общедоступным, проблема параллелизма может произойти.

public Holder holder; 
public void initialize() { 
    holder = new Holder(42); 
} 

Так что я придумал этот код, чтобы увидеть, если что-то плохое случится.

public class SanityCheck { 

    public Holder holder; 

    public static void main(String[] args) { 

     SanityCheck sanityCheck = new SanityCheck(); 
     sanityCheck.runTest(); 

    } 

    public void runTest() { 
     for (int i = 0; i < 100; i++) { 
      new Thread() { 
       @Override 
       public void run() { 
        while (true) { 
         if (holder != null) { 
          holder.assertSanity(); 
         } 

         try { 
          Thread.sleep(1); 
         } catch (InterruptedException e) { 
         } 
        } 
       } 
      }.start(); 
     } 

     try { 
      Thread.sleep(1000); 
     } catch (InterruptedException e) { 
     } 

     initialize(); 

    } 

    public void initialize() { 
     holder = new Holder(42); 
    } 
} 

Но ничего плохого не происходит, никакой AssertionError не было выброшено.

Не могли бы вы помочь мне разобраться, почему этот код ничего не тормозит?

Заранее благодарю вас за ваше время.

ответ

3

Тот факт, что код не поточно и может создавать проблемы параллелизма не означает, что она будет сделать это.

Модель памяти Java (JMM) говорит, что программа должна вести себя, когда она правильно синхронизирована. Но он не говорит о том, как работает , если это не так.

Например, JVM, обеспечивающий последовательную согласованность, будет соответствовать JMM, и никакая проблема параллелизма никогда не произойдет.

W.r.t. ваш конкретный пример, очень маловероятно, чтобы разбить комбинацию x86/hostpot.

+1

Я согласен, попробовать его на старом многоядерного процессора ARM и может сломаться. –

2

Он сказал, что если он используется в паровании пути (я считаю, что это о том, что поле является общедоступным, проблема параллелизма может произойти.

Проблема может случиться, но нет никакой гарантии, возникнут проблемы

Если вы используете JVM Oracle, AFAIK обрабатывает межоперационные обращения к кодам как изменчивые. Только после компиляции конструктора и проверки вы можете столкнуться с проблемой. Даже тогда я подозреваю вам будет сложно.

0

Разве вы не должны менять значение n, чтобы заставить что-то сломаться? В текущей форме я не вижу, как будет вызываться AssertionError, независимо от проблем с параллелизмом.

Я ожидал что-то вроде этого:

if (holder != null) { 
    holder.n = holder.n - 1; 
    holder.assertSanity(); 
} 
+0

Код может теоретически потерпеть неудачу даже без модификации 'Holder.n', поскольку поток проверки работоспособности может видеть частично инициализированную версию' holder', где 'n' равно нулю, до того как полная инициализация будет видна. И с данным кодом, нет гарантии, что вспомогательный поток будет/когда-либо/видеть изменения, внесенные в основной поток, неважно, в постоянном состоянии! – rxg

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