Fundamentals 7 min read

Java Multithreaded Printing of ABC Sequence Using Semaphores

This article explains how to create three Java threads that print the characters A, B, and C in order, first without synchronization, then using Semaphore for ordered output, and finally extending the solution to repeat the ABC sequence twenty times.

Full-Stack Internet Architecture
Full-Stack Internet Architecture
Full-Stack Internet Architecture
Java Multithreaded Printing of ABC Sequence Using Semaphores

The article introduces a common interview problem: three threads must print the characters A, B, and C sequentially for a total of 20 repetitions, and demonstrates several incremental solutions.

1. Print characters ABC without order

Three threads are started, each printing a single character; because there is no coordination, the output order is nondeterministic.

package com.sample.interview.multithread;
// three threads print characters ABC, order not guaranteed
public class PrintRandomly {
    public static void main(String[] args) {
        Thread threadA = new Thread(() -> System.out.print("A"));
        Thread threadB = new Thread(() -> System.out.print("B"));
        Thread threadC = new Thread(() -> System.out.print("C"));
        threadA.start();
        threadB.start();
        threadC.start();
    }
}

2. Print characters ABC in order

To enforce the order A → B → C, the solution uses three Semaphore objects as permits. Each thread acquires its own semaphore, prints its character, then releases the semaphore of the next thread, ensuring the required sequence.

package com.sample.interview.multithread;
import java.util.concurrent.Semaphore;
// multithreaded ordered printing of ABC
public class PrintSequentially {
    public static void main(String[] args) {
        Semaphore semaphoreA = new Semaphore(0);
        Semaphore semaphoreB = new Semaphore(0);
        Semaphore semaphoreC = new Semaphore(0);

        Thread threadA = new Thread(() -> {
            try { semaphoreA.acquire(); } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.print("A");
            semaphoreB.release();
        });

        Thread threadB = new Thread(() -> {
            try { semaphoreB.acquire(); } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.print("B");
            semaphoreC.release();
        });

        Thread threadC = new Thread(() -> {
            try { semaphoreC.acquire(); } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.print("C");
            semaphoreA.release();
        });

        // start the chain by releasing the first permit
        semaphoreA.release();
        threadC.start();
        threadB.start();
        threadA.start();
    }
}

3. Print characters ABC in order 20 times

Building on the previous step, each thread now loops 20 times, acquiring and releasing semaphores for each iteration. A helper class PrintChar implements Runnable and encapsulates the logic, making the solution concise and reusable.

package com.sample.interview.multithread;
import java.util.concurrent.Semaphore;
// looped ordered printing of ABC 20 times
public class PrintSequentiallyLoop {
    public static void main(String[] args) {
        Semaphore semaphoreA = new Semaphore(1);
        Semaphore semaphoreB = new Semaphore(0);
        Semaphore semaphoreC = new Semaphore(0);

        PrintChar printCharA = new PrintChar(semaphoreA, semaphoreB, "A");
        PrintChar printCharB = new PrintChar(semaphoreB, semaphoreC, "B");
        PrintChar printCharC = new PrintChar(semaphoreC, semaphoreA, "C");

        new Thread(printCharA).start();
        new Thread(printCharB).start();
        new Thread(printCharC).start();
    }

    static class PrintChar implements Runnable {
        Semaphore cur;
        Semaphore next;
        private String str;
        private int times = 20;
        public PrintChar(Semaphore cur, Semaphore next, String str) {
            this.cur = cur;
            this.next = next;
            this.str = str;
        }
        @Override
        public void run() {
            for (int i = 0; i < times; i++) {
                try { cur.acquire(); } catch (InterruptedException e) { e.printStackTrace(); }
                System.out.print(str);
                next.release();
            }
        }
    }
}

These three examples illustrate how to control thread execution order using semaphores, progressing from an unordered print to a deterministic sequence and finally to repeated ordered output, providing a clear, reusable pattern for similar concurrency interview questions.

JavaConcurrencyMultithreadingSemaphoreThread Synchronization
Full-Stack Internet Architecture
Written by

Full-Stack Internet Architecture

Introducing full-stack Internet architecture technologies centered on Java

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.