Java for Beginner
870 subscribers
1.01K photos
275 videos
14 files
1.69K links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Итерация и fail-fast семантика

Синхронизированные обертки не решают проблему итерации:
List<String> syncList = Collections.synchronizedList(new ArrayList<>());

// ОПАСНО: ConcurrentModificationException все еще возможен
for (String item : syncList) {
// Другой поток может модифицировать список
syncList.remove("someItem"); // Из другого потока
}



Для безопасной итерации требуется внешняя синхронизация:

List<String> syncList = Collections.synchronizedList(new ArrayList<>());

// Безопасная итерация
synchronized (syncList) {
Iterator<String> it = syncList.iterator();
while (it.hasNext()) {
String item = it.next();
process(item);
}
}




ConcurrentHashMap: Современный подход к параллельным отображениям


ConcurrentHashMap представляет собой фундаментально иную философию по сравнению с синхронизированными обертками.

Вместо блокировки всей структуры используется комбинация:
Fine-grained locking (тонкозернистые блокировки)
Lock-free алгоритмы для чтения
CAS операции (Compare-And-Swap)
Сегментирование (в версиях до Java 8)

В Java 8 архитектура была полностью переработана:
// Концептуальная структура с Java 8
public class ConcurrentHashMap<K,V> {
volatile Node<K,V>[] table;

static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
volatile V val;
volatile Node<K,V> next;
}

static final class TreeNode<K,V> extends Node<K,V> {
TreeNode<K,V> parent;
TreeNode<K,V> left;
TreeNode<K,V> right;
TreeNode<K,V> prev;
boolean red;
}
}


Инновации:
CAS для вставки: sun.misc.Unsafe.compareAndSwapObject
Tree bins: Преобразование в красно-черные деревья при длинных цепочках
Параллельные операции: forEach, search, reduce


Memory model и happens-before

ConcurrentHashMap обеспечивает строгие гарантии memory ordering:
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();

// Поток 1
map.put("key", 42); // Запись с memory barrier

// Путок 2
Integer value = map.get("key"); // Чтение с happens-before гарантиями
// Гарантированно увидит 42, если нет перезаписи


Atomicity guarantees
// Атомарные операции
map.putIfAbsent(key, value); // Вставить если отсутствует
map.replace(key, oldValue, newValue); // Заменить если совпадает
map.compute(key, (k, v) -> v == null ? 1 : v + 1); // Атомарное вычисление


Параллельные операции bulk
ConcurrentHashMap<String, Long> wordCounts = new ConcurrentHashMap<>();

// Параллельный forEach
wordCounts.forEach(1, // Параллелизм
(key, value) -> System.out.println(key + ":" + value));

// Поиск
String result = wordCounts.search(1,
(key, value) -> value > 1000 ? key : null);

// Свертка
long total = wordCounts.reduceValues(1, Long::sum);


Параметризация параллелизма
ConcurrentHashMap<String, Data> map = new ConcurrentHashMap<>(
16, // initial capacity
0.75f, // load factor
8 // concurrency level (оценочное количество потоков)
);



#Java #для_новичков #beginner #immutability #Collection #synchronizedList #ConcurrentHashMap #CopyOnWriteArrayList
👍4
Производительность в различных сценариях

Для сценариев с частым чтением ConcurrentHashMap показывает исключительную производительность:
Чтение полностью lock-free
Минимальный contention между читателями
Эффективное использование кэшей процессора

При частой записи производительность зависит от:

Качества хэш-функции
Количества коллизий
Наличия tree bins
Конкуренции за конкретные бакеты

В конкурентной среде точный размер постоянно меняется. ConcurrentHashMap использует приближенные методы:
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();

// Приближенный размер (O(1), но может быть неточным)
int approximateSize = map.size();

// Более точный (но дорогой) подсчет
int exactSize = map.mappingCount(); // Java 8+

// Проверка пустоты (эффективная)
boolean isEmpty = map.isEmpty();



CopyOnWriteArrayList: Оптимизация для read-mostly сценариев

CopyOnWriteArrayList основан на фундаментальном компромиссе: дорогая запись в обмен на безопасное и эффективное чтение. Этот подход заимствован из систем управления памятью и файловых систем, где копирование при записи является стандартным паттерном.


Архитектурные принципы

Неизменяемое состояние
public class CopyOnWriteArrayList<E> {
private transient volatile Object[] array;

final Object[] getArray() {
return array;
}

final void setArray(Object[] a) {
array = a;
}
}


Ключевые особенности:
Массив объявлен как volatile для обеспечения memory visibility
Все операции чтения работают с текущим массивом
Операции записи создают новую копию

Гарантии consistency

Итераторы обеспечивают strong consistency для snapshot:
Видят состояние на момент создания
Никогда не выбрасывают ConcurrentModificationException
Не поддерживают операцию remove() (UnsupportedOperationException)


Практические паттерны использования


