ProgrammingJava middle/backend developer

What do you know about working with threads in Java and how to ensure thread safety?

Pass interviews with Hintsage AI assistant

Answer.

In Java, working with threads is implemented through the Thread, Runnable classes, and packages from java.util.concurrent. Various synchronization mechanisms are used to ensure thread safety:

  • Synchronized blocks/methods (synchronized) allow multiple threads to access shared data without race conditions.
  • volatile guarantees visibility of variable changes between threads.
  • Classes from java.util.concurrent (for example, ReentrantLock, Semaphore, AtomicInteger, ConcurrentHashMap) provide more flexible synchronization methods.

Example of synchronization:

public class Counter { private int count = 0; public synchronized void increment() { count++; } public int getCount() { return count; } }

Example using atomic classes:

import java.util.concurrent.atomic.AtomicInteger; public class AtomicCounter { private AtomicInteger count = new AtomicInteger(0); public void increment() { count.incrementAndGet(); } public int getCount() { return count.get(); } }

Trick question.

Does the volatile keyword guarantee thread safety when incrementing an int counter?

Answer: No. volatile only ensures visibility of the value between threads, but not atomicity of operations. Incrementing is a non-atomic operation (count++ consists of reading, incrementing, and writing), so data loss can occur. For thread-safe incrementing, synchronization or classes like AtomicInteger are needed.

volatile int count = 0; // count++ is not thread-safe!

Examples of real errors due to lack of knowledge about the topic's nuances.


Story

In an online store, a bonus account was updated using a volatile counter. Under load, thousands of users were ordering products, and some bonuses were lost due to thread race on count++.


Story

An employee used a regular ArrayList as a shared buffer between a producer and consumer in a multithreaded application, resulting in ConcurrentModificationException. The solution was to use synchronized blocks or replace it with CopyOnWriteArrayList.


Story

In payment processing, the developer performed the operation "check and deduct amount" through two unrelated methods. Under high load, this led to double charging until atomic transactions and locks were implemented.