Knowledge Guide
HomeConcurrencyConcurrency Problems

Problem 10 Leap Year Detector Multithreading Problem

Overview

The Leap Year Detector problem involves identifying leap years from a given sequence. In general, a leap year is one that is divisible by 4. However, years divisible by 100 are not leap years unless they are also divisible by 400.

For instance, the year 2000 was a leap year because, even though it's divisible by 100, it's also divisible by 400. However, the year 1900 was not a leap year because, while it is divisible by 100, it is not divisible by 400.

In this multithreaded challenge, we aim to evaluate the sequence of years in two separate threads simultaneously:

  1. Thread A will detect and print the leap years.
  2. Thread B will detect and print the non-leap years.

A key challenge here is ensuring the years are printed in sequence. For instance, given the years [2000, 2001, 2002, 2003, 2004], the desired output might look like:

2000: Leap Year
2001: Non-Leap Year
2002: Non-Leap Year
2003: Non-Leap Year
2004: Leap Year

However, due to the concurrent nature of threads, without appropriate synchronization, we might end up with a jumbled output.

Concurrency (Pseudocode Explanation)

Given the concurrent nature of this task, we need to establish a synchronization mechanism to ensure that the years are evaluated and printed in sequence.

We can use two synchronization flags/signals:

  1. leapYearTurn: Indicates whether it's Thread A's turn to check and print.
  2. nonLeapYearTurn: Indicates whether it's Thread B's turn to check and print.
sqlCopy codesequence_of_years = [...] leapYearTurn = true nonLeapYearTurn = false Function CheckLeapYear(year): IF year MOD 4 == 0 AND (year MOD 100 != 0 OR year MOD 400 == 0): return true ELSE: return false Thread A: FOR each year in sequence_of_years: WAIT until leapYearTurn is true IF CheckLeapYear(year): print year + ": Leap Year" leapYearTurn = false nonLeapYearTurn = true Thread B: FOR each year in sequence_of_years: WAIT until nonLeapYearTurn is true IF NOT CheckLeapYear(year): print year + ": Non-Leap Year" leapYearTurn = true nonLeapYearTurn = false

In the pseudocode above, the two threads evaluate each year in sequence. Thread A waits for its turn (leapYearTurn) to check for leap years, while Thread B waits for its turn (nonLeapYearTurn) to check for non-leap years. Once a thread completes its check for a specific year, it toggles the flags to signal the other thread. This mechanism ensures that the years are printed in sequence.

Algorithm Walkthrough

We have a list of years: [1999, 2000, 2001].

Initialization:

Thread A (Leap Year Detector):

Thread B (Non-Leap Year Detector):

Thread A:

Thread B:

Thread A:

Thread B:

Image
Image
Image
Image
Image
Image
Image
Image
Image
Image
Image
Image
java
// First, we need to import necessary packages for threading and synchronization
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Solution {

  // Here's our array of years we want to evaluate.
  private final int[] years = {
    1990,
    1991,
    1992,
    1993,
    1994,
    1995,
    1996,
    1997,
    1998,
    1999,
    2000,
    2001,
    2002,
    2003,
    2004,
    2005,
  };
  private int currentIndex = 0;

  // We're using ReentrantLock for synchronization
  private final Lock lock = new ReentrantLock();

  // Condition variables are like "signals" for threads to wait or proceed
  private final Condition isLeap = lock.newCondition();
  private final Condition isNotLeap = lock.newCondition();

  // This function checks if a given year is a leap year
  private boolean isLeapYear(int year) {
    return (year % 4 == 0) && (year % 100 != 0 || year % 400 == 0);
  }

  // This is the function that Thread A will execute
  public void detectLeapYears() {
    while (currentIndex < years.length) {
      lock.lock(); // Acquire the lock to ensure mutual exclusion
      try {
        // If the year is leap, print and move to the next year
        if (isLeapYear(years[currentIndex])) {
          System.out.println(years[currentIndex] + ": Leap Year");
          currentIndex++;
          isNotLeap.signal(); // Signal the other thread it might be its turn
        } else {
          isLeap.await(); // If not leap, wait for its turn
        }
      } catch (InterruptedException e) {
        e.printStackTrace();
      } finally {
        lock.unlock(); // Always ensure the lock is released
      }
    }
  }

  // This is the function that Thread B will execute
  public void detectNonLeapYears() {
    while (currentIndex < years.length) {
      lock.lock();
      try {
        // If the year isn't leap, print and move to the next year
        if (!isLeapYear(years[currentIndex])) {
          System.out.println(years[currentIndex] + ": Non-Leap Year");
          currentIndex++;
          isLeap.signal(); // Signal the other thread
        } else {
          isNotLeap.await(); // If it's a leap year, wait
        }
      } catch (InterruptedException e) {
        e.printStackTrace();
      } finally {
        lock.unlock();
      }
    }
  }

  public static void main(String[] args) {
    // Create an instance of the class
    Solution detector = new Solution();

    // Create two threads - one for detecting leap years and one for detecting non-leap years
    Thread leapThread = new Thread(detector::detectLeapYears);
    Thread nonLeapThread = new Thread(detector::detectNonLeapYears);

    // Start both threads
    leapThread.start();
    nonLeapThread.start();

    // We should wait for both threads to finish before ending the main thread
    try {
      leapThread.join();
      nonLeapThread.join();
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}
🤖 Don't fully get this? Learn it with Claude

Stuck on Problem 10 Leap Year Detector Multithreading Problem? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🪜 Hint ladder (no spoilers)

Progressively stronger hints — you still solve it.

I'm working on the problem **Problem 10 Leap Year Detector Multithreading Problem** (Concurrency). Give me a HINT LADDER: start with the tiniest nudge, then wait. Only reveal the next, stronger hint when I ask. Do NOT show the full solution unless I type 'show solution'. Keep me doing the thinking. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🎨 Explain the approach visually

See the technique, not just code.

Explain the optimal approach to **Problem 10 Leap Year Detector Multithreading Problem** with a VISUAL walkthrough: trace it on a small concrete example using ASCII art / a step-by-step diagram, narrate what changes each step, then give time & space complexity with a one-line derivation. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🔍 Review my solution

Catch bugs, edge cases, sub-optimality.

I'll paste my solution to **Problem 10 Leap Year Detector Multithreading Problem**. Review it for correctness, missed edge cases, and time/space complexity, then coach me toward the optimal — don't just rewrite it. Ask me to paste my code now. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🔁 Drill the pattern

Lock in recognition with look-alikes.

Give me 2 problems that use the SAME underlying pattern as **Problem 10 Leap Year Detector Multithreading Problem**. For each, let me attempt first, then review my answer and name the trigger signal that reveals the pattern. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes