DeployU
Interviews / Backend Engineering / How do you handle concurrency in Java?

How do you handle concurrency in Java?

conceptual Concurrency Interactive Quiz Code Examples

The Scenario

You are a backend engineer at a fintech company. You are building a new service that needs to handle a large number of concurrent requests.

You need to find a way to write your code so that it is thread-safe and that it does not have any race conditions.

The Challenge

Explain how you would handle concurrency in Java. What are the different concurrency primitives that you would use, and what are the key benefits of Java’s approach to concurrency?

Wrong Approach

A junior engineer might not be aware of the different concurrency primitives in Java. They might try to solve the problem by using a `synchronized` block for everything, which would not be very performant.

Right Approach

A senior engineer would have a deep understanding of the different concurrency primitives in Java. They would be able to explain how to use `synchronized` blocks, locks, and atomic variables to write thread-safe code. They would also have a clear plan for how to handle concurrency in a consistent and predictable way.

Step 1: Understand the Key Concurrency Primitives

PrimitiveDescription
synchronizedA keyword that can be used to create a mutually exclusive block of code.
LockAn interface that provides a more flexible way to create a mutually exclusive block of code.
AtomicA set of classes that provide atomic operations on a single variable.
volatileA keyword that can be used to indicate that a variable may be modified by multiple threads.
ExecutorAn interface for executing tasks in the background.

Step 2: Choose the Right Tool for the Job

Use CaseRecommended Primitive
Protecting a small block of codesynchronized
Protecting a large block of codeLock
Incrementing a counterAtomicInteger
Sharing a variable between threadsvolatile
Executing tasks in the backgroundExecutorService

Step 3: Code Examples

Here are some code examples that show how to use some of these primitives:

synchronized:

public class Counter {
    private int count;

    public synchronized void increment() {
        count++;
    }
}

Lock:

public class Counter {
    private int count;
    private final Lock lock = new ReentrantLock();

    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }
}

AtomicInteger:

public class Counter {
    private final AtomicInteger count = new AtomicInteger(0);

    public void increment() {
        count.incrementAndGet();
    }
}

Practice Question

You are building a high-performance application and need to protect a shared resource from concurrent access. Which of the following would be the most appropriate?