我们提供一个类:
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 次。
方法一:Semaphore
class FooBar {
private int n;
private Semaphore fooSema = new Semaphore(1);
private Semaphore barSema = new Semaphore(0);
public FooBar(int n) {
this.n = n;
}
public void foo(Runnable printFoo) throws InterruptedException {
for (int i = 0; i < n; i++) {
fooSema.acquire();//值为1的时候,能拿到,执行下面的操作
printFoo.run();
barSema.release();//释放许可给barSema这个信号量 barSema 的值+1
}
}
public void bar(Runnable printBar) throws InterruptedException {
for (int i = 0; i < n; i++) {
barSema.acquire();//值为1的时候,能拿到,执行下面的操作
printBar.run();
fooSema.release();//释放许可给fooSema这个信号量 fooSema 的值+1
}
}
}
方法二:Thread.yield()
Thread.yield():使当前线程从执行状态(运行状态)变为可执行态(就绪状态)。cpu会从众多的可执行态里选择,也就是说,当前也就是刚刚的那个线程还是有可能会被再次执行到的,并不是说一定会执行其他线程而该线程在下一次中不会执行到了。
class FooBar {
private int n;
volatile boolean fooExec = true;//foo可以执行
public FooBar(int n) {
this.n = n;
}
public void foo(Runnable printFoo) throws InterruptedException {
for (int i = 0; i < n; ) {
if (fooExec) {
printFoo.run();
fooExec = false;
i++;
} else {
Thread.yield();
}
}
}
public void bar(Runnable printBar) throws InterruptedException {
for (int i = 0; i < n; ) {
if (!fooExec) {
printBar.run();
fooExec = true;
i++;
} else {
Thread.yield();
}
}
}
}
方法三:BlockingQueue
class FooBar {
private int n;
private BlockingQueue<Integer> fooQueue = new LinkedBlockingQueue<Integer>() {{
add(0);
}};
private BlockingQueue<Integer> barQueue = new LinkedBlockingQueue<>();
public FooBar(int n) {
this.n = n;
}
public void foo(Runnable printFoo) throws InterruptedException {
for (int i = 0; i < n; i++) {
fooQueue.take();
printFoo.run();
barQueue.add(0);
}
}
public void bar(Runnable printBar) throws InterruptedException {
for (int i = 0; i < n; i++) {
barQueue.take();
printBar.run();
fooQueue.add(0);
}
}
}
方法四:Synchronized
class FooBar {
private int n;
private Object obj = new Object();
private volatile boolean fooExec = true;
public FooBar(int n) {
this.n = n;
}
public void foo(Runnable printFoo) throws InterruptedException {
for (int i = 0; i < n; i++) {
synchronized (obj) {
if (!fooExec) {//fooExec为false时,该线程等待,为true的时候执行下面的操作
obj.wait();
}
printFoo.run();
fooExec = false;
obj.notifyAll();//唤醒其他线程
}
}
}
public void bar(Runnable printBar) throws InterruptedException {
for (int i = 0; i < n; i++) {
synchronized (obj) {
if (fooExec) {
obj.wait();
}
printBar.run();
fooExec = true;
obj.notifyAll();
}
}
}
}