這道題是字節的面試題,當場問我有點緊張沒想出來,只答上來要交替阻塞,還是面試官提醒我用生產者消費者思路解決。
題目
有A類線程50個,任務是打印字符A。有B類線程50個,任務是打印字符B。現在異步啟動這100個線程,問如何才能讓他們交替打印AB字符?
解題思路
設兩個信號SemaphoreA和SemaphoreB,他們代表A類和B類的資源數且他們的上限各有一個。初始設SemaphoreA=1,SemaphoreB=0。當一個A類線程消費完SemaphoreA,生產一個B類資源:SemaphoreB++。此時其他A類線程進入阻塞,某一B線程開始獲取資源打印。當一個B類線程消費完SemaphoreB,生產一個A類資源:SemaphoreA++。此后循環交替打印。該題的難點在於是否想到生產者消費者。
實踐
這道題LeetCode上有,我就刷了下:https://leetcode-cn.com/problems/print-foobar-alternately/
描述
兩個不同的線程將會共用一個 FooBar 實例。其中一個線程將會調用 foo() 方法,另一個線程將會調用 bar() 方法。請設計修改程序,以確保 "foobar" 被輸出 n 次。
代碼
class FooBar { private int n; private Semaphore semaphoreFoo = new Semaphore(1); private Semaphore semaphoreBar = new Semaphore(0); public FooBar(int n) { this.n = n; } public void foo(Runnable printFoo) throws InterruptedException { for (int i = 0; i < n; i++) { semaphoreFoo.acquire(); // printFoo.run() outputs "foo". Do not change or remove this line. printFoo.run(); semaphoreBar.release(); } } public void bar(Runnable printBar) throws InterruptedException { for (int i = 0; i < n; i++) { semaphoreBar.acquire(); // printBar.run() outputs "bar". Do not change or remove this line. printBar.run(); semaphoreFoo.release(); } } }