Event listeners и наблюдатели
public class EventPublisher {
private final CopyOnWriteArrayList<EventListener> listeners =
new CopyOnWriteArrayList<>();

public void addListener(EventListener listener) {
listeners.add(listener); // Безопасно даже во время уведомлений
}

public void publish(Event event) {
for (EventListener listener : listeners) {
// Итерация по snapshot - безопасна
listener.onEvent(event);
}
}
}


Кэширование конфигураций
public class ConfigurationCache {
private volatile CopyOnWriteArrayList<Config> cache;

public ConfigurationCache() {
cache = new CopyOnWriteArrayList<>();
}

public void refresh() {
List<Config> newConfigs = loadConfigs();
// Атомарная замена всего кэша
cache = new CopyOnWriteArrayList<>(newConfigs);
}

public List<Config> getConfigs() {
return cache; // Безопасное чтение
}
}



Ограничения и альтернативы

Когда не использовать CopyOnWriteArrayList

Частые модификации: Большие коллекции с частыми изменениями
Реальные требования: Когда нужны актуальные данные, а не snapshot
Ограничения памяти: Когда копирование больших массивов непозволительно

Альтернативные подходы
// Для частых модификаций
List<String> frequentWrites = Collections.synchronizedList(new ArrayList<>());

// Для mixed workloads
ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();

// Для сценариев с преобладанием чтения
List<String> readMostly = new CopyOnWriteArrayList<>();



#Java #для_новичков #beginner #immutability #Collection #synchronizedList #ConcurrentHashMap #CopyOnWriteArrayList
👍3
Типичные ошибки многопоточного программирования с коллекциями

ConcurrentModificationException: Анатомия ошибки

ConcurrentModificationException возникает при обнаружении структурных изменений коллекции во время итерации.

Механизм основан на сравнении счетчика модификаций:
// Внутренний механизм ArrayList
protected transient int modCount = 0;

// В итераторе
int expectedModCount = modCount;

void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}


Типичные сценарии возникновения

Сценарий 1: Модификация во время итерации в одном потоке
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));

for (String item : list) { // Создается итератор
if (item.equals("B")) {
list.remove(item); // modCount++ → исключение!
}
}



Сценарий 2: Конкурентная модификация в разных потоках

// Поток 1
for (String item : sharedList) {
process(item); // Итерация
}

// Поток 2
sharedList.add("new"); // ConcurrentModificationException в потоке 1



NullPointerException в многопоточном контексте


NullPointerException в многопоточных сценариях часто является следствием race conditions, а не просто нулевых ссылок:
public class UnsafeCache {
private Map<String, Data> cache = new HashMap<>();

public Data get(String key) {
Data data = cache.get(key);
if (data == null) {
data = loadData(key); // Дорогая операция
cache.put(key, data); // Race condition!
}
return data; // Может вернуть null
}
}


Классический антипаттерн с небезопасной публикацией:
public class BrokenSingleton {
private static Data instance;

public static Data getInstance() {
if (instance == null) { // Первая проверка (без синхронизации)
synchronized (BrokenSingleton.class) {
if (instance == null) { // Вторая проверка
instance = new Data(); // Небезопасная публикация!
}
}
}
return instance; // Может вернуть частично инициализированный объект
}
}


Разные коллекции по-разному обрабатывают null:
// ConcurrentHashMap: запрещает null
ConcurrentHashMap<String, String> chm = new ConcurrentHashMap<>();
chm.put("key", null); // NullPointerException

// CopyOnWriteArrayList: разрешает null
CopyOnWriteArrayList<String> cowal = new CopyOnWriteArrayList<>();
cowal.add(null); // Допустимо

// Collections.synchronizedList: зависит от оборачиваемой коллекции
List<String> syncList = Collections.synchronizedList(new ArrayList<>());
syncList.add(null); // Допустимо для ArrayList



#Java #для_новичков #beginner #immutability #Collection #synchronizedList #ConcurrentHashMap #CopyOnWriteArrayList
👍2
Race conditions и data races

Race condition: Неправильное поведение из-за непредсказуемого порядка выполнения
Data race: Одновременный доступ к shared memory без proper synchronization

Пример race condition
public class Counter {
private int count;

public void increment() {
count++; // Неатомарная операция: read-modify-write
}
}

// Два потока вызывают increment() 1000 раз каждый
// Ожидаемый результат: 2000
// Фактический результат: что угодно между 1000 и 2000


Пример data race
public class VisibilityProblem {
private boolean ready = false;
private int value;

// Поток 1
public void writer() {
value = 42;
ready = true; // Без happens-before!
}

// Путок 2
public void reader() {
if (ready) {
System.out.println(value); // Может увидеть 0 вместо 42!
}
}
}



Deadlock, livelock и starvation

Deadlock с коллекциями
// Классический deadlock с synchronizedList
List<String> list1 = Collections.synchronizedList(new ArrayList<>());
List<String> list2 = Collections.synchronizedList(new ArrayList<>());

// Поток 1
synchronized (list1) {
synchronized (list2) { // Ждет list2
// Критическая секция
}
}

// Путок 2 (обратный порядок)
synchronized (list2) {
synchronized (list1) { // Ждет list1 → DEADLOCK!
// Критическая секция
}
}


Livelock в конкурентных алгоритмах

public class LivelockExample {
private final ConcurrentHashMap<String, Boolean> locks =
new ConcurrentHashMap<>();

public void process(String key) {
// Бесконечные попытки захвата "локера"
while (!locks.putIfAbsent(key, true)) {
Thread.yield(); // Livelock: постоянно уступаем, но не прогрессируем
}

try {
// Работа с ресурсом
} finally {
locks.remove(key);
}
}
}



Starvation в synchronized коллекциях

// Поток, постоянно читающий
synchronized (sharedList) {
// Долгая операция чтения
processAllElements(sharedList);
}

// Другие потоки не могут получить доступ для записи
// → Starvation писателей


#Java #для_новичков #beginner #immutability #Collection #synchronizedList #ConcurrentHashMap #CopyOnWriteArrayList
👍2
Что выведет код?

import java.util.concurrent.*;

public class Task301225 {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("a", 1);

Integer result = map.computeIfAbsent("b", k -> {
map.put("b", 2);
return map.get("b");
});

System.out.println(result);
System.out.println(map.get("b"));
}
}


#Tasks
👍1
Варианты ответа:
Anonymous Quiz
21%
2 2
7%
null null
14%
null 2
57%
Исключение
👍1
Вопрос с собеседований

Почему volatile не заменяет synchronized? 🤓

Ответ:

volatile
гарантирует видимость изменений, но не атомарность составных операций.

Например, count++ небезопасен даже с volatile. synchronized обеспечивает и видимость, и взаимное исключение, но дороже по производительности.


#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
История IT-технологий сегодня — 31 декабря


ℹ️ Кто родился в этот день

Не нашел(


🌐 Знаковые события

1879 – Томас Эдисон впервые демонстрирует публике лампы накаливания в Менло-Парке, штат Нью-Джерси.

1983 – Компания AT&T Bell System была расформирована правительством Соединенных Штатов .


#Biography #Birth_Date #Events #31Декабря
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Друзья и подписчики!

Вот и пришёл 2026 год 🎄

Нам вновь даны 365 дней — для достижения целей и задач, для реализации смелых надежд и по-настоящему больших планов.

В этот день, который символизирует начало нового года, особенно приятно осознавать, что мы вместе. 🤝

Да, у нас небольшое и не самое активное сообщество, но я по-прежнему верю: нас объединяет стремление становиться лучше и сильнее, профессионально расти, быть более востребованными и со временем — действительно незаменимыми специалистами.

Я искренне благодарен каждому, кто участвует в жизни канала: ставит лайки, пишет комментарии и приходит на встречи. ❤️

Именно для Вас канал продолжает жить и развиваться — без этого он давно бы умер.

Я твёрдо уверен, что когда наши парни дожмут врага на фронте и мы победим (а это неизбежно)💪, компании перестанут жить в режиме неопределённости. Страх сменится расчётом и рынок начнёт постепенно оживать. Вакансий станет больше, требования — адекватнее, а ценность реальной экспертизы снова выйдет на первый план.

И именно те, кто уже сегодня системно наращивает знания и практику, окажутся максимально востребованными в этот момент.

И именно поэтому, несмотря на все штормы и бури рынка вакансий, засилье автоматических фильтров, роботов и ЧСВшных HR, я хочу, чтобы в 2026 году каждый из вас окончательно и бесповоротно покорил Java и получил тот самый оффер на 500k в секунду 😎

Пусть это звучит иронично, но каждое усилие, каждый разобранный класс и каждая изученная библиотека реально приближают вас к этой цели.

В первые минуты нового года, оставляя за спиной трудности и сомнения, хочется пожелать вам простых, но важных вещей — удачи и терпения.👌
Удача пригодится при откликах на вакансии, а терпение — при подготовке и прохождении собеседований. 😄

Желаю всем здоровья, счастья, любви близких и надёжной поддержки друзей.

Пусть 2026 год принесёт не только профессиональные достижения, но и внутреннюю гармонию, ощущение устойчивости и уверенности в выбранном пути.

С Новым годом! 🌲
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11🍾3👍1👎1🤓1🆒11
История IT-технологий сегодня — 01 января


ℹ️ Кто родился в этот день

Ива́н Алексе́евич Вышнегра́дский (20 декабря 1831 [1 января 1832], Вышний Волочёк — 25 марта [6 апреля] 1895, Санкт-Петербург)русский учёный-механик и государственный деятель. Основоположник теории автоматического регулирования, почётный член Петербургской АН (1888)


🌐 Знаковые события

1801 – Джузеппе Пиацци открывает Цереру , самый большой и первый известный объект в поясе астероидов.

1983 — ARPANET сменила основной протокол с NCP на TCP/IP, что и привело к появлению современного Интернета.


#Biography #Birth_Date #Events #01Января
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2