⚡️ Микро-оптимизация: Прощай,
👋 Сегодня поговорим о том, как можно немного ускорить ваш код, работающий с атомарными операциями, и сделать его более "современным" с помощью
🧐 Проблема с
Однако, у него есть небольшой недостаток: он добавляет слой косвенности. Методы типа
✨ Встречайте
Главное преимущество? JIT-компилятор (C2) лучше оптимизирует доступ через
🛠 Как использовать
Вместо того, чтобы хранить значение в отдельном объекте
1. Объявляем поле:
2. Создаем
3. Выполняем атомарную операцию:
Метод
🚀 Результат микро-оптимизации
В бенчмарках (например, с использованием JMH) можно увидеть, что операции
📲 Мы в MAX
👉@BookJava
AtomicInteger, привет, VarHandle!👋 Сегодня поговорим о том, как можно немного ускорить ваш код, работающий с атомарными операциями, и сделать его более "современным" с помощью
VarHandle, который появился в Java 9.🧐 Проблема с
AtomicIntegerAtomicInteger - это классический способ обеспечить атомарные операции (например, инкремент) над целым числом без блокировок, используя механизм Compare-And-Swap (CAS).Однако, у него есть небольшой недостаток: он добавляет слой косвенности. Методы типа
getAndIncrement() в AtomicInteger обычно вызывают внутренние статические методы из класса sun.misc.Unsafe (или его аналогов в более новых версиях), передавая в них ссылку на объект, смещение поля и новое значение.
// Примерно так это выглядит внутри AtomicInteger
// В реальном коде это, конечно, оптимизировано, но суть та же.
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
✨ Встречайте
VarHandle!VarHandle - это новый, более гибкий и, что самое главное, более производительный низкоуровневый API для работы с полями переменных (как экземпляров, так и статических) с заданными барьерами памяти и атомарностью.Главное преимущество? JIT-компилятор (C2) лучше оптимизирует доступ через
VarHandle, чем через старые обертки типа AtomicInteger или прямые вызовы Unsafe.🛠 Как использовать
VarHandle вместо AtomicIntegerВместо того, чтобы хранить значение в отдельном объекте
AtomicInteger, мы просто объявляем поле volatile в нашем классе и получаем VarHandle для этого поля.1. Объявляем поле:
public class Counter {
private volatile int count = 0; // Поле должно быть volatile
// ...
}
2. Создаем
VarHandle:VarHandle нужно инициализировать один раз (обычно в статическом блоке) для доступа к полю.
private static final VarHandle COUNT_HANDLE;
static {
try {
// Получаем VarHandle для поля 'count' класса 'Counter' с типом int
COUNT_HANDLE = MethodHandles.lookup().findVarHandle(
Counter.class,
"count",
int.class
);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new Error(e);
}
}
3. Выполняем атомарную операцию:
Метод
getAndAdd VarHandle работает точно так же, как getAndAdd в AtomicInteger.
public int increment() {
// В отличие от AtomicInteger, где первый аргумент неявен,
// VarHandle требует первым аргументом *объект*,
// к полю которого мы обращаемся.
return (int) COUNT_HANDLE.getAndAdd(this, 1);
}
🚀 Результат микро-оптимизации
В бенчмарках (например, с использованием JMH) можно увидеть, что операции
getAndAdd() через VarHandle могут быть незначительно быстрее (зачастую на 5-10%), чем те же операции через AtomicInteger, особенно под высокой нагрузкой, благодаря более эффективной генерации кода JIT-компилятором.🛑 Важно: Это микро-оптимизация. В большинстве приложений вы не заметите разницы. Но если вы пишете критически важные фреймворки, высоконагруженные коллекции или библиотеки, где каждая наносекунда на счету, переход на VarHandle может быть оправдан.VarHandle - это не только способ микро-оптимизации, но и стандартный, гибкий API для атомарного доступа, который заменил устаревший и менее безопасный Unsafe. Для нового кода, где требуется низкоуровневый атомарный доступ, стоит отдавать предпочтение именно ему.👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👎5👍4🔥1
Совет SpringBoot
Вы можете запустить метод в Spring
📲 Мы в MAX
👉@BookJava
Вы можете запустить метод в Spring
@Service сразу после запуска приложения, аннотируя его с помощью@EventListener (ApplicationReadyEvent.class). Метод не может иметь параметров. Иногда я неправильно использую его, чтобы быстро протестировать определенный метод Spring Service.👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🏆1
Использование лямбда-выражений и Streams:
Лямбда-выражения и streams делают код более лаконичным и читаемым.
📲 Мы в MAX
👉@BookJava
Лямбда-выражения и streams делают код более лаконичным и читаемым.
List<String> names = Arrays.asList("John", "Jane", "Jack", "Doe");
names.stream()
.filter(name -> name.startsWith("J"))
.map(String::toUpperCase)
.forEach(System.out::println);
👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👎4👍3