三个线程交替打印ABC如何实现?

问题描述:

写三个线程打印"ABC",一个线程打印A,一个线程打印B,一个线程打印C,一共打印10轮。

问题解决:

Semaphore实现:

我们先定义一个类ABCPrinter用于实现三个线程交替打印ABC。

public class ABCPrinter {
    private final int max;
    //从线程A开始
    private final Semaphore semaphoreA = new Semaphore(1);
    private final Semaphore semaphoreB = new Semaphore(0);
    private final Semaphore semaphoreC = new Semaphore(0);
    
    public ABCPrinter(int max) {
        this.max = max;
    }

    public void printerA() {
        print("A", semaphoreA, semaphoreB);
    }

    public void printerB() {
        print("B", semaphoreB, semaphoreC);
    }

    public void printerC() {
        print("C", semaphoreC, semaphoreA);
    }

    private void print(String alphabet, Semaphore currentSemaphore, Semaphore nextSemaphore) {
        for (int i = 1; i <= max; i++) {
            try{
                currentSemaphore.acquire();
                System.out.println(Thread.currentThread().getName() + " : " + alphabet);
                //传递信号给下一个线程
                nextSemaphore.release();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return;
            }
        }
    }
}

可以看到,我们这里用到了三个信号量,分别用于控制这三个线程的交替执行。semaphoreA 信号量先获取,也就是先输出“A”。一个线程执行完之后,就释放下一个信号量。也就是,A 线程执行完之后释放semaphoreB信号量,B 线程执行完之后释放semaphoreC信号量,以此类推。

接着,我们创建三个线程,分别用于打印 ABC。

ABCPrinter printer = new ABCPrinter(10);
Thread t1 = new Thread(printer::printA, "Thread A");
Thread t2 = new Thread(printer::printB, "Thread B");
Thread t3 = new Thread(printer::printC, "Thread C");

t1.start();
t2.start();
t3.start();

输出如下:

Thread A : A
Thread B : B
Thread C : C
......
Thread A : A
Thread B : B
Thread C : C

ReentrantLock + Condition 实现:

思路和 synchronized+wait/notify 很像。

public class ABCPrinter {
    private final int max;
    // 用来指示当前应该打印的线程序号,0-A, 1-B, 2-C
    private int turn = 0;
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition conditionA = lock.newCondition();
    private final Condition conditionB = lock.newCondition();
    private final Condition conditionC = lock.newCondition();

    public ABCPrinter(int max) {
        this.max = max;
    }

    public void printA() {
        print("A", conditionA, conditionB);
    }

    public void printB() {
        print("B", conditionB, conditionC);
    }

    public void printC() {
        print("C", conditionC, conditionA);
    }

                                                   
   private void print(String name, Condition currentCondition, Condition nextCondition) {
        for (int i = 0; i < max; i++) {
            lock.lock();
            try {
                // 等待直到轮到当前线程打印
                // turn 变量的值需要与线程要打印的字符相对应,例如,如果turn是0,且当前线程应该打印"A",则条件满足。如果不满足,当前线程调用currentCondition.await()进入等待状态。

                while (!((turn == 0 && name.charAt(0) == 'A') || (turn == 1 && name.charAt(0) == 'B') || (turn == 2 && name.charAt(0) == 'C'))) {
                    currentCondition.await();
                }
                System.out.println(Thread.currentThread().getName() + " : " + name);
                // 更新打印轮次,并唤醒下一个线程
                turn = (turn + 1) % 3;
                nextCondition.signal();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                lock.unlock();
            }
        }
    }
}

在上面的代码中,三个线程的协调主要依赖:

ReentrantLock lock: 用于线程同步的可重入锁,确保同一时刻只有一个线程能修改共享资源。Condition conditionA/B/C: 分别与"A"、"B"、"C"线程关联的条件变量,用于线程间的协调通信。一个线程执行完之后,通过调用nextCondition.signal()唤醒下一个应该打印的线程。

控制三个线程的执行顺序问题描述:

假设有 T1、T2、T3 三个线程,你怎样保证 T2 在 T1 执行完后执行,T3 在 T2 执行完后执行?

网上大部分人都是用 join()或者 CountDownLatch 实现,但在此推荐CompletableFuture

代码如下(这里为了简化代码,用到了 Hutool 的线程工具类 ThreadUtil 和日期时间工具类 DateUtil):

