多线程面试题:交替打印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 的锁机制
相关推荐
coderWangbuer27 分钟前
基于springboot的高校招生系统(含源码+sql+视频导入教程+文档+PPT)
spring boot·后端·sql
攸攸太上33 分钟前
JMeter学习
java·后端·学习·jmeter·微服务
Kenny.志36 分钟前
2、Spring Boot 3.x 集成 Feign
java·spring boot·后端
sky丶Mamba1 小时前
Spring Boot中获取application.yml中属性的几种方式
java·spring boot·后端
千里码aicood2 小时前
【2025】springboot教学评价管理系统(源码+文档+调试+答疑)
java·spring boot·后端·教学管理系统
程序员-珍2 小时前
使用openapi生成前端请求文件报错 ‘Token “Integer“ does not exist.‘
java·前端·spring boot·后端·restful·个人开发
liuxin334455663 小时前
教育技术革新:SpringBoot在线教育系统开发
数据库·spring boot·后端
数字扫地僧3 小时前
HBase与Hive、Spark的集成应用案例
后端
架构师吕师傅3 小时前
性能优化实战(三):缓存为王-面向缓存的设计
后端·微服务·架构
bug菌4 小时前
Java GUI编程进阶:多线程与并发处理的实战指南
java·后端·java ee