← Back to list

multithreading print A1B2C3…

In multithreading, one of the classic challenges is ensuring that multiple threads coordinate their execution order to produce a…

Sanjayharivilaspal · 2025-09-08 05:10 · 0 claps · 3.4 min read
#multithreading #locks #phaser #semaphore #blockingqueue
Open on Medium ↗
Wiki topics: 📚 · Books & Reading

multithreading print A1B2C3…

In multithreading, one of the classic challenges is ensuring that multiple threads coordinate their execution order to produce a predictable output.

Let’s consider a simple but tricky problem:

Write a multithreaded Java program that prints the sequence A1B2C3...Z26.

  • One thread should print letters (A, B, C, …, Z).
  • Another thread should print numbers (1, 2, 3, …, 26).
  • The threads must run concurrently, but the output must strictly alternate.
  • The challenge is to synchronize threads so they print in the required strict alternation.

This is small problem demonstrates big ideas: locks, conditions, semaphores, barriers, and thread communication patterns.

Approach 1: locks, wait and notifyAll

package multithreading;

public class PrintAlternateA1B2C3Approach1 {
    private final Object lock = new Object();
    private boolean letterTurn = true; // start with letter

    public static void main(String[] args) {
        PrintAlternateA1B2C3Approach1 printer = new PrintAlternateA1B2C3Approach1();

        Thread letterThread = printer.new LetterThread();
        Thread numberThread = printer.new NumberThread();

        letterThread.start();
        numberThread.start();
    }

    // ---------------- Thread for Letters ----------------
    class LetterThread extends Thread {
        @Override
        public void run() {
            printLetters();
        }

        private void printLetters() {
            for (char ch = 'A'; ch <= 'C'; ch++) {
                synchronized (lock) {
                    while (!letterTurn) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                        }
                    }
                    System.out.print(ch);
                    letterTurn = false;
                    lock.notifyAll();
                }
            }
        }
    }

    // ---------------- Thread for Numbers ----------------
    class NumberThread extends Thread {
        @Override
        public void run() {
            printNumbers();
        }

        private void printNumbers() {
            for (int i = 1; i <= 3; i++) {
                synchronized (lock) {
                    while (letterTurn) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                        }
                    }
                    System.out.print(i);
                    letterTurn = true;
                    lock.notifyAll();
                }
            }
        }
    }
}

Approach 2: ReentrantLock and Condition

package multithreading;

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

public class PrintAlternateA1B2C3ApproachLockAndCondition {
    private final Lock lock = new ReentrantLock();
    private final Condition letterCondition = lock.newCondition();
    private final Condition numberCondition = lock.newCondition();
    private boolean letterTurn = true; // start with letter

    public static void main(String[] args) {
        PrintAlternateA1B2C3ApproachLockAndCondition printer = new PrintAlternateA1B2C3ApproachLockAndCondition();

        Thread letterThread = printer.new LetterThread();
        Thread numberThread = printer.new NumberThread();

        letterThread.start();
        numberThread.start();
    }

    // ---------------- Thread for Letters ----------------
    class LetterThread extends Thread {
        @Override
        public void run() {
            printLetters();
        }

        private void printLetters() {
            for (char ch = 'A'; ch <= 'C'; ch++) {
                lock.lock();
                try {
                    while (!letterTurn) {
                        letterCondition.await();
                    }
                    System.out.print(ch);
                    letterTurn = false;
                    numberCondition.signal(); // wake number thread
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } finally {
                    lock.unlock();
                }
            }
        }
    }

    // ---------------- Thread for Numbers ----------------
    class NumberThread extends Thread {
        @Override
        public void run() {
            printNumbers();
        }

        private void printNumbers() {
            for (int i = 1; i <= 3; i++) {
                lock.lock();
                try {
                    while (letterTurn) {
                        numberCondition.await();
                    }
                    System.out.print(i);
                    letterTurn = true;
                    letterCondition.signal(); // wake letter thread
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } finally {
                    lock.unlock();
                }
            }
        }
    }
}

Approach 3: Semaphore

package multithreading;

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

public class PrintAlternateA1B2C3ApproachSemaphore {
    private final Semaphore letterSemaphore = new Semaphore(1); // letters start first
    private final Semaphore numberSemaphore = new Semaphore(0); // numbers wait