// T1
CompletableFuture<Void> futureT1 = CompletableFuture.runAsync(() -> {
    System.out.println("T1 is executing.Current time:" + DateUtil.now());
    // 模拟耗时操作
    ThreadUtil.sleep(1000);
});

// T2 在 T1 完成后执行
CompletableFuture<Void> futureT2 = futureT1.thenRunAsync(() -> {
    System.out.println("T2 is executing after T1.Current time:" + DateUtil.now());
    ThreadUtil.sleep(1000);
});

// T3 在 T2 完成后执行
CompletableFuture<Void> futureT3 = futureT2.thenRunAsync(() -> {
    System.out.println("T3 is executing after T2.Current time:" + DateUtil.now());
    ThreadUtil.sleep(1000);
});

// 等待所有任务完成,验证效果
ThreadUtil.sleep(3000);

可以看到,我们这里通过 thenRunAsync()方法就实现了 T1、T2、T3 的顺序执行。thenRunAsync()方法的作用就是做完第一个任务后,再做第二个任务。也就是说某个任务执行完成后,执行回调方法

输出:

T1 is executing.Current time:2024-08-20 15:59:38
T2 is executing after T1.Current time:2024-08-20 15:59:39
T3 is executing after T2.Current time:2024-08-20 15:59:40

如果我们想要实现 T3 在 T2 和 T1 执行完后执行,T2 和 T1 可以同时执行,应该怎么办呢?

// T1
CompletableFuture<Void> futureT1 = CompletableFuture.runAsync(() -> {
    System.out.println("T1 is executing. Current time:" + DateUtil.now());
    // 模拟耗时操作
    ThreadUtil.sleep(1000);
});
// T2
CompletableFuture<Void> futureT2 = CompletableFuture.runAsync(() -> {
    System.out.println("T2 is executing. Current time:" + DateUtil.now());
    ThreadUtil.sleep(1000);
});

// 使用allOf()方法合并T1和T2的CompletableFuture,等待它们都完成
CompletableFuture<Void> bothCompleted = CompletableFuture.allOf(futureT1, futureT2);
// 当T1和T2都完成后,执行T3
bothCompleted.thenRunAsync(() -> System.out.println("T3 is executing after T1 and T2 have completed.Current time:" + DateUtil.now()));
// 等待所有任务完成,验证效果
ThreadUtil.sleep(3000);

同样非常简单,可以通过 CompletableFuture allOf()这个静态方法来并行运行多个 CompletableFuture 。然后,再利用 thenRunAsync()方法即可。这个问题还有非常多的扩展,上面提到的场景都是异步任务编排最简单的场景。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以使用多线程编程来实现三个线程交替打印abc。下面是一个示例代码: ```python import threading class PrintABC: def __init__(self): self.current_letter = 'A' self.lock = threading.Lock() def print_a(self): for _ in range(10): with self.lock: while self.current_letter != 'A': self.lock.wait() print('A', end='') self.current_letter = 'B' self.lock.notify_all() def print_b(self): for _ in range(10): with self.lock: while self.current_letter != 'B': self.lock.wait() print('B', end='') self.current_letter = 'C' self.lock.notify_all() def print_c(self): for _ in range(10): with self.lock: while self.current_letter != 'C': self.lock.wait() print('C', end='') self.current_letter = 'A' self.lock.notify_all() def main(): printer = PrintABC() thread_a = threading.Thread(target=printer.print_a) thread_b = threading.Thread(target=printer.print_b) thread_c = threading.Thread(target=printer.print_c) thread_a.start() thread_b.start() thread_c.start() thread_a.join() thread_b.join() thread_c.join() if __name__ == '__main__': main() ``` 这个例子中,我们创建了一个 `PrintABC` 类,其中包含了三个方法 `print_a`、`print_b` 和 `print_c` 分别用于打印字母 'A'、'B' 和 'C'。在每个方法中,使用 `with self.lock` 来获取锁对象并进入临界区域。通过 `self.current_letter` 来确定当前应该打印的字母,并使用 `while self.current_letter != 'A'` 等待其他线程改变 `self.current_letter` 的值。当当前字母符合要求时,打印字母并切换到下一个字母,然后使用 `self.lock.notify_all()` 唤醒其他等待的线程。 在 `main` 方法中,我们创建了三个线程并分别启动它们,然后使用 `join` 方法等待所有线程执行完毕。运行这段代码时,你将会看到三个线程交替打印字母 'A'、'B' 和 'C',每个字母连续打印十次。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值