Энергозависимый семантический относительно других полей

Я попробовал тренером Regex против:

x foo y
x bar y
x foobar y

, Если я проверяю g опция, действительно она распознает все три слова, потому что она ищет снова после каждого соответствия.
, Если Вы не хотите это поведение, можно привязать выражение, например, соответствуя только на границах слова:

\b(foo|bar)\b

Предоставление большего количества контекста на проблеме (на что похожи данные) могло бы дать лучшие ответы.

13
задан Denis Bazhenov 22 January 2015 в 01:40
поделиться

4 ответа

Да, этот код «правильный» в его нынешнем виде, начиная с Java 1.5.

Атомарность не является проблемой , с изменчивым кодом или без него (записи в ссылки на объекты являются атомарными), так что вы можете вычеркнуть это из списка проблем в любом случае - единственный открытый вопрос - это видимость изменений и «правильность» порядка.

Любая запись с изменчивой переменной устанавливает связь «происходит до» (ключевая концепция новой модели памяти Java, как указано в JSR-133 ) с любыми последующими чтениями той же переменной. Это означает, что поток чтения должен иметь видимость всего, что видно потоку записи: то есть он должен видеть все переменные с по крайней мере своими «текущими» значениями на момент записи.

Мы можем объяснить это подробно, просмотрев раздел 17.4.5 Спецификации языка Java , в частности следующие ключевые моменты:

  1. «Если x и y являются действиями одного и того же потока и x стоит перед y в программном порядке, затем hb (x, y) "(то есть, действия в одном потоке не могут быть переупорядочены таким образом, чтобы они не соответствовали порядку программы)
  2. " Запись в изменчивое поле (§8.3 .1.4) происходит перед каждым последующим чтением этого поля ». (это поясняющий текст, объясняющий, что запись и чтение изменчивого поля является точкой синхронизации)
  3. «Если hb (x, y) и hb (y, z), то hb (x, z)» ( транзитивность случая-раньше)

Итак, в вашем примере:

  • запись в 'service' (a) происходит до записи в 'serviceReady' (b), из-за правила 1
  • запись в ' serviceReady ' (b) происходит - до чтения того же (c), в соответствии с правилом 2
  • , следовательно, (a) происходит - до (c) (3-е правило)

, что означает, что вам гарантировано, что 'service' установлен правильно, в этом случае, когда serviceReady истинно.

Вы можете увидеть несколько хороших описаний, используя почти точно тот же пример, один на IBM DeveloperWorks - см. "Новое Гарантии для Volatile »:

значения, которые были видны A в то время, когда V была написана, теперь гарантированно будут видны B.

и одно в FAQ JSR-133 , написанное авторы этого JSR:

Таким образом, если читатель увидит истинное значение v, он также гарантированно увидит запись в 42, которая произошла до него. При старой модели памяти это было бы не так. Если бы v не было изменчивым, тогда компилятор может переупорядочить записи в модуле записи, и при чтении x будет отображаться 0.

18
ответ дан 1 December 2019 в 22:39
поделиться

AFAIK, это правильный код.

@CPerkins: синхронизация единственного метода setService не сработает, поскольку вам также придется синхронизировать при чтении.

Однако в этом случае достаточно одной переменной. Зачем вам дополнительное логическое поле. Например,

private volatile Service service;

public void setService(Service service) {
  this.service = service;
}

public void doWork() {
  if ( service != null ) {
    service.doWork();
  }
}

, учитывая, что никто никогда не вызывает setService для null . Поэтому вам, вероятно, следует выполнить нулевую проверку:

private volatile Service service;

public void setService(Service service) {
  if (service == null) throw NullPointerException();
  this.service = service;
}

public void doWork() {
  if ( service != null ) {
    service.doWork();
  }
}
2
ответ дан 1 December 2019 в 22:39
поделиться

Теоретически никогда не должно работать. Вы хотите обеспечить согласованность памяти для двух переменных и полагаться на энергозависимое чтение первой из них. Только чтение volatile гарантирует, что поток чтения увидит самое последнее значение переменной. Так что это определенно не так сильно, как вход в заблокированный (синхронизированный) раздел.

На практике это может сработать, в зависимости от реализации volatile в JVM, которую вы используете. Если энергозависимые чтения реализованы путем очистки всех кешей ЦП, это должно работать. Но готов поспорить, что этого не произойдет. Могу ли я принудительно согласовать кэш на многоядерном процессоре x86? - хорошее прочтение по этой теме.

Я бы сказал, просто иметь общую блокировку (java.util.concurrent.Lock или синхронизированную) для двух переменные и покончить с этим.

0
ответ дан 1 December 2019 в 22:39
поделиться

Вы правы насчет эффектов volatile , так что это должно быть правильно, но я смущен вашим дизайном. Я не понимаю, почему вы просто не синхронизируете setService - вероятно, он будет вызываться не часто. Если это называется более чем один раз, «, если (serviceReady) » часть является спорным, так как он все равно будет так, но это нормально, так как замена атомарным, если я правильно понимаю.

Я так понимаю, что service.doWork () является потокобезопасным, да?

1
ответ дан 1 December 2019 в 22:39
поделиться
Другие вопросы по тегам:

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