Объявление учетной записи как volatile подвержено следующим проблемам и ограничениям
1. "Поскольку другие потоки не могут видеть локальные переменные, объявление локальных переменных volatile бесполезно ."Более того, если вы попытаетесь объявить переменную в методе, в некоторых случаях вы получите ошибку компилятора.
double getBalance () {volatile Account acct = verify (name, password);// Неверно ..}
Объявление учетной записи как volatile предупреждает компилятор извлекать их каждый раз заново, а не кэшировать их в регистрах .Это также запрещает определенные оптимизации , предполагающие, что никакой другой поток не изменит значения неожиданно.
Если вам требуется синхронизация для координации изменений переменных из разных потоков, volatile не гарантирует вам атомарный доступ , потому что доступ к переменной volatile никогда не удерживает блокировку, он не подходит для случаев, когда мы хотим читать-обновлять-записывать как атомарную операцию.Если вы не уверены, что acct = verify (имя, пароль);является единственной атомарной операцией, вы не можете гарантировать исключительные результаты
Если переменная acct является ссылкой на объект, скорее всего, она может быть нулевой. Попытка синхронизации с нулевым объектом приведет кисключение NullPointerException с использованием синхронизации.(потому что вы эффективно синхронизируете ссылку, а не реальный объект) Где volatile не жалуется
Вместо этого вы можете объявить булеву переменную как volatile, как здесь
private volatile логическое someAccountflag;
public void getBalance () {Account acct;while (! someAccountflag) {acct = verify (имя, пароль);}}
Обратите внимание, что вы не можете объявить someAccountflag как синхронизированный, поскольку вы не можете синхронизировать примитив с синхронизированным, synchronized работает только с объектными переменными, где в качестве примитива или объектной переменнойможет быть объявлено как volatile
6. Конечные статические поля класса не должны быть volatile , JVM решает эту проблему.Таким образом, флаг someAccount не нужно даже объявлять как volatile, если он является окончательным статическим, или вы можете использовать ленивую одноэлементную инициализацию, делающую Account как объект singleton, и объявить его следующим образом: private final static AccountSingleton acc_singleton = new AccountSingleton ();