我们提供一个类:
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" 将被输出两次。通过两个信号量来完成线程切换,acquire()、release()方法分别对应着信号量的增加和释放。
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++) { foo.acquire(); printFoo.run(); bar.release(); } } public void bar(Runnable printBar) throws InterruptedException { for(int i = 0; i < n; i++) { bar.acquire(); printBar.run(); foo.release(); } } }通过单一信号量来完成,由于while轮询会占用cpu,所以通过yield()方法来进行cpu的释放,提升运行效率。
class FooBar { private int n; private volatile int flag = 0; public FooBar(int n) { this.n = n; } public void foo(Runnable printFoo) throws InterruptedException { for (int i = 0; i < n; i++) { while(flag != 0) { Thread.yield(); } // printFoo.run() outputs "foo". Do not change or remove this line. printFoo.run(); flag = 1; } } public void bar(Runnable printBar) throws InterruptedException { for (int i = 0; i < n; i++) { while(flag != 1) { Thread.yield(); } // printBar.run() outputs "bar". Do not change or remove this line. printBar.run(); flag = 0; } } }利用公平锁来实现
class FooBar { private int n; Lock lock = new ReentrantLock(true); volatile boolean fooPer = true; public FooBar(int n) { this.n = n; } public void foo(Runnable printFoo) throws InterruptedException { for(int i = 0; i < n;) { lock.lock(); try { if(fooPer) { printFoo.run(); i++; fooPer = false; } } finally { lock.unlock(); } } } public void bar(Runnable printBar) throws InterruptedException { for(int i = 0; i < n;) { lock.lock(); try { if(!fooPer) { printBar.run(); i++; fooPer = true; } } finally { lock.unlock(); } } } }