🎉5❤2
HashMap и ConcurrentHashMap1️⃣ HashMap:
• Не потокобезопасен.
• Быстрее в однопоточном окружении.
• Можно получить
ConcurrentModificationException, если итерация выполняется параллельно с изменением данных.2️⃣ ConcurrentHashMap:
• Потокобезопасен.
• Использует сегментацию для увеличения производительности в многопоточном режиме.
• Не выбрасывает
ConcurrentModificationException.Пример:
Map<String, String> map = new ConcurrentHashMap<>();
map.put("key", "value");
ConcurrentHashMap.#java #hashmap #concurrenthashmap
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🤯3❤1
📌 Что такое
Ключевое слово
✔️ Основные особенности:
1️⃣ Обеспечивает чтение переменной из основной памяти, а не из кэша потока.
2️⃣ Гарантирует видимость изменений между потоками.
Пример:
💡 Ограничение:
#java #volatile #multithreading
volatile и как оно работает?Ключевое слово
volatile в Java используется для переменных, к которым обращаются несколько потоков. Оно гарантирует, что изменения переменной одним потоком будут видны другим.1️⃣ Обеспечивает чтение переменной из основной памяти, а не из кэша потока.
2️⃣ Гарантирует видимость изменений между потоками.
Пример:
class SharedObject {
volatile int count = 0;
}volatile не гарантирует атомарность операций. Для этого используйте synchronized или классы из java.util.concurrent.#java #volatile #multithreading
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤1🔥1
default методы в интерфейсах?С появлением Java 8 интерфейсы могут содержать методы с реализацией по умолчанию с помощью ключевого слова
default.1️⃣ Позволяет добавлять новые методы в интерфейс без нарушения обратной совместимости.
2️⃣ Облегчает создание интерфейсов с базовой реализацией.
Пример:
interface MyInterface {
default void defaultMethod() {
System.out.println("Default implementation");
}
}default методы для минимальной реализации интерфейсов без создания дополнительных классов.#java #defaultmethods #java8
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤2
AtomicInteger и зачем он нужен?AtomicInteger — это класс из java.util.concurrent.atomic, который предоставляет атомарные операции над int без использования synchronized.1️⃣ Позволяет безопасно изменять значение в многопоточной среде.
2️⃣ Работает быстрее, чем synchronized, так как использует низкоуровневые атомарные операции.
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicExample {
private static AtomicInteger count = new AtomicInteger(0);
public static void main(String[] args) {
count.incrementAndGet(); // Увеличиваем значение на 1
System.out.println(count.get()); // 1
}
}
AtomicInteger, если вам нужны безопасные инкременты/декременты без блокировки.#java #atomicinteger #concurrency
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤2
CopyOnWriteArrayList — это коллекция, которая предоставляет потокобезопасный доступ к данным. Она реализует интерфейс
List и часто используется в многопоточных приложениях, где требуется безопасная работа с коллекцией. 📌 Преимущества CopyOnWriteArrayList
1️⃣ Потокобезопасность: операции чтения выполняются быстро и безопасно, без синхронизации.
2️⃣ Отсутствие блокировок при чтении: читатели не блокируют друг друга, что ускоряет доступ к данным.
3️⃣ Безопасность при итерации: при изменении коллекции (добавление, удаление) итераторы не выбрасывают
ConcurrentModificationException. 📌 Недостатки CopyOnWriteArrayList
1️⃣ Медленные операции записи: при изменении данных создаётся новый массив, что делает операции записи (добавление/удаление) дорогими по времени.
2️⃣ Высокие затраты на память: каждый раз при изменении списка создаётся копия массива, что увеличивает потребление памяти.
3️⃣ Неэффективно для частых изменений: если коллекция часто модифицируется, производительность сильно снижается.
📌 Когда стоит использовать CopyOnWriteArrayList?
- Когда коллекция используется преимущественно для чтения и редко изменяется.
- Когда важно избежать ошибок при многопоточном доступе к коллекции.
💡 Совет: Если ваша коллекция часто изменяется, лучше использовать другие коллекции с явной синхронизацией, такие как
ConcurrentLinkedQueue или Collections.synchronizedList(). #Java #CopyOnWriteArrayList #Потокобезопасность #Коллекции
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤2
Рекурсия — это техника программирования, когда метод вызывает сам себя для решения подзадачи.
1️⃣ Упрощает код, особенно для задач, которые естественно описываются рекурсивно (например, вычисление факториала, обход дерева).
2️⃣ Позволяет заменять циклы более читаемым кодом.
public class Factorial {
static int factorial(int n) {
return (n == 0) ? 1 : n * factorial(n - 1);
}
public static void main(String[] args) {
System.out.println(factorial(5)); // 120
}
}
#java #recursion #factorial
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤1
LinkedBlockingQueue — это очередь, поддерживающая потокобезопасное взаимодействие между производителями и потребителями. Она реализует интерфейс
BlockingQueue, что означает, что потоки, работающие с этой очередью, могут блокироваться до тех пор, пока элементы не будут доступны для потребления или пока место не освободится для добавления новых элементов.📌 Преимущества LinkedBlockingQueue:
1️⃣ Потокобезопасность: поддерживает безопасное добавление и извлечение элементов из разных потоков.
2️⃣ Блокировка: потоки, извлекающие элементы, могут блокироваться до появления элементов, а потоки, добавляющие элементы, могут блокироваться, если очередь полна.
3️⃣ Гибкость: поддерживает как ограниченные, так и неограниченные очереди.
📌 Когда использовать LinkedBlockingQueue?
- Для реализации паттернов "производитель-потребитель", когда один или несколько потоков производят данные, а другие их потребляют.
- Когда требуется синхронизация между потоками с блокировкой при переполнении или пустой очереди.
- В задачах, требующих управления очередностью выполнения потоков (например, в очередях задач).
📌 Пример использования LinkedBlockingQueue:
import java.util.concurrent.*;
public class LinkedBlockingQueueExample {
public static void main(String[] args) throws InterruptedException {
LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<>(10);
// Производитель
Thread producer = new Thread(() -> {
try {
for (int i = 0; i < 20; i++) {
System.out.println("Производитель добавил: " + i);
queue.put(i); // Блокирует, если очередь полна
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
// Потребитель
Thread consumer = new Thread(() -> {
try {
for (int i = 0; i < 20; i++) {
int item = queue.take(); // Блокирует, если очередь пуста
System.out.println("Потребитель забрал: " + item);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
producer.start();
consumer.start();
producer.join();
consumer.join();
}
}
📌 Как это работает:
1️⃣ Производитель добавляет элементы в очередь с помощью
put(). Если очередь полна, поток будет блокироваться. 2️⃣ Потребитель извлекает элементы с помощью
take(). Если очередь пуста, поток будет блокироваться до появления элементов. ✨ Когда использовать LinkedBlockingQueue?
- Для решения задач с ограниченным количеством ресурсов (например, пул потоков).
- В многозадачных приложениях, где важно организовать очередь обработки данных между потоками.
- Когда необходимо сбалансировать нагрузку между потоками, эффективно распределяя задачи и ресурсы.
💡 Совет: Используйте
LinkedBlockingQueue для решения задач с конкурентными потоками и синхронизацией, где важно поддержание порядка и эффективное управление потоками. #Java #LinkedBlockingQueue #Потокобезопасность #Многозадачность
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤1
synchronized?Ключевое слово
synchronized используется для управления доступом к разделяемым ресурсам в многопоточном окружении.📌 Пример использования:
1️⃣ Синхронизация метода:
public synchronized void increment() {
count++;
}2️⃣ Синхронизация блока кода:
public void increment() {
synchronized (this) {
count++;
}
}• Обеспечивает монопольный доступ к методу или блоку.
• Снижает производительность из-за блокировок.
synchronized только там, где это действительно необходимо, чтобы избежать узких мест.#java #synchronized #multithreading
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13❤1
volatile и synchronized Lazy Initialization — это паттерн, при котором объект создаётся только при первом обращении к нему, а не в момент запуска приложения. Это полезно для оптимизации производительности, особенно если объект может быть дорогим в создании, а его использование не всегда необходимо.
В Java можно реализовать Lazy Initialization с помощью ключевого слова
volatile и синхронизации (synchronized), чтобы гарантировать правильное поведение в многозадачных приложениях.📌 Что такое
volatile и synchronized? 1️⃣
volatile: Гарантирует, что все потоки видят актуальное значение переменной, без кэширования её в локальной памяти. 2️⃣
synchronized: Блокирует доступ к коду, чтобы только один поток мог выполнить его в определённый момент времени.Пример:
public class LazyInitialization {
// Переменная с модификатором volatile
private static volatile SomeClass instance;
// Метод для получения экземпляра класса
public static SomeClass getInstance() {
// Первый контроль (без блокировки), если объект уже инициализирован
if (instance == null) {
synchronized (LazyInitialization.class) {
// Второй контроль с блокировкой для создания объекта
if (instance == null) {
instance = new SomeClass();
}
}
}
return instance;
}
public static void main(String[] args) {
SomeClass obj = LazyInitialization.getInstance();
System.out.println(obj);
}
}
class SomeClass {
// Пример класса для инициализации
public SomeClass() {
System.out.println("Объект SomeClass создан!");
}
}
📌 Как это работает:
1️⃣ При первом обращении к
getInstance(), проверяется, создан ли уже объект. Если нет — блокируется доступ для других потоков с помощью synchronized. 2️⃣ Внутри блока
synchronized снова проверяется, не был ли объект создан другим потоком, чтобы избежать повторной инициализации. 3️⃣
volatile гарантирует, что создание объекта будет завершено до того, как другие потоки получат доступ к переменной.📌 Когда использовать такую реализацию?
- Для обеспечения потокобезопасности при ленивой инициализации объектов.
- В многозадачных приложениях, где объект должен быть создан только один раз.
💡 Совет: Эта техника подходит для случаев, когда объект может быть дорогим в создании и его создание должно происходить только при первом обращении.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤2👎1🔥1
StringBuilder и StringBufferИ
StringBuilder, и StringBuffer используются для работы со строками, но между ними есть важные отличия.✔️ StringBuilder быстрее, но не потокобезопасен.
✔️ StringBuffer потокобезопасен, но медленнее из-за синхронизации.
StringBuilder:StringBuilder sb = new StringBuilder("Hello");
sb.append(" World");
System.out.println(sb); // Hello WorldStringBuffer:StringBuffer sb = new StringBuffer("Hello");
sb.append(" World");
System.out.println(sb); // Hello WorldStringBuilder для лучшей производительности.#java #stringbuilder #stringbuffer
Please open Telegram to view this post
VIEW IN TELEGRAM
👍18❤3🔥2
DatagramChannel из java.nio.channels — это мощный инструмент для работы с UDP-соединениями в Java. Этот канал позволяет отправлять и принимать датаграммы (пакеты данных), что делает его идеальным для создания лёгких и быстрых сетевых приложений. 🔍 Особенности DatagramChannel:
1️⃣ Поддерживает неблокирующий режим.
2️⃣ Простое взаимодействие без установки соединения.
3️⃣ Отлично подходит для передачи небольших сообщений.
📌 Пример отправки и получения сообщения:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
public class DatagramChannelExample {
public static void main(String[] args) {
new Thread(() -> {
// Создаём канал для получения
try (DatagramChannel receiver = DatagramChannel.open()) {
receiver.bind(new InetSocketAddress(9999));
ByteBuffer buffer = ByteBuffer.allocate(1024);
receiver.receive(buffer);
buffer.flip();
byte[] receivedData = new byte[buffer.limit()];
buffer.get(receivedData);
System.out.println("Получено сообщение: " + new String(receivedData));
} catch (IOException e) {
throw new RuntimeException(e);
}
}).start();
// Создаём канал для отправки
try (DatagramChannel sender = DatagramChannel.open()) {
String message = "Привет, мир!";
ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());
sender.send(buffer, new InetSocketAddress("localhost", 9999));
System.out.println("Сообщение отправлено.");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
🔗 Ключевые моменты:
1️⃣ Отправка: Используйте
send для передачи данных по указанному адресу. 2️⃣ Получение: Метод
receive позволяет читать входящие датаграммы. 3️⃣ Порт: Убедитесь, что отправитель и получатель используют один и тот же порт.
✨ Когда использовать?
- Для приложений с низкой задержкой, где важна скорость.
- Для отправки сообщений в локальной сети.
- В системах, где не требуется постоянное соединение.
💡 Совет: Используйте
DatagramChannel для лёгких и быстрых решений, например, для игровых серверов или мониторинга систем. #Java #DatagramChannel #UDP
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤4🔥3👏1
var и когда его использовать?С появлением Java 10 был добавлен
var – ключевое слово для вывода типа переменной на основе присвоенного значения.• Позволяет сократить код, убрав явное указание типа.• Работает только для локальных переменных (нельзя использовать для аргументов метода или полей класса).
var message = "Hello, Java!"; // Компилятор автоматически определит тип String
var number = 42; // int
var list = List.of("A", "B", "C"); // List<String>
var так:
var x; // Ошибка, требуется инициализация
var, если тип очевиден, но не злоупотребляйте, чтобы не терять читаемость кода.#java #var #java10
Please open Telegram to view this post
VIEW IN TELEGRAM
👍19❤1👎1
Record в Java?Record – это новый тип класса, который появился в Java 14 и предназначен для создания неизменяемых объектов с минимальным кодом.• Автоматически создаёт equals(), hashCode() и toString().• Подходит для DTO (Data Transfer Object) и неизменяемых объектов.public record Person(String name, int age) {}
public class Main {
public static void main(String[] args) {
Person person = new Person("Alice", 30);
System.out.println(person); // Person[name=Alice, age=30]
}
}Record, если вам нужен неизменяемый объект с автогенерацией методов.#java #record #java14
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤2
WeakReference?WeakReference – это специальный тип ссылки, который не предотвращает сборщик мусора от удаления объекта.• Используется, когда объект не является критически важным.• Полезен для кеширования, где объект можно освободить при нехватке памяти.
import java.lang.ref.WeakReference;
public class WeakRefExample {
public static void main(String[] args) {
String str = new String("WeakReference");
WeakReference<String> weakRef = new WeakReference<>(str);
str = null; // Теперь объект доступен для GC
System.gc();
System.out.println(weakRef.get()); // Может быть null
}
}
WeakReference, если объект должен автоматически удаляться при нехватке памяти.#java #weakreference
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8👍2🔥1🙏1
💡 Как управлять потоками с помощью ExecutorCompletionService
ExecutorCompletionService — это инструмент для удобной работы с потоками, позволяющий эффективно управлять задачами, выполняющимися асинхронно, и получать результаты по мере их готовности. Он сочетает в себе возможности
📌 Преимущества ExecutorCompletionService:
1️⃣ Удобное управление задачами: позволяет управлять и отслеживать несколько асинхронных задач одновременно.
2️⃣ Получение результатов по мере выполнения: результаты задач можно получать в том порядке, в котором они завершены.
3️⃣ Обработка ошибок: позволяет перехватывать исключения, возникающие в процессе выполнения задач.
📌 Пример использования ExecutorCompletionService:
📌 Как это работает:
1️⃣ Создаём
2️⃣ Задачи отправляются в очередь с помощью метода
3️⃣ Метод
4️⃣ Метод
📌 Когда использовать ExecutorCompletionService?
- Когда необходимо параллельно выполнить несколько задач и получить результаты по мере их завершения.
- В ситуациях, когда задачи могут занять разное время на выполнение.
- Для эффективного управления потоками в многозадачных приложениях.
💡 Совет: Используйте
#Java #ExecutorCompletionService #ПараллельноеВыполнение #Многозадачность
ExecutorCompletionService — это инструмент для удобной работы с потоками, позволяющий эффективно управлять задачами, выполняющимися асинхронно, и получать результаты по мере их готовности. Он сочетает в себе возможности
ExecutorService и очередь для получения результатов выполнения задач. 📌 Преимущества ExecutorCompletionService:
1️⃣ Удобное управление задачами: позволяет управлять и отслеживать несколько асинхронных задач одновременно.
2️⃣ Получение результатов по мере выполнения: результаты задач можно получать в том порядке, в котором они завершены.
3️⃣ Обработка ошибок: позволяет перехватывать исключения, возникающие в процессе выполнения задач.
📌 Пример использования ExecutorCompletionService:
import java.util.concurrent.*;
public class ExecutorCompletionServiceExample {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executor = Executors.newFixedThreadPool(3);
ExecutorCompletionService<Integer> completionService = new ExecutorCompletionService<>(executor);
// Добавляем задачи в очередь
for (int i = 0; i < 5; i++) {
final int taskId = i;
completionService.submit(() -> {
// Задача выполняется
Thread.sleep(1000); // Эмулируем работу
return taskId * 2;
});
}
// Получаем результаты по мере их готовности
for (int i = 0; i < 5; i++) {
Future<Integer> result = completionService.take(); // Возвращает первый завершившийся результат
System.out.println("Задача завершена с результатом: " + result.get());
}
executor.shutdown();
}
}
📌 Как это работает:
1️⃣ Создаём
ExecutorCompletionService, передавая ему пул потоков. 2️⃣ Задачи отправляются в очередь с помощью метода
submit(). 3️⃣ Метод
take() извлекает завершённую задачу и её результат. 4️⃣ Метод
get() позволяет получить результат выполнения задачи. 📌 Когда использовать ExecutorCompletionService?
- Когда необходимо параллельно выполнить несколько задач и получить результаты по мере их завершения.
- В ситуациях, когда задачи могут занять разное время на выполнение.
- Для эффективного управления потоками в многозадачных приложениях.
💡 Совет: Используйте
ExecutorCompletionService для повышения производительности, когда важно обрабатывать результаты задач в порядке их завершения. #Java #ExecutorCompletionService #ПараллельноеВыполнение #Многозадачность
👍15❤3
