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

Я читаю "Параллелизм Java на практике" и смотрю на пример кода на странице 51.

Согласно книге эта часть кода из-за опасности отказа, если это не было опубликовано правильно. Поскольку я люблю к примерам кода и повреждаю их, чтобы доказать, как они работают. Я попытался заставить его бросить AssertionError, но перестал работать. (Продвижение меня к моему предыдущему вопросу)

Кто-либо может отправить пример кода так, чтобы AssertionError был брошен? Правило: не изменяйте класс Держателя.

public class Holder{
    private int n;

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

    public void assertSanity(){
        if (n != n) {
            throw new AssertionError("This statement is false");
        }
    }
}

Я изменил класс для создания этого более хрупким, но я все еще не мог бросить AssertionError.

class Holder2 {
    private int n;
    private int n2;

    public Holder2(int n) throws InterruptedException{
        this.n = n;
        Thread.sleep(200);
        this.n2 = n;
    }

    public void assertSanity(){
        if (n != n2) {
            throw new AssertionError("This statement is false");
        }
    }
}

Действительно ли возможно заставить любой из вышеупомянутых классов бросить AssertionError? Или мы должны признать, что они могут иногда делать так, и мы не можем написать код для доказательства его?

9
задан Community 23 May 2017 в 02:03
поделиться

3 ответа

Я бы запустил это на многопроцессорной машине в течение нескольких часов и посмотрел, что произойдет (удалите спящий режим, если вы используете свой Holder2). Такие условия гонки могут быть редкими или отсутствовать на вашей конкретной машине - но, по крайней мере, попытайтесь спровоцировать их на миллион случаев, пробуя миллионы раз.

class Checker {
  private Holder h;
  public Checker() {
   h = new Holder(42);
  }

  public void check() {
    h.assertSanity();
  }

  public void create(int n) {
   h = new Holder(n);
   }

}

public class MyThread extends thread{
  private bool check;
  private final Checker c;
  public MyThread(bool check,Checker c) {
    this.check = check;
    this.c = c;
  }
    public static void main(String[] args) {
      Checker c = new Checker();
      MyThread t1 = new MyThread(false,c);  
      MyThread t2 = new MyThread(true,c);
      t1.start();
      t2.start();
      t1.join();
      t2.join();
   }
   public void run() {
     int n = 0;
     while(true) {
       if(check) 
         c.check();
       else
         c.create(n++);
    }
   }
 }
}
3
ответ дан 3 November 2019 в 07:47
поделиться

Как сказал БоббиШафто в другом потоке, вы не можете полагаться на простое выполнение кода достаточное количество раз, чтобы показать, что ошибка может или не может произойти. Если вы подумаете об этом с уровня сборки, это будет очень сложно для n! = N, так как это так мало вызовов и зависит от процесса, который отключается в действительно точное время.

Если вы хотите иметь возможность показать, является ли параллельная система доказуемой, лучше смоделировать ее, используя что-то вроде систем помеченных переходов. Попробуйте инструмент LTSA, если вы хотите проверить параллелизм или найти ошибки.

http://www.doc.ic.ac.uk/ltsa/

1
ответ дан 3 November 2019 в 07:47
поделиться

Вы не можете изменить значение n в любое время, используя:

  Holder h = new Holder(5);
  Field f = h.getClass().getDeclaredField("n");
  f.setAccessible(true);
  f.setInt(h, 10);
  h.assertSanity();
-1
ответ дан 3 November 2019 в 07:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: