Prepare Interview

Mock Exams

Make Homepage

Bookmark this page

Subscribe Email Address

Java Concurrency Concepts Tutorial

1. What is the difference between the Runnable and Callable interfaces in Java?

Answer: The main difference is that Callable can return a result and throw exceptions, whereas Runnable cannot.


import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class CallableExample implements Callable<String> {
  public String call() throws Exception {
    return "Hello from Callable!";
  }

  public static void main(String[] args) throws Exception {
    ExecutorService executorService = Executors.newSingleThreadExecutor();
    Future<String> result = executorService.submit(new CallableExample());
    System.out.println(result.get()); // Output: Hello from Callable!
    executorService.shutdown();
  }
}
    

2. Explain the difference between the synchronized and volatile keywords in Java.

Answer: Synchronized ensures exclusive access to a resource, while volatile guarantees visibility of changes across threads.


public class SynchronizedVsVolatile {
  private static int counter = 0;

  // Synchronized method
  public synchronized void increment() {
    counter++;
  }

  // Volatile variable
  private volatile boolean flag = false;

  public void setFlag() {
    flag = true;
  }
}
    

3. How can you achieve thread-safety in Java?

Answer: Thread-safety can be achieved using synchronization (e.g., synchronized methods or blocks), using concurrent data structures, or using the `java.util.concurrent` library.


import java.util.concurrent.atomic.AtomicInteger;

public class ThreadSafetyExample {
  private int nonAtomicCounter = 0;
  private AtomicInteger atomicCounter = new AtomicInteger(0);

  // Synchronized method
  public synchronized void incrementNonAtomicCounter() {
    nonAtomicCounter++;
  }

  // Atomic operation
  public void incrementAtomicCounter() {
    atomicCounter.incrementAndGet();
  }
}
    

4. What is the purpose of the `join` method in Java threads?

Answer: The `join` method is used to wait for a thread to complete its execution before proceeding to the next steps in the program.


public class JoinExample {
  public static void main(String[] args) throws InterruptedException {
    Thread thread1 = new Thread(() -> {
      // Some time-consuming task
    });

    Thread thread2 = new Thread(() -> {
      // Another task
    });

    thread1.start();
    thread2.start();

    thread1.join(); // Wait for thread1 to finish
    thread2.join(); // Wait for thread2 to finish

    System.out.println("All threads have completed.");
  }
}
    

5. Explain the concept of the `Executor` framework in Java concurrency.

Answer: The `Executor` framework provides a higher-level replacement for managing threads, allowing the separation of task submission and execution policies.


import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecutorFrameworkExample {
  public static void main(String[] args) {
    ExecutorService executorService = Executors.newFixedThreadPool(3);

    for (int i = 0; i < 5; i++) {
      final int taskNumber = i;
      executorService.execute(() -> System.out.println("Task " + taskNumber + " executed by " + Thread.currentThread().getName()));
    }

    executorService.shutdown();
  }
}
    

6. What is the purpose of the `synchronized` keyword in Java?

Answer: The `synchronized` keyword is used to control access to shared resources by multiple threads, ensuring that only one thread can access the critical section at a time.


public class SynchronizedExample {
  private int sharedCounter = 0;

  // Synchronized method
  public synchronized void incrementCounter() {
    sharedCounter++;
  }
}
    

7. Explain the concept of the `ReentrantLock` in Java concurrency.

Answer: `ReentrantLock` is a synchronization mechanism that allows a thread to hold the lock multiple times, enabling reentrant locking.


import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockExample {
  private Lock lock = new ReentrantLock();

  public void performTask() {
    lock.lock();
    try {
      // Critical section
    } finally {
      lock.unlock();
    }
  }
}
    

8. What is the significance of the `volatile` keyword in Java?

Answer: The `volatile` keyword ensures that a variable's value is always read from and written to the main memory, preventing thread-local caching of the variable.


public class VolatileExample {
  private volatile boolean flag = false;

  public void setFlag() {
    flag = true;
  }
}
    

9. How does the `CountDownLatch` class work in Java concurrency?

Answer: `CountDownLatch` is a synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.


import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {
  public static void main(String[] args) throws InterruptedException {
    CountDownLatch latch = new CountDownLatch(2);

    // Worker threads
    new Thread(() -> {
      // Task 1
      latch.countDown();
    }).start();

    new Thread(() -> {
      // Task 2
      latch.countDown();
    }).start();

    // Main thread waits for tasks to complete
    latch.await();
    System.out.println("All tasks have completed.");
  }
}
    

10. Explain the concept of the `BlockingQueue` interface in Java.

Answer: `BlockingQueue` is an interface that represents a queue that supports blocking operations, allowing threads to wait until space is available or an element is retrieved.


import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class BlockingQueueExample {
  public static void main(String[] args) throws InterruptedException {
    BlockingQueue<Integer> queue = new LinkedBlockingQueue<>();

    // Producer
    new Thread(() -> {
      try {
        queue.put(1);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }).start();

    // Consumer
    new Thread(() -> {
      try {
        int value = queue.take();
        System.out.println("Consumed: " + value);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }).start();
  }
}
    

11. Explain the concept of the `Semaphore` in Java concurrency.

Answer: `Semaphore` is a synchronization construct that controls access to a shared resource by limiting the number of threads that can access it simultaneously.


import java.util.concurrent.Semaphore;

public class SemaphoreExample {
  private Semaphore semaphore = new Semaphore(2); // Allow 2 permits

  public void accessResource() throws InterruptedException {
    semaphore.acquire(); // Acquire a permit
    try {
      // Access the shared resource
    } finally {
      semaphore.release(); // Release the permit
    }
  }
}
    

12. What is the purpose of the `CyclicBarrier` class in Java?

Answer: `CyclicBarrier` is a synchronization aid that allows a set of threads to wait for each other to reach a common barrier point, and then proceed together.


import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierExample {
  private static final int THREAD_COUNT = 3;
  private CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT);

  public void performTask() {
    try {
      // Task execution
      barrier.await(); // Wait for other threads
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
    

13. How can deadlock be prevented in a multi-threaded Java application?

Answer: Deadlock prevention involves strategies such as avoiding circular waits, using a consistent order when acquiring multiple locks, and setting a timeout for lock acquisition.


// Example of avoiding circular waits
public class DeadlockPreventionExample {
  private static final Object lock1 = new Object();
  private static final Object lock2 = new Object();

  public void method1() {
    synchronized (lock1) {
      // Critical section
      synchronized (lock2) {
        // Critical section
      }
    }
  }

  public void method2() {
    synchronized (lock2) {
      // Critical section
      synchronized (lock1) {
        // Critical section
      }
    }
  }
}
    

14. What is the `ThreadLocal` class in Java?

Answer: `ThreadLocal` is a class that provides thread-local variables, allowing each thread to have its own copy of a variable without affecting other threads.


public class ThreadLocalExample {
  private static final ThreadLocal<String> threadLocalVariable = new ThreadLocal<>();

  public void setThreadLocalValue(String value) {
    threadLocalVariable.set(value);
  }

  public String getThreadLocalValue() {
    return threadLocalVariable.get();
  }
}
    

15. Explain the purpose of the `Thread.sleep()` method in Java.

Answer: The `Thread.sleep()` method is used to temporarily pause the execution of a thread, allowing other threads to run or introducing a delay in the program.


public class ThreadSleepExample {
  public static void main(String[] args) {
    try {
      System.out.println("Task 1");
      Thread.sleep(2000); // Sleep for 2 seconds
      System.out.println("Task 2");
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}
    

16. How does the `Thread.yield()` method work in Java?

Answer: The `Thread.yield()` method is a hint to the scheduler that the current thread is willing to yield its current use of a processor, allowing other threads to run.


public class ThreadYieldExample {
  public static void main(String[] args) {
    Thread thread1 = new Thread(() -> {
      for (int i = 0; i < 5; i++) {
        System.out.println("Thread 1: " + i);
        Thread.yield(); // Yield to other threads
      }
    });

    Thread thread2 = new Thread(() -> {
      for (int i = 0; i < 5; i++) {
        System.out.println("Thread 2: " + i);
        Thread.yield(); // Yield to other threads
      }
    });

    thread1.start();
    thread2.start();
  }
}
    

17. Explain the concept of the `ReadWriteLock` in Java concurrency.

Answer: `ReadWriteLock` is an interface that provides a way to implement a lock mechanism where multiple threads can read a resource simultaneously, but only one thread can write to the resource at a time.


import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockExample {
  private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
  private int sharedResource = 0;

  public int readFromResource() {
    readWriteLock.readLock().lock();
    try {
      return sharedResource;
    } finally {
      readWriteLock.readLock().unlock();
    }
  }

  public void writeToResource(int value) {
    readWriteLock.writeLock().lock();
    try {
      sharedResource = value;
    } finally {
      readWriteLock.writeLock().unlock();
    }
  }
}
    

18. What is the purpose of the `ScheduledExecutorService` in Java?

Answer: `ScheduledExecutorService` is an interface that extends `ExecutorService` and provides methods to schedule tasks for future execution with specified delays or at fixed rates.


import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduledExecutorServiceExample {
  public static void main(String[] args) {
    ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);

    // Schedule a task to run every 1 second
    executorService.scheduleAtFixedRate(() -> {
      System.out.println("Task executed at " + System.currentTimeMillis());
    }, 0, 1, TimeUnit.SECONDS);
  }
}
    

19. Explain the concept of the `CompletableFuture` class in Java.

Answer: `CompletableFuture` is a class that represents a promise of a future result and provides a flexible way to compose, combine, and perform asynchronous operations.


import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class CompletableFutureExample {
  public static void main(String[] args) throws ExecutionException, InterruptedException {
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello")
      .thenApplyAsync(s -> s + " CompletableFuture")
      .thenApply(String::toUpperCase);

    System.out.println(future.get()); // Output: HELLO COMPLETABLEFUTURE
  }
}
    

20. How does the `ForkJoinPool` class work in Java?

Answer: `ForkJoinPool` is a framework for parallelizing recursive tasks, particularly those that can be broken down into smaller independent tasks.


import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;

public class ForkJoinPoolExample extends RecursiveTask<Integer> {
  private static final int THRESHOLD = 5;
  private int[] array;
  private int start;
  private int end;

  public ForkJoinPoolExample(int[] array, int start, int end) {
    this.array = array;
    this.start = start;
    this.end = end;
  }

  @Override
  protected Integer compute() {
    if (end - start <= THRESHOLD) {
      // Perform the computation
      return 0;
    } else {
      int mid = (start + end) / 2;
      ForkJoinPoolExample leftTask = new ForkJoinPoolExample(array, start, mid);
      ForkJoinPoolExample rightTask = new ForkJoinPoolExample(array, mid, end);

      // Fork tasks
      leftTask.fork();
      rightTask.fork();

      // Join results
      return leftTask.join() + rightTask.join();
    }
  }
}
    
©2024 WithoutBook