【Java多執行緒程式設計題】兩個執行緒迴圈輸出A和B
非個人面試,這是京東面試的一道程式設計題
前言:這道題挺有意思的,剛好我剛學了基礎的Java多執行緒,那就試一試。另外以下的兩種方案都需要注意就是,wait()
需要放在while
迴圈裡以防錯失notify
訊號
一種程式碼風格比較好的方案:同步方法
package thread.print; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class CyclicPrint { private ExecutorService executorService = Executors.newFixedThreadPool(2); private boolean printA = true; private synchronized void printA() throws InterruptedException { while (!printA) wait(); System.out.println("A"); printA = false; notifyAll(); } private synchronized void printB() throws InterruptedException { while (printA) wait(); System.out.println("B"); printA = true; notifyAll(); } private Thread a = new Thread(() -> { while (!Thread.interrupted()) { try { printA(); } catch (InterruptedException e) { e.printStackTrace(); } } }); private Thread b = new Thread(() -> { while (!Thread.interrupted()) { try { printB(); } catch (InterruptedException e) { e.printStackTrace(); } } }); public CyclicPrint() throws InterruptedException { executorService.execute(a); executorService.execute(b); Thread.sleep(1000); executorService.shutdownNow(); } public static void main(String[] args) throws InterruptedException { new CyclicPrint(); } }
另外一種與上面大同小異的方案,但是可讀性較之低一些:同步臨界區
package thread.print; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class CyclicPrint2 { private ExecutorService executorService = Executors.newFixedThreadPool(2); private final CyclicPrint2 p = this; private boolean printA = true; private Thread a = new Thread(() -> { while (!Thread.interrupted()) { synchronized (p) { while (!printA) { try { p.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("A"); printA = false; p.notifyAll(); } } }); private Thread b = new Thread(() -> { while (!Thread.interrupted()) { synchronized (p) { while (printA) { try { p.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("B"); printA = true; p.notifyAll(); } } }); public CyclicPrint2() throws InterruptedException { executorService.execute(a); executorService.execute(b); Thread.sleep(1000); executorService.shutdownNow(); } public static void main(String[] args) throws InterruptedException { new CyclicPrint(); } }
Lock
+Condition
版
package thread.print; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class CyclicPrint3 { Lock lock = new ReentrantLock(); Condition condition = lock.newCondition(); private ExecutorService executorService = Executors.newFixedThreadPool(2); private boolean printA = true; private void printA() throws InterruptedException { lock.lock(); while (!printA) condition.await(); System.out.println("A"); printA = false; condition.signalAll(); lock.unlock(); } private void printB() throws InterruptedException { lock.lock(); while (printA) condition.await(); System.out.println("B"); printA = true; condition.signalAll(); lock.unlock(); } private Thread a = new Thread(() -> { while (!Thread.interrupted()) { try { printA(); } catch (InterruptedException e) { e.printStackTrace(); } } }); private Thread b = new Thread(() -> { while (!Thread.interrupted()) { try { printB(); } catch (InterruptedException e) { e.printStackTrace(); } } }); public CyclicPrint3() throws InterruptedException { executorService.execute(a); executorService.execute(b); Thread.sleep(1000); executorService.shutdownNow(); } public static void main(String[] args) throws InterruptedException { new CyclicPrint3(); } }
結語:剛開始這道題還是難住我了的,因為剛學完基礎,最初甚至萌生用CountDownLatch
或是CyclicBarrier
等新構件解決,但應該是行不通的。然後慢慢想才有了同步+迴圈條件的解決方案,效果還不錯。