История IT-технологий сегодня — 03 января
ℹ️ Кто родился в этот день
Не нашел(
🌐 Знаковые события
1977 — произведён первый компьютер фирмы Apple.
2009 – Создатель системы, Сатоши Накамото, устанавливает первый блок блокчейна децентрализованной платежной системы Биткойн, называемый генезис-блоком.
#Biography #Birth_Date #Events #03Января
Не нашел(
1977 — произведён первый компьютер фирмы Apple.
2009 – Создатель системы, Сатоши Накамото, устанавливает первый блок блокчейна децентрализованной платежной системы Биткойн, называемый генезис-блоком.
#Biography #Birth_Date #Events #03Января
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Как Вы считаете, в 2026 году сможете устроиться на работу Java-разработчиком? А если уже работаете, то сменить место на более перспективное?
Anonymous Poll
28%
Да, конечно, я в этом уверен!
38%
Мне кажется шансы маленькие, но они точно есть!
23%
Не уверен, но по-моему повезет не всем...
10%
Уверен, что в этом году найму пи...ц. Надо что-то менять...
0%
Напишу свой вариант в комментариях
👍2
Можете меня поздравить 👏
Моя первая статья на хабре одобрена с 3-его,мать его, раза!)
Кому не лень, накидайте че там вместо лайков😉
Заранее спасибо☺️
#мои_статьи
Моя первая статья на хабре одобрена с 3-его,
Кому не лень, накидайте че там вместо лайков
Заранее спасибо
#мои_статьи
Please open Telegram to view this post
VIEW IN TELEGRAM
Хабр
Под капотом многопоточной синхронизации в Java: как потоки договариваются через Mark Word
Синхронизация в Java часто воспринимается как простая языковая конструкция — достаточно использовать ключевое слово synchronized , и код начинает «просто работать». На практике же на уровне JVM...
🔥12
История IT-технологий сегодня — 04 января
ℹ️ Кто родился в этот день
Не нашел(
🌐 Знаковые события
1959 — «Луна-1» становится первым в мире космическим аппаратом, достигшим окрестностей Луны.
1975 — Эта дата вышла за пределы 12-битного поля, которое использовалось в TOPS-10. В связи с этой ошибкой возникло множество проблем и сбоев, пока разрабатывался альтернативный формат.
2004 — Марсоход «Спирит» совершил посадку на Марсе.
#Biography #Birth_Date #Events #04Января
Не нашел(
1959 — «Луна-1» становится первым в мире космическим аппаратом, достигшим окрестностей Луны.
1975 — Эта дата вышла за пределы 12-битного поля, которое использовалось в TOPS-10. В связи с этой ошибкой возникло множество проблем и сбоев, пока разрабатывался альтернативный формат.
2004 — Марсоход «Спирит» совершил посадку на Марсе.
#Biography #Birth_Date #Events #04Января
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Не смог удержаться, взял к нам в канал)) Очень со смыслом и смешно 😂😂😂
https://t.me/Java_for_beginner_dev
#Mems
https://t.me/Java_for_beginner_dev
#Mems
🤓1 1
История IT-технологий сегодня — 05 января
ℹ️ Кто родился в этот день
Стивен Коул Клин ( / ˈ k l eɪ n i / KLAY -nee ; [ a ] 5 января 1909 — 25 января 1994) — американский математик и логик. Один из учеников Алонзо Чёрча, Клин, наряду с Розой Петер, Аланом Тьюрингом, Эмилем Постом и другими, наиболее известен как основатель раздела математической логики, известного как теория рекурсии, которая впоследствии помогла заложить основы теоретической информатики.
🌐 Знаковые события
1769 — Джеймс Уатт получает патент на свою паровую машину.
1969 – Космический зонд «Венера-5» запущен в 06:28:08 UTC с Байконура.
2005 — в Солнечной системе обнаружена карликовая планета Эрида.
#Biography #Birth_Date #Events #05Января
Стивен Коул Клин ( / ˈ k l eɪ n i / KLAY -nee ; [ a ] 5 января 1909 — 25 января 1994) — американский математик и логик. Один из учеников Алонзо Чёрча, Клин, наряду с Розой Петер, Аланом Тьюрингом, Эмилем Постом и другими, наиболее известен как основатель раздела математической логики, известного как теория рекурсии, которая впоследствии помогла заложить основы теоретической информатики.
1769 — Джеймс Уатт получает патент на свою паровую машину.
1969 – Космический зонд «Венера-5» запущен в 06:28:08 UTC с Байконура.
2005 — в Солнечной системе обнаружена карликовая планета Эрида.
#Biography #Birth_Date #Events #05Января
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Spring Boot 3.x + RabbitMQ: Продвинутая конфигурация
Введение: Современный стек для production
Spring Boot 3.x в сочетании с RabbitMQ представляет собой enterprise-уровневую платформу для построения event-driven систем. В 2025 году фокус сместился с базовой интеграции на production-готовые конфигурации, обеспечивающие безопасность, наблюдаемость и отказоустойчивость.
Spring Boot 3.3+ и RabbitMQ Starter: ключевые изменения
Spring Boot 3.3 существенно улучшил автоконфигурацию RabbitMQ:
Автоматическое определение кворумных очередей (Quorum Queues) как стандарта
Интеграция с Micrometer для детального мониторинга
Поддержка реактивных потоков через Project Reactor
Готовность к GraalVM native images из коробки
Минимальная конфигурация:
Конфигурация для production: критичные параметры
Для production обязательны:
TLS/SSL для шифрования трафика
mTLS (Mutual TLS) для аутентификации клиентов
OAuth2 или JWT для авторизации
Конфигурация mTLS в application.yaml:
Гарантии доставки
Spring Boot 3.3 предоставляет расширенный мониторинг через Micrometer:
Reactive RabbitMQ с Project Reactor
Реактивная модель идеальна для:
Высоконагруженных систем с тысячами соединений
Сценариев, требующих backpressure управления
Интеграции с другими реактивными компонентами (WebFlux, R2DBC)
#Java #middle #RabbitMQ
Введение: Современный стек для production
Spring Boot 3.x в сочетании с RabbitMQ представляет собой enterprise-уровневую платформу для построения event-driven систем. В 2025 году фокус сместился с базовой интеграции на production-готовые конфигурации, обеспечивающие безопасность, наблюдаемость и отказоустойчивость.
Spring Boot 3.3+ и RabbitMQ Starter: ключевые изменения
Spring Boot 3.3 существенно улучшил автоконфигурацию RabbitMQ:
Автоматическое определение кворумных очередей (Quorum Queues) как стандарта
Интеграция с Micrometer для детального мониторинга
Поддержка реактивных потоков через Project Reactor
Готовность к GraalVM native images из коробки
Минимальная конфигурация:
@Configuration
public class RabbitMQConfig {
@Bean
public CachingConnectionFactory connectionFactory(
@Value("${spring.rabbitmq.host}") String host) {
CachingConnectionFactory factory = new CachingConnectionFactory(host);
// Производственные настройки по умолчанию
factory.setPublisherConfirmType(CachingConnectionFactory.ConfirmType.CORRELATED);
factory.setPublisherReturns(true);
factory.setChannelCacheSize(25);
return factory;
}
}
Конфигурация для production: критичные параметры
Для production обязательны:
TLS/SSL для шифрования трафика
mTLS (Mutual TLS) для аутентификации клиентов
OAuth2 или JWT для авторизации
Конфигурация mTLS в application.yaml:
spring:
rabbitmq:
ssl:
enabled: true
algorithm: TLSv1.3
key-store: file:/etc/ssl/client-keystore.p12
key-store-password: ${KEYSTORE_PASSWORD}
key-store-type: PKCS12
trust-store: file:/etc/ssl/truststore.jks
trust-store-password: ${TRUSTSTORE_PASSWORD}
trust-store-type: JKS
verify-hostname: true
Гарантии доставки
spring:
rabbitmq:
# Подтверждения от брокера
publisher-confirm-type: correlated
publisher-returns: true
# Подтверждения от потребителя
listener:
simple:
acknowledge-mode: manual # Для полного контроля
prefetch: 10 # Балансировка нагрузки
retry:
enabled: true
max-attempts: 3
back-off:
initial-interval: 1s
multiplier: 2
Spring Boot 3.3 предоставляет расширенный мониторинг через Micrometer:
@Configuration
public class MonitoringConfig {
@Bean
public MeterRegistryCustomizer<MeterRegistry> rabbitMQMetrics() {
return registry -> {
// Кастомные метрики для RabbitMQ
registry.config().commonTags("application", "order-service");
};
}
@Bean
public RabbitTemplateMonitoring rabbitTemplateMonitoring(
RabbitTemplate rabbitTemplate,
MeterRegistry meterRegistry) {
// Мониторинг времени доставки
Timer timer = Timer.builder("rabbitmq.publish.duration")
.description("Time to publish message to RabbitMQ")
.register(meterRegistry);
rabbitTemplate.setObservationEnabled(true);
return new RabbitTemplateMonitoring(rabbitTemplate, timer);
}
}
Reactive RabbitMQ с Project Reactor
Реактивная модель идеальна для:
Высоконагруженных систем с тысячами соединений
Сценариев, требующих backpressure управления
Интеграции с другими реактивными компонентами (WebFlux, R2DBC)
#Java #middle #RabbitMQ
👍2🔥1
Конфигурация реактивного RabbitMQ:
Реактивный consumer с обработкой backpressure:
GraalVM native поддержка
Spring Boot 3.3 значительно улучшил поддержку GraalVM native images:
Необходимые зависимости:
Конфигурация для RabbitMQ в native-образе:
Проблемы и решения для native-сборок:
Reflection: RabbitMQ клиент использует reflection для создания соединений
Динамическая загрузка классов: Требует явного конфигурирования в native-image
Сетевые операции: Нативный образ требует явного разрешения сетевых операций
#Java #middle #RabbitMQ
@Configuration
@EnableReactiveRabbit
public class ReactiveRabbitConfig {
@Bean
public ReactiveRabbitTemplate reactiveRabbitTemplate(
ReactiveRabbitConnectionFactory factory) {
ReactiveRabbitTemplate template = new ReactiveRabbitTemplate(factory);
// Настройки backpressure
template.setObservationEnabled(true);
template.setUsePublisherConfirm(true);
return template;
}
@Bean
public ReactiveRabbitListenerContainerFactory containerFactory(
ReactiveRabbitConnectionFactory factory) {
ReactiveRabbitListenerContainerFactory containerFactory =
new ReactiveRabbitListenerContainerFactory();
containerFactory.setConnectionFactory(factory);
// Обработка ошибок в реактивном стиле
containerFactory.setErrorHandler(errorHandler());
return containerFactory;
}
private ReactiveErrorHandler errorHandler() {
return new ReactiveErrorHandler() {
@Override
public Mono<Void> handleError(Throwable throwable,
Acknowledgement acknowledgement) {
log.error("Reactive consumption error", throwable);
return acknowledgement.nack(false); // Не requeue при фатальных ошибках
}
};
}
}
Реактивный consumer с обработкой backpressure:
@Component
public class OrderEventConsumer {
@ReactiveRabbitListener(queues = "orders.queue")
public Mono<Void> processOrder(OrderEvent event,
Channel channel,
@Header(AmqpHeaders.DELIVERY_TAG) long tag) {
return Mono.fromCallable(() -> {
// Обработка события
return processOrderInternal(event);
})
.doOnSuccess(result -> {
// Ручное подтверждение
channel.basicAck(tag, false);
})
.doOnError(error -> {
// Логика повторной обработки
channel.basicNack(tag, false, shouldRequeue(error));
})
.then();
}
}
GraalVM native поддержка
Spring Boot 3.3 значительно улучшил поддержку GraalVM native images:
Необходимые зависимости:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aot</artifactId>
</dependency>
<dependency>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
</dependency>
Конфигурация для RabbitMQ в native-образе:
@NativeHint(
types = {
@TypeHint(types = {
com.rabbitmq.client.impl.AMQConnection.class,
com.rabbitmq.client.impl.recovery.AutorecoveringConnection.class,
// Критичные классы для RabbitMQ клиента
})
},
initialization = {
@InitializationHint(
types = com.rabbitmq.client.impl.AMQConnection.class,
initTime = InitializationTime.BUILD
)
}
)
@Configuration
public class RabbitMQNativeConfig {
// Явное объявление бинов, необходимых в runtime
@Bean
@RuntimeHint
public ConnectionFactory connectionFactory() {
// Фабрика должна создаваться с явными типами
return new CachingConnectionFactory();
}
}
Проблемы и решения для native-сборок:
Reflection: RabbitMQ клиент использует reflection для создания соединений
Динамическая загрузка классов: Требует явного конфигурирования в native-image
Сетевые операции: Нативный образ требует явного разрешения сетевых операций
#Java #middle #RabbitMQ
👍3🔥1
Контейнеризация: health checks и liveness probes
Spring Boot Actuator предоставляет расширенные health indicators для RabbitMQ:
Кастомный health indicator для бизнес-логики:
Kubernetes liveness и readiness probes
Security: продвинутые сценарии
OAuth2 с Resource Server
#Java #middle #RabbitMQ
Spring Boot Actuator предоставляет расширенные health indicators для RabbitMQ:
management:
endpoints:
web:
exposure:
include: health,metrics,prometheus
endpoint:
health:
show-details: always
probes:
enabled: true
health:
rabbit:
enabled: true
livenessstate:
enabled: true
readinessstate:
enabled: true
Кастомный health indicator для бизнес-логики:
@Component
public class RabbitMQBusinessHealthIndicator
implements HealthIndicator {
private final RabbitAdmin rabbitAdmin;
private final MeterRegistry meterRegistry;
public RabbitMQBusinessHealthIndicator(RabbitAdmin rabbitAdmin,
MeterRegistry meterRegistry) {
this.rabbitAdmin = rabbitAdmin;
this.meterRegistry = meterRegistry;
}
@Override
public Health health() {
try {
// Проверка критичных очередей
Properties queueProperties = rabbitAdmin.getQueueProperties("orders.queue");
if (queueProperties == null) {
return Health.down()
.withDetail("error", "Critical queue not found")
.build();
}
int messageCount = (int) queueProperties.get("QUEUE_MESSAGE_COUNT");
// Проверка на переполнение
if (messageCount > 10000) {
return Health.down()
.withDetail("warning", "Queue backlog too high")
.withDetail("messageCount", messageCount)
.build();
}
return Health.up()
.withDetail("queueStatus", "healthy")
.withDetail("messageCount", messageCount)
.build();
} catch (Exception e) {
return Health.down(e).build();
}
}
}
Kubernetes liveness и readiness probes
# Kubernetes deployment конфигурация
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: order-service
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 90 # Учитываем старт Spring Boot 3.x
periodSeconds: 15
failureThreshold: 3
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 30
periodSeconds: 5
successThreshold: 2
failureThreshold: 5
startupProbe:
httpGet:
path: /actuator/health/startup
port: 8080
failureThreshold: 30 # Долгий старт допустим
periodSeconds: 10
Security: продвинутые сценарии
OAuth2 с Resource Server
@Configuration
@EnableWebSecurity
public class RabbitMQSecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authz -> authz
.requestMatchers("/actuator/**").permitAll()
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> jwt
.jwtAuthenticationConverter(jwtAuthenticationConverter())
)
);
return http.build();
}
@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtGrantedAuthoritiesConverter converter = new JwtGrantedAuthoritiesConverter();
converter.setAuthorityPrefix("RABBITMQ_");
converter.setAuthoritiesClaimName("rabbitmq_roles");
JwtAuthenticationConverter jwtConverter = new JwtAuthenticationConverter();
jwtConverter.setJwtGrantedAuthoritiesConverter(converter);
return jwtConverter;
}
}
#Java #middle #RabbitMQ
👍2🔥1
Интеграция OAuth2 с RabbitTemplate:
Spring Cloud Vault предоставляет seamless интеграцию:
Динамическое получение credentials:
mTLS с автоматической ротацией сертификатов
#Java #middle #RabbitMQ
@Component
public class OAuth2RabbitTemplateDecorator {
private final ReactiveClientRegistrationRepository clientRegistrationRepository;
public OAuth2RabbitTemplateDecorator(
ReactiveClientRegistrationRepository clientRegistrationRepository) {
this.clientRegistrationRepository = clientRegistrationRepository;
}
public Mono<RabbitTemplate> decorateWithOAuth2(RabbitTemplate template) {
return clientRegistrationRepository
.findByRegistrationId("rabbitmq")
.flatMap(clientRegistration -> {
// Получение OAuth2 токена для RabbitMQ
return retrieveAccessToken(clientRegistration);
})
.map(accessToken -> {
// Декорация сообщений с токеном
template.addBeforePublishPostProcessors(message -> {
message.getMessageProperties()
.setHeader("Authorization", "Bearer " + accessToken.getTokenValue());
return message;
});
return template;
});
}
}
Spring Cloud Vault предоставляет seamless интеграцию:
spring:
cloud:
vault:
host: ${VAULT_HOST}
port: 8200
scheme: https
authentication: APPROLE
app-role:
role-id: ${VAULT_ROLE_ID}
secret-id: ${VAULT_SECRET_ID}
kv:
backend: kv-v2
default-context: rabbitmq/production
Динамическое получение credentials:
@Configuration
public class VaultRabbitMQConfig {
@Bean
@VaultPropertySource(
value = "rabbitmq/production/credentials",
renewal = Renewal.ROTATE
)
public PropertySource<?> vaultPropertySource() {
return new MapPropertySource("vault-rabbitmq", Map.of());
}
@Bean
@RefreshScope
public ConnectionFactory connectionFactory(
@Value("${spring.rabbitmq.vault.username}") String username,
@Value("${spring.rabbitmq.vault.password}") String password) {
CachingConnectionFactory factory = new CachingConnectionFactory();
factory.setUsername(username);
factory.setPassword(password);
// Автоматическое обновление при rotation credentials
factory.setConnectionListeners(Collections.singletonList(connection -> {
log.info("RabbitMQ connection updated with new credentials");
}));
return factory;
}
}
mTLS с автоматической ротацией сертификатов
@Configuration
public class MTLSConfig {
@Bean
@Scheduled(fixedDelay = 3600000) // Каждый час
public void rotateMTLSCertificates() {
// Автоматическая ротация сертификатов mTLS
// Интеграция с cert-manager или аналогичным решением
}
@Bean
public SslContextFactory sslContextFactory(VaultTemplate vaultTemplate) {
return SslContextFactory.builder()
.keyManager(keyManagerFromVault(vaultTemplate))
.trustManager(trustManagerFromVault(vaultTemplate))
.protocol("TLSv1.3")
.build();
}
private KeyManager keyManagerFromVault(VaultTemplate vaultTemplate) {
// Получение клиентского сертификата из Vault
VaultResponse response = vaultTemplate.read("pki/issue/rabbitmq-client");
byte[] certificate = Base64.getDecoder()
.decode(response.getData().get("certificate").toString());
byte[] privateKey = Base64.getDecoder()
.decode(response.getData().get("private_key").toString());
return loadKeyManager(certificate, privateKey);
}
}
#Java #middle #RabbitMQ
👍3🔥1
Что выведет код?
#Tasks
public class Task050126 {
public static void main(String[] args) throws InterruptedException {
Counter c1 = new Counter();
Counter c2 = new Counter();
Thread t1 = new Thread(() -> c1.increment());
Thread t2 = new Thread(() -> c2.increment());
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(Counter.count);
}
static class Counter {
static int count = 0;
private final Object lock = new Object();
public void increment() {
for (int i = 0; i < 100000; i++) {
synchronized (lock) {
count++;
}
}
}
}
}#Tasks
👍4
👍3 3
Вопрос с собеседований
Когда ForkJoinPool может ухудшить производительность?🤓
Ответ:
Если задачи блокирующие (I/O, synchronized), ForkJoinPool теряет эффективность.
Он рассчитан на CPU-bound задачи. Блокировки приводят к starvation и снижению параллелизма, особенно при использовании parallelStream.
#собеседование
Когда ForkJoinPool может ухудшить производительность?
Ответ:
Он рассчитан на CPU-bound задачи. Блокировки приводят к starvation и снижению параллелизма, особенно при использовании parallelStream.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
История IT-технологий сегодня — 06 января
ℹ️ Кто родился в этот день
Не нашел(
🌐 Знаковые события
2015 — открытие экзопланеты с самым высоким Индексом подобия Земле — Kepler-438 b.
#Biography #Birth_Date #Events #06Января
Не нашел(
2015 — открытие экзопланеты с самым высоким Индексом подобия Земле — Kepler-438 b.
#Biography #Birth_Date #Events #06Января
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Раздел 6. Коллекции в Java
Глава 8. Дополнительные аспекты коллекций
Практика: В «Библиотеке» сделать коллекцию книг потокобезопасной (CopyOnWriteArrayList). Реализовать неизменяемый список популярных книг для чтения
Перед началом убедитесь, что проект готов, и вспомните ключевые концепции:
CopyOnWriteArrayList: Thread-safe версия List, где модификации создают копию массива (copy-on-write), а чтение — без locks. Идеально для read-heavy сценариев (много чтения, мало записи).
Преимущества: Безопасность без синхронизации, итераторы не fail-fast (не бросают ConcurrentModificationException при mod).
Недостатки: Высокий overhead на память и время для модификаций (копия всего списка), не подходит для write-heavy.
Неизменяемые коллекции: Collections.unmodifiableList делает List read-only — методы mod бросают UnsupportedOperationException. Полезно для constants или защиты данных.
Импорты: java.util.concurrent.CopyOnWriteArrayList, java.util.Collections.
Откройте проект
Запустите IDE, откройте LibraryProject. Проверьте List<Book> books, методы addBook, printAllBooks и т.д.
Импортируйте пакеты: В Library.java добавьте import java.util.concurrent.CopyOnWriteArrayList; и import java.util.Collections;. IDE поможет.
Планирование: Мы изменим поле books на CopyOnWriteArrayList, добавим метод для создания неизменяемого списка популярных книг и протестируем в multi-thread (опционально).
Замена List на CopyOnWriteArrayList для потокобезопасности
CopyOnWriteArrayList — отличный выбор для библиотеки, где чтение (поиск, вывод) частое, а запись (добавление книг) редкое. Это сделает коллекцию thread-safe без manual locks.
Измените поле books
В классе Library замените private List<Book> books = new ArrayList<>(); на private CopyOnWriteArrayList<Book> books = new CopyOnWriteArrayList<>();.
Это обеспечит thread-safety: при add/remove создается копия внутреннего массива, читатели видят snapshot.
Обновите конструктор Library
Если инициализация в конструкторе — обновите на CopyOnWriteArrayList.
Обновите метод addBook(Book book)
Используйте books.add(book); — это thread-safe (копия под капотом).
Добавьте проверку: if (book == null) return; или бросьте IllegalArgumentException.
Выведите сообщение о добавлении.
Обновите методы, использующие books
В printAllBooks() или findBookByTitle используйте for-each или Iterator — они работают на snapshot, безопасны при параллельных mod.
В removeBookByIndex(int index): books.remove(index); — thread-safe.
Реализация неизменяемого списка популярных книг
Неизменяемый список — это read-only view, полезный для "популярных" книг, которые не должны изменяться.
Добавьте поле для популярных книг:
В Library добавьте приватное поле List<Book> popularBooks = new ArrayList<>();.
В конструкторе или методе initPopularBooks() добавьте 3-5 статических книг (new Book("1984", "Orwell", 1949) и т.д.).
Сделайте список неизменяемым:
После заполнения popularBooks присвойте ему Collections.unmodifiableList(popularBooks);.
Теперь методы mod (add, remove) бросят UnsupportedOperationException.
Добавьте метод getPopularBooks():
Возвращайте unmodifiable список — public List<Book> getPopularBooks() { return popularBooks; }.
Это безопасно — внешний код не сможет изменить.
Добавьте метод printPopularBooks():
Переберите unmodifiable список и выведите детали книг.
Попробуйте в Main popularBooks.add(new Book(...)) — поймайте исключение.
#Java #для_новичков #beginner #immutability #Collection #synchronizedList #ConcurrentHashMap #CopyOnWriteArrayList #Практика
Глава 8. Дополнительные аспекты коллекций
Практика: В «Библиотеке» сделать коллекцию книг потокобезопасной (CopyOnWriteArrayList). Реализовать неизменяемый список популярных книг для чтения
Перед началом убедитесь, что проект готов, и вспомните ключевые концепции:
CopyOnWriteArrayList: Thread-safe версия List, где модификации создают копию массива (copy-on-write), а чтение — без locks. Идеально для read-heavy сценариев (много чтения, мало записи).
Преимущества: Безопасность без синхронизации, итераторы не fail-fast (не бросают ConcurrentModificationException при mod).
Недостатки: Высокий overhead на память и время для модификаций (копия всего списка), не подходит для write-heavy.
Неизменяемые коллекции: Collections.unmodifiableList делает List read-only — методы mod бросают UnsupportedOperationException. Полезно для constants или защиты данных.
Импорты: java.util.concurrent.CopyOnWriteArrayList, java.util.Collections.
Откройте проект
Запустите IDE, откройте LibraryProject. Проверьте List<Book> books, методы addBook, printAllBooks и т.д.
Импортируйте пакеты: В Library.java добавьте import java.util.concurrent.CopyOnWriteArrayList; и import java.util.Collections;. IDE поможет.
Планирование: Мы изменим поле books на CopyOnWriteArrayList, добавим метод для создания неизменяемого списка популярных книг и протестируем в multi-thread (опционально).
Замена List на CopyOnWriteArrayList для потокобезопасности
CopyOnWriteArrayList — отличный выбор для библиотеки, где чтение (поиск, вывод) частое, а запись (добавление книг) редкое. Это сделает коллекцию thread-safe без manual locks.
Измените поле books
В классе Library замените private List<Book> books = new ArrayList<>(); на private CopyOnWriteArrayList<Book> books = new CopyOnWriteArrayList<>();.
Это обеспечит thread-safety: при add/remove создается копия внутреннего массива, читатели видят snapshot.
Обновите конструктор Library
Если инициализация в конструкторе — обновите на CopyOnWriteArrayList.
Обновите метод addBook(Book book)
Используйте books.add(book); — это thread-safe (копия под капотом).
Добавьте проверку: if (book == null) return; или бросьте IllegalArgumentException.
Выведите сообщение о добавлении.
Обновите методы, использующие books
В printAllBooks() или findBookByTitle используйте for-each или Iterator — они работают на snapshot, безопасны при параллельных mod.
В removeBookByIndex(int index): books.remove(index); — thread-safe.
Реализация неизменяемого списка популярных книг
Неизменяемый список — это read-only view, полезный для "популярных" книг, которые не должны изменяться.
Добавьте поле для популярных книг:
В Library добавьте приватное поле List<Book> popularBooks = new ArrayList<>();.
В конструкторе или методе initPopularBooks() добавьте 3-5 статических книг (new Book("1984", "Orwell", 1949) и т.д.).
Сделайте список неизменяемым:
После заполнения popularBooks присвойте ему Collections.unmodifiableList(popularBooks);.
Теперь методы mod (add, remove) бросят UnsupportedOperationException.
Добавьте метод getPopularBooks():
Возвращайте unmodifiable список — public List<Book> getPopularBooks() { return popularBooks; }.
Это безопасно — внешний код не сможет изменить.
Добавьте метод printPopularBooks():
Переберите unmodifiable список и выведите детали книг.
Попробуйте в Main popularBooks.add(new Book(...)) — поймайте исключение.
#Java #для_новичков #beginner #immutability #Collection #synchronizedList #ConcurrentHashMap #CopyOnWriteArrayList #Практика
👍4
Тестирование и отладка (объемно)
Базовое тестирование:
В Main добавьте книги, вызовите printAllBooks — всё как раньше.
Неизменяемость тест:
В Main получите getPopularBooks(), попробуйте add/remove — UnsupportedOperationException.
Переберите и выведите — чтение работает.
Отладка нюансов:
В CopyOnWriteArrayList добавьте breakpoint в add — увидите копию массива.
Тестируйте с большим размером (1000 элементов) — замерьте время (System.nanoTime()) для add в multi-thread.
Ловушки: CopyOnWriteArrayList slow для write-heavy — если много добавлений, используйте synchronized List.
Эксперименты (объемно и превышает текущий уровень экспертизы):
Замените на synchronizedList(new ArrayList<>()) — протестируйте thread-safety, но заметьте locks (медленнее для read-heavy).
Добавьте метод addPopularBook(Book book) — но сделайте так, чтобы он работал только до unmodifiable (или используйте builder для init).
Тестируйте с null — CopyOnWriteArrayList позволяет null элементы.
В multi-thread добавьте System.out в add/print — увидите interleaving, но без ошибок.
Измерьте память (Runtime.getRuntime().totalMemory()) перед/после многих add — увидите overhead копий в CopyOnWrite.
Работу данных коллекций мы будем проверять когда дойдем до многопоточности в java.
#Java #для_новичков #beginner #immutability #Collection #synchronizedList #ConcurrentHashMap #CopyOnWriteArrayList #Практика
Базовое тестирование:
В Main добавьте книги, вызовите printAllBooks — всё как раньше.
Неизменяемость тест:
В Main получите getPopularBooks(), попробуйте add/remove — UnsupportedOperationException.
Переберите и выведите — чтение работает.
Отладка нюансов:
В CopyOnWriteArrayList добавьте breakpoint в add — увидите копию массива.
Тестируйте с большим размером (1000 элементов) — замерьте время (System.nanoTime()) для add в multi-thread.
Ловушки: CopyOnWriteArrayList slow для write-heavy — если много добавлений, используйте synchronized List.
Эксперименты (объемно и превышает текущий уровень экспертизы):
Замените на synchronizedList(new ArrayList<>()) — протестируйте thread-safety, но заметьте locks (медленнее для read-heavy).
Добавьте метод addPopularBook(Book book) — но сделайте так, чтобы он работал только до unmodifiable (или используйте builder для init).
Тестируйте с null — CopyOnWriteArrayList позволяет null элементы.
В multi-thread добавьте System.out в add/print — увидите interleaving, но без ошибок.
Измерьте память (Runtime.getRuntime().totalMemory()) перед/после многих add — увидите overhead копий в CopyOnWrite.
Работу данных коллекций мы будем проверять когда дойдем до многопоточности в java.
#Java #для_новичков #beginner #immutability #Collection #synchronizedList #ConcurrentHashMap #CopyOnWriteArrayList #Практика
👍3
👍2
