由于水平原因,博客大部分内容摘抄于网络,如有错误或者侵权请指出,本人将尽快修改

1115. 交替打印FooBar

1115. 交替打印FooBar

题目描述

我们提供一个类:

class FooBar {
  public void foo() {
    for (int i = 0; i < n; i++) {
      print("foo");
    }
  }

  public void bar() {
    for (int i = 0; i < n; i++) {
      print("bar");
    }
  }
}

两个不同的线程将会共用一个 FooBar 实例。其中一个线程将会调用 foo() 方法,另一个线程将会调用 bar() 方法。

请设计修改程序,以确保 "foobar" 被输出 n 次。

 

示例 1:

输入: n = 1
输出: "foobar"
解释: 这里有两个线程被异步启动。其中一个调用 foo() 方法, 另一个调用 bar() 方法,"foobar" 将被输出一次。

示例 2:

输入: n = 2
输出: "foobarfoobar"
解释: "foobar" 将被输出两次。

解法

Java

Condition 使用场景分析

使用单个 Condition 的情况:

  1. 简单交替执行

    • 线程间只需要简单的等待/唤醒机制
    • FooBar 问题中,两个线程轮流执行的场景
  2. 共享同一个等待条件

    • 多个线程基于相同的条件变量进行等待
    • 状态切换逻辑简单明确
  3. 性能要求不严格

    • 不需要精确控制唤醒特定线程
    • 可以接受所有等待线程都被唤醒的开销

使用多个 Condition 的情况:

  1. 复杂状态管理

    • 需要根据不同条件唤醒不同类型的线程
    • 多种不同的等待状态需要区分管理
  2. 性能优化需求

    • 避免 signalAll() 唤醒所有线程的性能损耗
    • 精确唤醒特定线程,减少不必要的线程调度
  3. 语义清晰性要求

    • 不同的 Condition 对象代表不同的等待语义
    • 代码可读性和维护性更好

实际建议:

  • 简单场景(如本题):使用单个 Condition 足够
  • 复杂场景(多个不同类型的消费者/生产者):建议使用多个 Condition
  • 性能敏感场景:优先考虑多个 Condition 以获得更好的精确控制
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class FooBar {
    private int n;
    private Lock lock = new ReentrantLock();
    private Condition fooCondition = lock.newCondition();
    private Condition barCondition = lock.newCondition();
    private boolean fooTurn = true;

    public FooBar(int n) {
        this.n = n;
    }

    public void foo(Runnable printFoo) throws InterruptedException {
        for (int i = 0; i < n; i++) {
            lock.lock();
            try {
                // 如果不是foo的回合,则等待
                while (!fooTurn) {
                    fooCondition.await();
                }
                // printFoo.run() outputs "foo". Do not change or remove this line.
                printFoo.run();
                fooTurn = false; // 切换到bar的回合
                barCondition.signal(); // 唤醒bar线程
            } finally {
                lock.unlock();
            }
        }
    }

    public void bar(Runnable printBar) throws InterruptedException {
        for (int i = 0; i < n; i++) {
            lock.lock();
            try {
                // 如果不是bar的回合,则等待
                while (fooTurn) {
                    barCondition.await();
                }
                // printBar.run() outputs "bar". Do not change or remove this line.
                printBar.run();
                fooTurn = true; // 切换到foo的回合
                fooCondition.signal(); // 唤醒foo线程
            } finally {
                lock.unlock();
            }
        }
    }
}

Java

class FooBar {
    private int n;
    private boolean fooTurn = true; // true表示该foo执行,false表示该bar执行

    public FooBar(int n) {
        this.n = n;
    }

    public void foo(Runnable printFoo) throws InterruptedException {
        for (int i = 0; i < n; i++) {
            synchronized (this) {
                // 如果不是foo的回合,则等待
                while (!fooTurn) {
                    wait();
                }
                // printFoo.run() outputs "foo". Do not change or remove this line.
                printFoo.run();
                fooTurn = false; // 切换到bar的回合
                notify(); // 唤醒一个等待的线程
            }
        }
    }

    public void bar(Runnable printBar) throws InterruptedException {
        for (int i = 0; i < n; i++) {
            synchronized (this) {
                // 如果不是bar的回合,则等待
                while (fooTurn) {
                    wait();
                }
                // printBar.run() outputs "bar". Do not change or remove this line.
                printBar.run();
                fooTurn = true; // 切换到foo的回合
                notify(); // 唤醒一个等待的线程
            }
        }
    }
}

...


posted @ 2025-10-23 09:48  小纸条  阅读(7)  评论(0)    收藏  举报