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.
ОтветитьУдалитьНасколько я понимаю -- предсказатель ветвлений это и делает. Он спекулятивно отправляет на выполнение инструкции по наивероятнейшей ветке, и откатывает уже выполненные, если вдруг окажется, что с веткой он не угадал.
ОтветитьУдалить