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

У меня есть этот упрощенный фрагмент кода с двумя переменными (предположим, что мы должны сохранить оба поля):

      volatile boolean hasParam;
volatile String param;

boolean hasParam() {
  if (param == null) {
    getParam();
  }
  return hasParam;
}

String getParam() {
  String tmp = param;
  if (tmp == null) {
    tmp = "String";
    hasParam = true;
    param = tmp;
  }
  return tmp;
}

Я размышляю, могу ли я отказаться от объявления поля таким образом: если есть два потока, вызывающих под гонкой, и первый записывает в volatile поле (делает освобождение хранилища), а второй поток читает ненулевое значение из того же поля ( делая получение чтения ) тогда он должен читать и только из . В противоположном случае ( приобретение чтения читаетnull) второй поток пишетtrueвparamи возвращает его изhasParam().

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

Чтобы доказать это, я разработал этот тест на основе JCStress:

      @State
@JCStressTest
@Outcome(id = "true, String", expect = ACCEPTABLE, desc = "Boolean value was flushed")
@Outcome(id = "false, String", expect = FORBIDDEN, desc = "Boolean value was not flushed")
public class ConcurrencyTest {
  Value value = new Value();

  @Actor
  public void actor1(ZL_Result r) {
    r.r1 = value.hasParameter();
    r.r2 = value.param;
  }

  @Actor
  public void actor2(ZL_Result r) {
    r.r1 = value.hasParameter();
    r.r2 = value.param;
  }

  static class Value {

    volatile boolean hasParam;
    volatile String param;

    boolean hasParameter() {
      if (param == null) {
        getParam();
      }
      return hasParam;
    }

    String getParam() {
      String tmp = param;

      if (tmp == null) {
        tmp = "String";
        hasParam = true;
        param = tmp;
      }

      return tmp;
    }
  }
}

Этот тест дает результаты:

             RESULT      SAMPLES     FREQ      EXPECT  DESCRIPTION
false, String            0    0,00%   Forbidden  Boolean value was not flushed
 true, String  638 164 992  100,00%  Acceptable  Boolean value was flushed

Если я сотру изhasParamfield, то я получаю те же результаты (я предполагаю, что это доказывает правильность моего предположения):

             RESULT        SAMPLES     FREQ      EXPECT  DESCRIPTION
false, String              0    0,00%   Forbidden  Boolean value was not flushed
 true, String  1 074 450 432  100,00%  Acceptable  Boolean value was flushed

И если я сотруvolatileиз объявления обоих полей тест завершается неудачно:

             RESULT        SAMPLES     FREQ      EXPECT  DESCRIPTION
false, String      1 420 423    0,12%   Forbidden  Boolean value was not flushed
 true, String  1 164 432 249   99,88%  Acceptable  Boolean value was flushed

Итак, у меня есть два вопроса:

  1. Правильно ли мое предположение и программа остается правильной?
  2. Верен ли мой тест?

0 ответов

Другие вопросы по тегам