• 交替打印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();
            }
        }
    }


    
    
  • 相关阅读:
    HDU1862 EXCEL排序
    结构体+字符串比较大小(HDU1234开门人和关门人 )
    两个大数字相加
    Ksusha and Array (vector)
    Ksenia and Pan Scales(思维题)
    最大公约数问题(Wolf and Rabbit )
    HDU2044一只小蜜蜂(递推)
    HDU2043密码
    基础贪心算法(HDU2037今年暑假不AC)
    c# winform 关于DataGridView的一些操作(很全,绝对够用)
  • 原文地址:https://www.cnblogs.com/handsomecui/p/13811029.html
Copyright © 2020-2023  润新知