面試題:用程序實現兩個線程交替打印 0~100 的奇偶數。

作者: dadiyang 
公眾號:Java面試那些事兒

面試場景

面試官:Java多線程瞭解嗎?你給我寫一下,起兩個線程交替打印0~100的奇偶數。

小黃:啊?

面試官:就是有兩個線程,一個線程打印奇數另一個打印偶數,它們交替輸出,類似這樣。


偶線程:0
奇線程:1
偶線程:2
……
奇線程:99
偶線程:100

小黃:啊?

面試官:……嗯。好的。回去等通知吧。

解說

遇到這種突如其來的面試題,有時候會讓人無從下手。儘管可能你學習過多線程的知識,但是面試官拋一個問題過來,短時間內可能想不出如何使用這些知識來解決這個具體的問題。其實這個問題考察的知識點並不難,但是如果準備的面試的時候沒有看過這道題,一時間還是比較難想出解決方案來的,而且這種題往往是讓面試者手寫代碼。

回到題目上來。首先是兩個線程,其次是交替打印。這可以聯繫到線程之間的通信問題。這時可以想到大致的方向就是加鎖,哪個線程拿到鎖就打印,然後釋放鎖讓另一個線程獲取鎖。兩個線程輪流拿到鎖,實現交替打印的效果。

起兩個線程大家都會,加鎖也簡單,問題是如何讓這兩個線程輪流拿到鎖呢?我們知道,加鎖之後線程之前相互競爭鎖,而Java默認是不保證鎖的公平性的(使用公平鎖可能也是一個思路),這就有可能出現同一個線程一直打印而另一個線程一直沒有打印的情況。

討巧的方案

比較容易想的一個方案是,要輸出的時候判斷一下當前需要輸出的數是不是自己要負責打印的值,如果是就輸出,不是就直接釋放鎖。

面試題:用程序實現兩個線程交替打印 0~100 的奇偶數。

輸出結果如下。


偶數: 0
奇數: 1
偶數: 2
……
奇數: 99
偶數: 100

從輸出上看,是實現了題目上的要求,兩個線程,一個打印奇數,一個打印偶數,輪流輸出。但只是用了一個討巧的方式避開了線程交替獲取鎖的需求,明顯沒有答到面試官想考察的考點上。而且效率較低,如果同一個線程一直搶到鎖,而另一個線程一直沒有拿到,就會導致線程做很多無謂的空轉。那麼有沒有更好的解決方案,讓兩個線程嚴格地交替獲取到鎖呢?

交替獲取鎖的方案

面試題:用程序實現兩個線程交替打印 0~100 的奇偶數。

面試題:用程序實現兩個線程交替打印 0~100 的奇偶數。

上面為了直觀起見,我將兩個線程都獨立寫了出來,其實 Thead 中的代碼是相同的,可以抽成一個 Runnable 類。

面試題:用程序實現兩個線程交替打印 0~100 的奇偶數。

輸出結果如下。


偶數: 0
奇數: 1
偶數: 2
……
奇數: 99
偶數: 100

這種實現方式的原理就是線程1打印之後喚醒其他線程,然後讓出鎖,自己進入休眠狀態。因為進入了休眠狀態就不會與其他線程搶鎖,此時只有線程2在獲取鎖,所以線程2必然會拿到鎖。線程2以同樣的邏輯執行,喚醒線程1並讓出自己持有的鎖,自己進入休眠狀態。這樣來來回回,持續執行直到任務完成。就達到了兩個線程交替獲取鎖的效果了。

至此,本題解決。

擴展

兩個線程交替打印的問題解決了,讓我們來擴展一下,如果有三個線程,要求讓它們交替輸出 1、2、3,即。


線程1:1
線程2:2
線程3:3
線程1:1
線程2:2
線程3:3
……

這種情況要怎麼解決呢?歡迎留言討論。


分享到:


相關文章: