多執行緒 -- 交替列印
阿新 • • 發佈:2021-09-04
輸入一個數字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();
}
}
}
}