多线程面试题:交替打印ABC的多种实现方法

题目描述

建立三个线程thread1、thread2、thread3,要求三个线程同时运行,并且实现交替打印ABC,即按照 ABCABCABCABC... 的顺序打印。

实现思路

  • 使用 volatile 实现
  • 使用 AtomicInteger 实现
  • 使用 wait/notify 实现
  • 使用 Condition 和 lock 实现
  • 使用 BlockingQueue 实现
  • 使用 Semaphore 实现

使用 volatile 实现

使用 volatile 实现是最容易想到的方式。

java 复制代码
public class VolatileOrderThread {

    static volatile int ticket = 1;

    public static void main(String[] args) {

        Thread thread1 = new Thread(() -> {
            while (true) {
                if (ticket == 1) {
                    System.out.println("A");
                    ticket = 2;
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            while (true) {
                if (ticket == 2) {
                    System.out.println("B");
                    ticket = 3;
                }
            }
        });

        Thread thread3 = new Thread(() -> {
            while (true) {
                if (ticket == 3) {
                    System.out.println("C");
                    ticket = 1;
                }
            }
        });

        thread1.start();
        thread2.start();
        thread3.start();
    }
}

使用 AtomicInteger 实现

使用 AtomicInteger 实现本质上和使用 volatile 是一回事情,在 AtomicInteger 内部也维护了一个 volatile 类型的变量,用来保证共享变量的可见性。

java 复制代码
public class AtomicIntegerOrderThread {

    static AtomicInteger ticket = new AtomicInteger(1);

    public static void main(String[] args) {

        Thread thread1 = new Thread(() -> {
            while (true) {
                if (ticket.get() == 1) {
                    System.out.println("A");
                    ticket.set(2);
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            while (true) {
                if (ticket.get() == 2) {
                    System.out.println("B");
                    ticket.set(3);
                }
            }
        });

        Thread thread3 = new Thread(() -> {
            while (true) {
                if (ticket.get() == 3) {
                    System.out.println("C");
                    ticket.set(1);
                }
            }
        });

        thread1.start();
        thread2.start();
        thread3.start();
    }
}

使用 wait/notify 实现

要实现线程间通信,最原始也是最万能的方法,当然是使用 wait/notify。

java 复制代码
public class WaitNotifyOrderThread {

    static int ticket = 1;

    static final Object object = new Object();

    public static void main(String[] args) {

        Thread thread1 = new Thread(() -> {
            while (true) {
                synchronized (object) {
                    try {
                        while (ticket != 1) {
                            object.wait();
                        }
                        System.out.println("A");
                        ticket = 2;
                        object.notifyAll();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            while (true) {
                synchronized (object) {
                    try {
                        while (ticket != 2) {
                            object.wait();
                        }
                        System.out.println("B");
                        ticket = 3;
                        object.notifyAll();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        });

        Thread thread3 = new Thread(() -> {
            while (true) {
                synchronized (object) {
                    try {
                        while (ticket != 3) {
                            object.wait();
                        }
                        System.out.println("C");
                        ticket = 1;
                        object.notifyAll();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        });

        thread1.start();
        thread2.start();
        thread3.start();
    }
}

使用 Condition 和 lock 实现

Doug Lea 神一样的男人。

java 复制代码
public class ConditionOrderThread {

    static int ticket = 1;

    static Lock lock = new ReentrantLock();

    static Condition conditionA = lock.newCondition();

    static Condition conditionB = lock.newCondition();

    static Condition conditionC = lock.newCondition();

    public static void main(String[] args) {

        Thread thread1 = new Thread(() -> {
            while (true) {
                lock.lock();
                try {
                    if (ticket != 1) {
                        conditionA.await();
                    }
                    System.out.println("A");
                    ticket = 2;
                    conditionB.signal();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                } finally {
                    lock.unlock();
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            while (true) {
                lock.lock();
                try {
                    if (ticket != 2) {
                        conditionB.await();
                    }
                    System.out.println("B");
                    ticket = 3;
                    conditionC.signal();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                } finally {
                    lock.unlock();
                }
            }
        });

        Thread thread3 = new Thread(() -> {
            while (true) {
                lock.lock();
                try {
                    if (ticket != 3) {
                        conditionC.await();
                    }
                    System.out.println("C");
                    ticket = 1;
                    conditionA.signal();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                } finally {
                    lock.unlock();
                }
            }
        });

        thread1.start();
        thread2.start();
        thread3.start();
    }
}

使用 BlockingQueue 实现

这种方式,本质上也是使用 Condition 和 lock,阻塞队列的 take 方法就是使用 Condition 和 lock 实现的。

java 复制代码
public class BlockingQueueOrderThread {

    static BlockingQueue<Character> queueA = new LinkedBlockingQueue<>(1);

    static BlockingQueue<Character> queueB = new LinkedBlockingQueue<>(1);

    static BlockingQueue<Character> queueC = new LinkedBlockingQueue<>(1);

    public static void main(String[] args) {

        queueA.add('A');

        Thread thread1 = new Thread(() -> {
            while (true) {
                try {
                    Character element = queueA.take();
                    System.out.println(element);
                    queueB.put('B');
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            while (true) {
                try {
                    Character element = queueB.take();
                    System.out.println(element);
                    queueC.put('c');
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        Thread thread3 = new Thread(() -> {
            while (true) {
                try {
                    Character element = queueC.take();
                    System.out.println(element);
                    queueA.put('A');
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        thread1.start();
        thread2.start();
        thread3.start();
    }
}

使用 Semaphore 实现

使用 基于 AQS 的 Semaphore(信号量) 也可以轻松的实现。

java 复制代码
public class SemaphoreOrderThread {

    static Semaphore semaphoreA = new Semaphore(1);
    static Semaphore semaphoreB = new Semaphore(0);
    static Semaphore semaphoreC = new Semaphore(0);

    public static void main(String[] args) {

        Thread thread1 = new Thread(() -> {
            while (true) {
                try {
                    semaphoreA.acquire();
                    System.out.println("A");
                    semaphoreB.release();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            while (true) {
                try {
                    semaphoreB.acquire();
                    System.out.println("B");
                    semaphoreC.release();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        Thread thread3 = new Thread(() -> {
            while (true) {
                try {
                    semaphoreC.acquire();
                    System.out.println("C");
                    semaphoreA.release();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        thread1.start();
        thread2.start();
        thread3.start();
    }
}

总结

虽然有多种方法,但归根结底只有两种:

  • 一种是基于 Java 原生的锁机制;
  • 一种是基于 CAS 的锁机制
相关推荐
Python私教3 小时前
Django全栈班v1.04 Python基础语法 20250912 下午
后端·python·django
爱读源码的大都督3 小时前
为什么Spring 6中要把synchronized替换为ReentrantLock?
java·后端·架构
这里有鱼汤3 小时前
发现一个高性能回测框架,Python + Rust,比 backtrader 快 250 倍?小团队必备!
后端·python
程序员爱钓鱼4 小时前
Go语言实战案例 — 项目实战篇:图书管理系统(文件存储)
后端·google·go
元闰子4 小时前
OLTP上云,哪种架构最划算?·VLDB'25
数据库·后端·云原生
IT_陈寒4 小时前
Vite 5.0重磅升级:8个性能优化秘诀让你的构建速度飙升200%!🚀
前端·人工智能·后端
hui函数4 小时前
scrapy框架-day02
后端·爬虫·python·scrapy
Moshow郑锴4 小时前
SpringBootCodeGenerator使用JSqlParser解析DDL CREATE SQL 语句
spring boot·后端·sql
小沈同学呀10 小时前
创建一个Spring Boot Starter风格的Basic认证SDK
java·spring boot·后端
不要再敲了12 小时前
JDBC从入门到面试:全面掌握Java数据库连接技术
java·数据库·面试