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:
- Thread A will detect and print the leap years.
- 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:
leapYearTurn: Indicates whether it's Thread A's turn to check and print.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:
- We have two boolean flags,
leapYearTurnandnonLeapYearTurn. - Initially,
leapYearTurnis set totrueandnonLeapYearTurntofalse.
Thread A (Leap Year Detector):
- Thread A starts and looks at the first year, 1999.
- It checks if it's its turn (
leapYearTurn == true), which it is, so it proceeds. - It applies the leap year check on 1999:
- 1999 is not divisible by 4, so it’s not a leap year.
- Thread A doesn't print anything since it's not a leap year, but it sets
leapYearTurntofalseandnonLeapYearTurntotrueto pass the turn to Thread B.
Thread B (Non-Leap Year Detector):
- Thread B gets its turn because
nonLeapYearTurnis nowtrue. - It looks at 1999, confirms it's not a leap year (which is its responsibility to print), and prints "1999: Non-Leap Year".
- It then sets
leapYearTurntotrueandnonLeapYearTurntofalseto give the turn back to Thread A.
Thread A:
- Now it's 2000, and
leapYearTurnistrueagain, so Thread A checks it. - 2000 is divisible by 4 and also by 400, so it is a leap year.
- Thread A prints "2000: Leap Year" and toggles the flags for Thread B’s turn.
Thread B:
- Thread B sees
nonLeapYearTurnisfalseand waits.
Thread A:
- Moves to 2001, sees that
leapYearTurnistrue. - It checks 2001 and determines it's not a leap year.
- Again, Thread A does not print anything and passes the turn to Thread B by toggling the flags.
Thread B:
- Thread B wakes up with
nonLeapYearTurntrue, checks 2001, sees it's not a leap year, and prints "2001: Non-Leap Year". - Toggles the flags for Thread A.The process continues in this manner, with each thread taking turns and only acting when it's their turn. This ensures that the years are printed in the correct order, alternating between leap years and non-leap years, even though two threads are operating concurrently.






// 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.
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.
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.
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.
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.