    public static void main(String[] args) {
        PrintAlternateA1B2C3ApproachSemaphore printer = new PrintAlternateA1B2C3ApproachSemaphore();

        Thread letterThread = printer.new LetterThread();
        Thread numberThread = printer.new NumberThread();

        letterThread.start();
        numberThread.start();
    }

    // ---------------- Thread for Letters ----------------
    class LetterThread extends Thread {
        @Override
        public void run() {
            printLetters();
        }

        private void printLetters() {
            for (char ch = 'A'; ch <= 'C'; ch++) {
                try {
                    letterSemaphore.acquire();  // wait until it's letter's turn
                    System.out.print(ch);
                    numberSemaphore.release();  // give turn to number thread
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }
    }

    // ---------------- Thread for Numbers ----------------
    class NumberThread extends Thread {
        @Override
        public void run() {
            printNumbers();
        }

        private void printNumbers() {
            for (int i = 1; i <= 3; i++) {
                try{
                    numberSemaphore.acquire();
                    System.out.print(i);
                    letterSemaphore.release();
                }catch (InterruptedException e){
                    Thread.currentThread().interrupt();
                }
            }
        }
    }
}

Approach 4: BlockingQueue

package multithreading;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Semaphore;

public class PrintAlternateA1B2C3ApproachBlockingQueue {
    private final BlockingQueue<Integer> letterQueue = new ArrayBlockingQueue<>(1);
    private final BlockingQueue<Integer> numberQueue = new ArrayBlockingQueue<>(1);

    public static void main(String[] args) {
        PrintAlternateA1B2C3ApproachBlockingQueue printer = new PrintAlternateA1B2C3ApproachBlockingQueue();

        Thread letterThread = printer.new LetterThread();
        Thread numberThread = printer.new NumberThread();

        letterThread.start();
        numberThread.start();
    }

    // ---------------- Thread for Letters ----------------
    class LetterThread extends Thread {
        @Override
        public void run() {
            printLetters();
        }

        private void printLetters() {
            for (char ch = 'A'; ch <= 'C'; ch++) {
                try {
                    System.out.print(ch);
                    numberQueue.put(1);
                    letterQueue.take();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }
    }

    // ---------------- Thread for Numbers ----------------
    class NumberThread extends Thread {
        @Override
        public void run() {
            printNumbers();
        }

        private void printNumbers() {
            for (int i = 1; i <= 3; i++) {
                try{
                    numberQueue.take();
                    System.out.print(i);
                    letterQueue.put(1);
                }catch (InterruptedException e){
                    Thread.currentThread().interrupt();
                }
            }
        }
    }
}

Approach 5: Phaser

package multithreading;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Phaser;

public class PrintAlternateA1B2C3ApproachPhaser {
    private final Phaser phaser = new Phaser(2); // 2 parties: letter + number

    public static void main(String[] args) {
        PrintAlternateA1B2C3ApproachPhaser printer = new PrintAlternateA1B2C3ApproachPhaser();

        Thread letterThread = printer.new LetterThread();
        Thread numberThread = printer.new NumberThread();

        letterThread.start();
        numberThread.start();
    }

    // ---------------- Thread for Letters ----------------
    class LetterThread extends Thread {
        @Override
        public void run() {
            printLetters();
        }

        private void printLetters() {
            for (char ch = 'A'; ch <= 'C'; ch++) {
                System.out.print(ch);
                phaser.arriveAndAwaitAdvance(); // wait for nu
            }
        }
    }

    // ---------------- Thread for Numbers ----------------
    class NumberThread extends Thread {
        @Override
        public void run() {
            printNumbers();
        }

        private void printNumbers() {
            for (int i = 1; i <= 3; i++) {
                System.out.print(i);
                phaser.arriveAndAwaitAdvance(); // wait for nu
            }
        }
    }
}

메타데이터
post_id
3d80f603a237
slug
multithreading-print-a1b2c3-3d80f603a237
url
https://medium.com/@sanjayharivilaspal/multithreading-print-a1b2c3-3d80f603a237
canonical_url
https://medium.com/@sanjayharivilaspal/multithreading-print-a1b2c3-3d80f603a237
author_url
https://medium.com/@sanjayharivilaspal
status
ok
fetched_at
2026-07-17 16:58:18