AtomicXXXFieldUpdater — чудесные классы, открывающие значительную часть магии Unsafe без проблем с безопасностью и переносимостью. К сожалению, есть некоторая цена. Вот цитата из AtomicLongFieldUpdater.CASUpdater:public void lazySet(T obj, long newValue) {
if (obj == null || obj.getClass() != tclass || cclass != null)
fullCheck(obj);
unsafe.putOrderedLong(obj, offset, newValue);
}
private void ensureProtectedAccess(T obj) {
if (cclass.isInstance(obj))
return;
throw new RuntimeException (
new IllegalAccessException("Class " + cclass.getName() +
" can not access a protected member of class " + tclass.getName() +
" using an instance of " + obj.getClass().getName()
)
);
}
private void fullCheck(T obj) {
if (!tclass.isInstance(obj))
throw new ClassCastException();
if (cclass != null)
ensureProtectedAccess(obj);
}
Выглядит все довольно страшно, хотя на практике в большинстве случаев все закончится на первых трех проверках: (
obj == null || obj.getClass() != tclass || cclass != null). Эффект от них невелик, в моих бенчмарках замена AtomicUpdater на Unsafe давала 15-20% максимум в очень нагруженном конкурентном коде. По-видимому, дело в том, что результат этих проверок в правильно написанном коде всегда одинаков (false), поэтому предсказатель ветвлений в процессоре довольно быстро сообразит, какая из веток реализуется со 100% вероятностью, и будет спекулятивно выполнять код дальше. Тем не менее, иногда не хочется терять и этих процентов. Хорошая новость состоит в том, что
AtomicLongFieldUpdater — абстрактный класс, и никто не мешает вам написать свою реализацию. Например, взять за основу AtomicLongFieldUpdater.CASUpdater, и просто выбросить все "лишние" проверки. Результат будет практически drop-in-replacement для большинства сценариев использования.Разумеется, у меня сразу возникла мысль сделать какую-то свою фабрику, на замену
AtomicLongFieldUpdater.newUpdater(...), которая по-умолчанию делегировала бы к AtomicLongFieldUpdater.newUpdater, а при указании специального свойства -Djava.concurrent.run-faster начинала бы использовать оптимизированную версию. Плохая новость состоит в том, что так не получается: в конструкторе AtomicFieldUpdater-а проверяется, что вы можете создать AtomicUpdater только для того поля, которое вы и так можете видеть из создающего кода. Если я собираюсь обновлять private поле, то AtomicUpdater для него я смогу создать только изнутри этого же класса. И значит выбор реализации AtomicUpdater-а придется делать внутри каждого класса, его использующего.
про фабрику.
ОтветитьУдалитьне работает в аплетах.
Да, конечно не работает. Как и все, связанное с Unsafe. Но мне сомнительно, чтобы в апплетах был востребован такой hardcore concurrency, чтобы нужно было оптимизировать safety checks.
ОтветитьУдалитьИнтересно, может ли умный JIT, увидев при компиляции, что мы не посещали путь тяжёлых проверок, забить на него, и поставить там Uncommon trap.
ОтветитьУдалитьНасколько я понимаю -- предсказатель ветвлений это и делает. Он спекулятивно отправляет на выполнение инструкции по наивероятнейшей ветке, и откатывает уже выполненные, если вдруг окажется, что с веткой он не угадал.
ОтветитьУдалить