经典问题 | 线程打印ABA问题

问题描述

有三个线程,分别命名为 ThreadA、ThreadB 和 ThreadC。请设计一个程序,使得它们循环打印输出字符串 "A"、"B"、"C",打印顺序为 "ABCABCABC..."。要求使用线程同步机制确保按照指定顺序打印。

解决思路

线程的元素判断问题

线程A, B,C三个线程, 当存在竞争的时候, 第一个元素应该打印A, 这个时候打印B的线程进来了, 为了要保证打印ABC是顺序执行的,因此不能让打印B的线程打印.

那线程是打印的什么元素以及和我现在要打印的元素是否匹配是不是就构成了一个条件? 

使用一个共享的计数器, 默认从0开始, 每打印一个元素, 次数+1, 严格按照0,1,2顺序打印ABC

条件1 :  因此计数器的次数对3取模, 就知道当前应该打印什么元素.

条件2 :  在条件1的基础上, 判断线程携带的元素是否是需要打印的元素即可.

这里有个小技巧:

在ASCII码表中,每个字符都有一个对应的整数值。对于大写字母 'A' ,'B','C', 其ASCII码分别为 65 , 66,  67.

因此线程携带的字母减去'A'构成了条件, 与计数器对3取模的数值进行比较, 就知道当前线程是否可以打印字母.

并发问题

在多线程环境中,多个线程并发执行可能导致不确定性的结果。在这个问题中,我们有三个线程,每个线程负责打印一个字符。线程执行快慢问题也会导致顺序紊乱.

为了确保每一次只有一个线程可以执行, 需要有上锁逻辑.

完整的思路: 使用线程等待-通知机制结合共享计数器来实现线程同步。

使用一个共享的计数器 counter,初始值为0,表示当前应该由哪个线程打印。

  1. 三个线程分别为 ThreadA、ThreadB 和 ThreadC,它们负责打印字符 "A"、"B" 和 "C"。
  2. 每个线程在打印自己对应的字符之前,首先检查 counter 的值,只有当 counter 的值模3等于当前线程应该打印的字符的序号时,才进行打印。
  3. 打印完成后,递增 counter 的值,并使用 notifyAll 通知所有线程。
  4. 其他线程在被唤醒后重新检查 counter 的值,如果不满足条件,继续等待。

java代码示例

public class PrintABAThreeThreads {
    private static final int TOTAL_COUNT = 10; // 打印总次数
    private static final Object lock = new Object(); // 用于同步的锁
    private static int counter = 0; // 共享计数器

  

    private static void print(String message) {
        for (int i = 0; i < TOTAL_COUNT; i++) {
            synchronized (lock) {
                while (counter % 3 != message.charAt(0) - 'A') {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                System.out.print(message);
                counter++;
                lock.notifyAll();
            }
        }
    }

  public static void main(String[] args) {
        Thread threadA = new Thread(() -> print("A"));
        Thread threadB = new Thread(() -> print("B"));
        Thread threadC = new Thread(() -> print("C"));

        threadA.start();
        threadB.start();
        threadC.start();
    }
}

你可能感兴趣的:(java基础,并发编程学习指南,java,前端,服务器)