Я читаю "Параллелизм 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? Или мы должны признать, что они могут иногда делать так, и мы не можем написать код для доказательства его?
Я бы запустил это на многопроцессорной машине в течение нескольких часов и посмотрел, что произойдет (удалите спящий режим, если вы используете свой 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++);
}
}
}
}
Как сказал БоббиШафто в другом потоке, вы не можете полагаться на простое выполнение кода достаточное количество раз, чтобы показать, что ошибка может или не может произойти. Если вы подумаете об этом с уровня сборки, это будет очень сложно для n! = N, так как это так мало вызовов и зависит от процесса, который отключается в действительно точное время.
Если вы хотите иметь возможность показать, является ли параллельная система доказуемой, лучше смоделировать ее, используя что-то вроде систем помеченных переходов. Попробуйте инструмент LTSA, если вы хотите проверить параллелизм или найти ошибки.
Вы не можете изменить значение n
в любое время, используя:
Holder h = new Holder(5);
Field f = h.getClass().getDeclaredField("n");
f.setAccessible(true);
f.setInt(h, 10);
h.assertSanity();