Я попробовал тренером Regex против:
x foo y
x bar y
x foobar y
, Если я проверяю g
опция, действительно она распознает все три слова, потому что она ищет снова после каждого соответствия.
, Если Вы не хотите это поведение, можно привязать выражение, например, соответствуя только на границах слова:
\b(foo|bar)\b
Предоставление большего количества контекста на проблеме (на что похожи данные) могло бы дать лучшие ответы.
Да, этот код «правильный» в его нынешнем виде, начиная с Java 1.5.
Атомарность не является проблемой , с изменчивым кодом или без него (записи в ссылки на объекты являются атомарными), так что вы можете вычеркнуть это из списка проблем в любом случае - единственный открытый вопрос - это видимость изменений и «правильность» порядка.
Любая запись с изменчивой переменной устанавливает связь «происходит до» (ключевая концепция новой модели памяти Java, как указано в JSR-133 ) с любыми последующими чтениями той же переменной. Это означает, что поток чтения должен иметь видимость всего, что видно потоку записи: то есть он должен видеть все переменные с по крайней мере своими «текущими» значениями на момент записи.
Мы можем объяснить это подробно, просмотрев раздел 17.4.5 Спецификации языка Java , в частности следующие ключевые моменты:
Итак, в вашем примере:
, что означает, что вам гарантировано, что 'service' установлен правильно, в этом случае, когда serviceReady истинно.
Вы можете увидеть несколько хороших описаний, используя почти точно тот же пример, один на IBM DeveloperWorks - см. "Новое Гарантии для Volatile »:
значения, которые были видны A в то время, когда V была написана, теперь гарантированно будут видны B.
и одно в FAQ JSR-133 , написанное авторы этого JSR:
Таким образом, если читатель увидит истинное значение v, он также гарантированно увидит запись в 42, которая произошла до него. При старой модели памяти это было бы не так. Если бы v не было изменчивым, тогда компилятор может переупорядочить записи в модуле записи, и при чтении x будет отображаться 0.
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();
}
}
Теоретически никогда не должно работать. Вы хотите обеспечить согласованность памяти для двух переменных и полагаться на энергозависимое чтение
первой из них. Только чтение volatile гарантирует, что поток чтения увидит самое последнее значение переменной. Так что это определенно не так сильно, как вход в заблокированный (синхронизированный) раздел.
На практике это может сработать, в зависимости от реализации volatile в JVM, которую вы используете. Если энергозависимые чтения реализованы путем очистки всех кешей ЦП, это должно работать. Но готов поспорить, что этого не произойдет. Могу ли я принудительно согласовать кэш на многоядерном процессоре x86? - хорошее прочтение по этой теме.
Я бы сказал, просто иметь общую блокировку (java.util.concurrent.Lock или синхронизированную) для двух переменные и покончить с этим.
Вы правы насчет эффектов volatile
, так что это должно быть правильно, но я смущен вашим дизайном. Я не понимаю, почему вы просто не синхронизируете setService
- вероятно, он будет вызываться не часто. Если это называется более чем один раз, «, если (serviceReady)
» часть является спорным, так как он все равно будет так, но это нормально, так как замена атомарным, если я правильно понимаю.
Я так понимаю, что service.doWork ()
является потокобезопасным, да?