输入一个数字n
,交替打印foo
和bar
n 次
public static void main(String[] args) {
int n = 10; //打印次数
FooBar fooBar = new FooBar(n);
Runnable printFoo = () -> {
System.out.print("foo");
};
Runnable printBar = () -> {
System.out.print("bar");
};
Thread fooThread = new Thread(() -> {
try {
fooBar.foo(printFoo);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread barThread = new Thread(() -> {
try {
fooBar.bar(printBar);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
fooThread.start();
barThread.start();
}
1. ReentrantLock
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class FooBar {
private int n;
private volatile boolean bl;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public FooBar(int n) {
this.n = n;
}
public void foo(Runnable printFoo) throws InterruptedException {
for (int i = 0; i < n; i++) {
lock.lock();
try {
while (bl) { //当false时输出foo,否则在这里阻塞
condition.await();
}
// printFoo.run() outputs "foo".
printFoo.run();
bl = true;
condition.signal();
} finally {
lock.unlock();
}
}
}
public void bar(Runnable printBar) throws InterruptedException {
for (int i = 0; i < n; i++) {
lock.lock();
try {
while (!bl) { //当true时输出bar,否则在这里阻塞
condition.await();
}
// printBar.run() outputs "bar".
printBar.run();
bl = false;
condition.signal();
} finally {
lock.unlock();
}
}
}
}
2. 使用信号量Semaphore
class FooBar {
private int n;
private Semaphore fooSemaphore = new Semaphore(1); //控制输出foo
private Semaphore barSemaphore = new Semaphore(0); //控制输出bar
public FooBar(int n) {
this.n = n;
}
public void foo(Runnable printFoo) throws InterruptedException {
for (int i = 0; i < n; i++) {
fooSemaphore.acquire(); //可以认为需要得到这个信号量才能进行下一步,不然就阻塞
printFoo.run();
barSemaphore.release(); //将信号量+1
}
}
public void bar(Runnable printBar) throws InterruptedException {
for (int i = 0; i < n; i++) {
barSemaphore.acquire();
printBar.run();
fooSemaphore.release();
}
}
}
3. 使用CyclicBarrier (与CountDownLatch 的主要区别是CyclicBarrier 可以重复使用)
class FooBar {
private int n;
private volatile boolean bl;
private CyclicBarrier cb = new CyclicBarrier(2);
public FooBar(int n) {
this.n = n;
}
public void foo(Runnable printFoo) throws InterruptedException {
for (int i = 0; i < n; i++) {
while(bl) { //当是true时, 进行空转或者让出, false时打印foo
Thread.yield();
}
printFoo.run();
bl = true;
try {
cb.await(); //将foo线程进行同步,相当于-1,然后阻塞当前线程
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
public void bar(Runnable printBar) throws InterruptedException {
for (int i = 0; i < n; i++) {
try {
cb.await(); //将bar线程同步
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
printBar.run();
bl = false;
}
}
}
4. 用Thread.yield()
,让出CPU,具体还是得看线程的调度
class FooBar {
private int n;
private volatile boolean bl;
public FooBar(int n) {
this.n = n;
}
public void foo(Runnable printFoo) throws InterruptedException {
for (int i = 0; i < n;) {
if (!bl) {
printFoo.run();
bl = true;
i++;
} else { //让出这一轮循环,等待重新进入循环
Thread.yield();
}
}
}
public void bar(Runnable printBar) throws InterruptedException {
for (int i = 0; i < n;) {
if (bl) {
printBar.run();
bl = false;
i++;
} else {
Thread.yield();
}
}
}
}
5. BlockingQueue
class FooBar {
private int n;
private BlockingQueue<Integer> fooQueue = new LinkedBlockingDeque<>();
private BlockingQueue<Integer> barQueue = new LinkedBlockingDeque<>();
public FooBar(int n) {
this.n = n;
fooQueue.add(0); //做为第一个输出
}
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);
}
}
}
6.使用Synchronized,配合wait和notify进行线程的控制
class FooBar {
private int n;
private volatile boolean bl;
private Object lock = new Object();
public FooBar(int n) {
this.n = n;
}
public void foo(Runnable printFoo) throws InterruptedException {
for (int i = 0; i < n; i++) {
synchronized (lock) {
if (bl) {
lock.wait();
}
printFoo.run();
bl = true;
lock.notify();
}
}
}
public void bar(Runnable printBar) throws InterruptedException {
for (int i = 0; i < n; i++) {
synchronized (lock) {
if (!bl) {
lock.wait();
}
printBar.run();
bl = false;
lock.notify();
}
}
}
}
7.使用LockSupport,方式上类似于Synchronized
多线程 -- 交替打印