Reviewed by Aditya Kumar · Last reviewed 2026-03-24
A Semaphore in Java is a counting semaphore that controls access to a shared resource by maintaining a set of "permits." It limits the number of threads that can concurrently access a critical section…
This easy-level Python/Coding question appears frequently in data engineering interviews at companies like Walmart. While less common, it tests deeper understanding that distinguishes strong candidates.
Start by clearly defining the core concept being asked about. Interviewers want to see that you understand the fundamentals before diving into implementation details. Structure your answer with a definition, then explain the practical application with a concise example. The expert answer includes a code example that demonstrates the implementation pattern.
A Semaphore in Java is a counting semaphore that controls access to a shared resource by maintaining a set of "permits." It limits the number of threads that can concurrently access a critical section or a finite pool of resources.
Semaphore(n)). Threads call acquire() to obtain a permit; if no permits are available, the thread blocks until one is released. After using the resource, threads call release() to return a permit. The tryAcquire() method offers a non-blocking attempt to get a permit. This mechanism provides crucial backpressure, preventing resource exhaustion (e.g., overwhelming a database or an API) and ensuring controlled access to finite resources. It's fundamental for bounding concurrency and protecting shared infrastructure within data processing applications.
Semaphore to ensure only a specified number of concurrent writes hit a Delta Lake table or Kafka topic, preventing performance degradation or resource contention. It's critical to always release the permit in a finally block to prevent resource leaks, even if an exception occurs. For production systems, consider fairness; new Semaphore(n, true) ensures threads acquire permits in the order they requested them, which can be vital for predictable throughput and avoiding thread starvation in long-running data pipelines.
import java.util.concurrent.Semaphore;
public class ApiRateLimiter {
private final Semaphore semaphore;
public ApiRateLimiter(int maxConcurrentCalls) {
this.semaphore = new Semaphore(maxConcurrentCalls);
}
public void makeApiCall() throws InterruptedException {
semaphore.acquire(); // Blocks if max calls reached
try {
// Logic to make the actual API call
System.out.println(Thread.currentThread().getName() + " making API call.");
Thread.sleep(100); // Simulate network latency/work
} finally {
semaphore.release(); // Always release the permit
}
}
}
In the interview, also mention its role in managing concurrent operations in distributed systems, such as limiting parallel tasks in a Spark job that interact with external services, or controlling the fan-out of data processing steps.
Pro-Move: tryAcquire with timeout. Red Flag: Forgetting release in finally.
Some links below are affiliate links. If you buy through them we may earn a small commission at no extra cost to you — it helps keep DataEngPrep free.
According to DataEngPrep.tech, this is one of the most frequently asked Python/Coding interview questions, reported at 1 company. DataEngPrep.tech maintains an editor-reviewed database of 1,863 data engineering interview questions across 7 categories.