交替打印FooBar

题目来源:https://leetcode-cn.com/problems/print-foobar-alternately

两个不同的线程将会共用一个 FooBar 实例。其中一个线程将会调用 foo() 方法,另一个线程将会调用 bar() 方法。
设计修改程序,以确保 "foobar" 被输出 n 次。

题解:两个线程,一个输出完唤醒另一个线程,输出时等待上一个线程。有多种写法
写法一:使用java的Condition条件await和signal实现
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 两个不同的线程将会共用一个 FooBar 实例。其中一个线程将会调用 foo() 方法,另一个线程将会调用 bar() 方法。
 * <p>
 * 请设计修改程序,以确保 "foobar" 被输出 n 次。
 * <p>
 *  https://leetcode-cn.com/problems/print-foobar-alternately
 *
 * @author jy.cui
 * @version 1.0
 * @date 2020/10/9 16:40
 */
class FooBar {
    private int n;
    private ReentrantLock lock = new ReentrantLock();
    private Condition conditionFoo = lock.newCondition();
    private Condition conditionBar = lock.newCondition();
    private volatile boolean isSignal = false;

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

    public void foo(Runnable printFoo) throws InterruptedException {
        lock.lock(); // 注意Condition需要被lock包围
        for (int i = 0; i < n; i++) {
            // printFoo.run() outputs "foo". Do not change or remove this line.
            printFoo.run();
            conditionFoo.signal(); //释放信号
            isSignal = true; //标记已释放信号
            conditionBar.await();
        }
        lock.unlock();
    }

    public void bar(Runnable printBar) throws InterruptedException {
        lock.lock();
        for (int i = 0; i < n; i++) {
            if(!isSignal){ // 没释放信号再锁
                conditionFoo.await();
            }
            // printBar.run() outputs "bar". Do not change or remove this line.
            printBar.run();
            isSignal = false; //输出完回退标记
            conditionBar.signal();
        }
        lock.unlock();
    }
}

 写法二:利用syncronized的对象wait和notify,交替等待另一个线程的输出,标记为判断此线程的输出状态进行阻塞。

/**
 * 交替打印FooBar
 * 两个不同的线程将会共用一个 FooBar 实例。其中一个线程将会调用 foo() 方法,另一个线程将会调用 bar() 方法。
 * <p>
 * 请设计修改程序,以确保 "foobar" 被输出 n 次。
 * <p>
 *  https://leetcode-cn.com/problems/print-foobar-alternately
 *
 * @author jy.cui
 * @version 1.0
 * @date 2020/10/9 16:40
 */
class FooBar {
    private int n;
    private Object lock = new Object();
    private volatile boolean barHandle = false; //bar输出控制
    public FooBar(int n) {
        this.n = n;
    }

    public void foo(Runnable printFoo) throws InterruptedException {
        for (int i = 0; i < n; i++) {
            synchronized (lock){
                if(barHandle){ // bar输出时等待
                    lock.wait();
                }
                // printFoo.run() outputs "foo". Do not change or remove this line.
                printFoo.run();
                lock.notify(); //唤醒bar线程
                barHandle = true; // 标记唤醒bar输出
            }
        }

    }

    public void bar(Runnable printBar) throws InterruptedException {

        for (int i = 0; i < n; i++) {
            synchronized (lock){
                if(!barHandle){ //初始等待foo输出
                    lock.wait();
                }
                // printBar.run() outputs "bar". Do not change or remove this line.
                printBar.run();
                lock.notify();  //唤醒foo线程
                barHandle = false; //恢复标记,控制foo输出
            }
        }
    }
}

 写法三:无锁,标记互斥,根据全局标记让出时间片


class FooBar {
    private int n;
    private volatile boolean flag = false;
    public FooBar(int n) {
        this.n = n;
    }

    public void foo(Runnable printFoo) throws InterruptedException {
        for (int i = 0; i < n; i++) {
            while (flag){
                Thread.yield();
            }
            // printFoo.run() outputs "foo". Do not change or remove this line.
            printFoo.run();
            flag = true;
        }

    }

    public void bar(Runnable printBar) throws InterruptedException {

        for (int i = 0; i < n; i++) {
            while (!flag){
                Thread.yield();
            }
            // printBar.run() outputs "bar". Do not change or remove this line.
            printBar.run();
            flag = false;
        }
    }
}

 写法四:Semaphore信号量,分别等待其他线程唤醒

class FooBar {
    private int n;
    private Semaphore foo = new Semaphore(0);
    private Semaphore bar = new Semaphore(0);
    public FooBar(int n) {
        this.n = n;
    }

    public void foo(Runnable printFoo) throws InterruptedException {
        for (int i = 0; i < n; i++) {
            if(i != 0){
                foo.acquire();
            }
            // printFoo.run() outputs "foo". Do not change or remove this line.
            printFoo.run();
            bar.release();
        }

    }

    public void bar(Runnable printBar) throws InterruptedException {

        for (int i = 0; i < n; i++) {
            bar.acquire();
            // printBar.run() outputs "bar". Do not change or remove this line.
            printBar.run();
            foo.release();
        }
    }
}

 

 




posted @ 2020-10-13 20:37  handsomecui  阅读(325)  评论(0编辑  收藏  举报