Backend Development 10 min read

Java Multithreading Tutorial: Simulating Ticket Booking with Runnable

This article explains how to implement Java multithreading using the Runnable interface through a ticket‑booking example, demonstrates common pitfalls like calling run() directly, shows code with and without Thread.sleep, and discusses concurrency issues such as thread‑unsafe ticket duplication.

FunTester
FunTester
FunTester
Java Multithreading Tutorial: Simulating Ticket Booking with Runnable

Previously we discussed Java multithreading approaches, noting that extending Thread or implementing Runnable are possible, but implementing Runnable is generally preferred.

A common mistake is invoking the run() method directly; the correct way to start a new thread is to call start().

To illustrate multithreading, we analyze a ticket‑booking scenario where a limited number of train seats are available and multiple users attempt to purchase tickets simultaneously.

Define the total number of tickets (e.g., 10) and ensure the number of sold tickets never exceeds this limit.

Maintain the remaining ticket count, which must stay non‑negative.

Allow N users to compete for tickets concurrently using multiple threads and display the results.

package demo11;
//买火车票的例子
public class TestThread4 implements Runnable {
    //火车票票数
    private int ticketNums = 10;

    //重写run方法
    @Override
    public void run() {
        while (true) {
            if (ticketNums <= 0) {
                break;
            }
            //打印出谁拿到了第N张票 谁用的是 Thread.currentThread().getName
            System.out.println(Thread.currentThread().getName() + "-->拿到了第 " + ticketNums-- + " 张票");
        }
    }

    public static void main(String[] args) {
        TestThread4 ticket = new TestThread4();
        //目前有三个线程在抢10张票
        new Thread(ticket, "小明").start();
        new Thread(ticket, "老师").start();
        new Thread(ticket, "黄牛党").start();
    }
}

Running this program with three threads ("小明", "老师", "黄牛党") shows that the first two obtain tickets while the third may miss out, illustrating basic thread scheduling.

小明-->拿到了第 10 张票
小明-->拿到了第 8 张票
小明-->拿到了第 7 张票
老师-->拿到了第 9 张票
小明-->拿到了第 6 张票
老师-->拿到了第 5 张票
老师-->拿到了第 3 张票
小明-->拿到了第 4 张票
老师-->拿到了第 2 张票
小明-->拿到了第 1 张票

A second execution may let the "黄牛党" thread also acquire tickets, demonstrating that thread execution order is nondeterministic.

小明-->拿到了第 10 张票
老师-->拿到了第 9 张票
黄牛党-->拿到了第 7 张票
小明-->拿到了第 8 张票
黄牛党-->拿到了第 5 张票
黄牛党-->拿到了第 4 张票
黄牛党-->拿到了第 3 张票
老师-->拿到了第 6 张票
黄牛党-->拿到了第 1 张票
小明-->拿到了第 2 张票

To slow down the output and observe thread behavior, we can insert Thread.sleep(1000) inside the loop, handling the required InterruptedException with a try‑catch block.

package demo11;
//买火车票的例子
public class TestThread4 implements Runnable {
    //火车票票数
    private int ticketNums = 10;

    //重写run方法
    @Override
    public void run() {
        while (true) {
            if (ticketNums <= 0) {
                break;
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //打印出谁拿到了第N张票 谁用的是 Thread.currentThread().getName
            System.out.println(Thread.currentThread().getName() + "-->拿到了第 " + ticketNums-- + " 张票");
        }
    }

    public static void main(String[] args) {
        TestThread4 ticket = new TestThread4();
        //目前有三个线程在抢10张票
        new Thread(ticket, "小明").start();
        new Thread(ticket, "老师").start();
        new Thread(ticket, "黄牛党").start();
    }
}

Running the version with Thread.sleep shows a one‑second pause after each ticket is printed, and also reveals that without proper synchronization the same ticket number can be printed by multiple threads, indicating a thread‑unsafe (data race) situation.

How to resolve such concurrency issues will be covered in a future article.

「Have Fun ~ Tester !」

140 interview questions (UI, Linux, MySQL, API, Security)

Share 11 written test papers

Fiddler learning package

Microsoft Zune leap‑year bug analysis

Phone‑binding performance test

Automated testing lifecycle

Quality over quantity in software testing

Web security checklist

Code‑based vs. no‑code automation

Python Socket.IO testing script

Thread‑pool batch API request practice

Golang fasthttp practice

Colored console output

Automa basic features demo

JavaconcurrencythreadmultithreadingRunnableticket-booking
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

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.