美文网首页
多线程-交替打印FooBar的3种写法

多线程-交替打印FooBar的3种写法

作者: 97_灰太狼 | 来源:发表于2020-02-17 09:23 被阅读0次
    我们提供一个类:
    
    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" 将被输出两次。
    
    

    写法1:使用yield方法暂停当前正在执行的线程对象,并执行其他线程

    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++) {
              
                // printFoo.run() outputs "foo". Do not change or remove this line.
                while(flag){
                   Thread.yield();
                }
                printFoo.run();
                flag = true;
            }
        }
    
        public void bar(Runnable printBar) throws InterruptedException {
            
            for (int i = 0; i < n; i++) {
                // printBar.run() outputs "bar". Do not change or remove this line.
                    while(!flag){
                   Thread.yield();
                }
                printBar.run();
                flag = false;
            
            }
        }
    }
    

    写法2:使用Semaphore信号量

    class FooBar {
        private int n;
    
        Semaphore foo = new Semaphore(1);
        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++) {
                // printFoo.run() outputs "foo". Do not change or remove this line.
                foo.acquire();
                printFoo.run();
                bar.release();
            }
        }
    
        public void bar(Runnable printBar) throws InterruptedException {
            
            for (int i = 0; i < n; i++) {
                // printBar.run() outputs "bar". Do not change or remove this line.
                bar.acquire();
                printBar.run();
                foo.release();
            
            }
        }
    }
    

    写法3:使用CyclicBarrier适合用在循环场景中,CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程使用await()方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。

    class FooBar {
        private int n;
    
       CyclicBarrier cb = new CyclicBarrier(2);
        volatile boolean fin = true;
    
        public FooBar(int n) {
            this.n = n;
        }
    
        public void foo(Runnable printFoo) throws InterruptedException {
            
            for (int i = 0; i < n; i++) {
              
                // printFoo.run() outputs "foo". Do not change or remove this line.
                  while(!fin);
                printFoo.run();
                fin = false;
                try {
            cb.await();
            } catch (BrokenBarrierException e) {
            }
            
            }
        }
    
        public void bar(Runnable printBar) throws InterruptedException {
            
            for (int i = 0; i < n; i++) {
                // printBar.run() outputs "bar". Do not change or remove this line.
                try {
            cb.await();
            } catch (BrokenBarrierException e) {
            }
                printBar.run();
                fin = true;
            
            }
        }
    }
    

    测试代码:

     public static void main(String[] args) {
            FooBar fooBar = new FooBar(3);
            ExecutorService service = Executors.newFixedThreadPool(2);
            service.submit(() ->{
                try {
                    fooBar.foo(()->{
                        System.out.println("foo");
                    });
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            service.submit(() ->{
                try {
                    fooBar.bar(()->{
                        System.out.println("bar");
                    });
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            service.isShutdown();
        }
    

    个人座右铭:主动 行动 思考 反省 总结

    相关文章

      网友评论

          本文标题:多线程-交替打印FooBar的3种写法

          本文链接:https://www.haomeiwen.com/subject/ginvfhtx.html