多线程面试题:交替打印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 的锁机制
相关推荐
brzhang1 分钟前
OpenAI 终究还是背刺了自己:1200亿参数模型直接开源,实测 120b 模型编码能力强过 Claude3.5!
前端·后端·架构
Java水解1 分钟前
Spring AI+Redis会话记忆持久化存储实现
后端·spring
bcbnb8 分钟前
怎么在 Windows 上架 iOS APP?签名 + 发布一文全懂
后端
掘金一周16 分钟前
只有 7 KB!前端圈疯传的 Vue3 转场动效神库!效果炸裂! | 掘金一周 8.7
前端·后端·ai编程
枣伊吕波21 分钟前
十一、请求响应-请求:简单参数和实体参数(简单实体参数与复杂实体参数)
java·spring boot·后端
苇柠21 分钟前
SpringMVC基础
java·后端·spring
白白白鲤鱼24 分钟前
Vue2项目—基于路由守卫实现钉钉小程序动态更新标题
服务器·前端·spring boot·后端·职场和发展·小程序·钉钉
苦学编程的谢35 分钟前
Spring_事务
java·后端·spring
Running_C1 小时前
Vue组件化开发:从基础到实践的全面解析
前端·vue.js·面试
用户9096783069431 小时前
Python 列表中所有数字加1,返回新列表
后端