記一個有意思的面試題 → 執行緒交替輸出問題

青石路發表於2021-02-13

開心一刻

大年初一,一起嗨起來!!!

  強調一句很重要的心裡話:祝大家在 2021 年,健康好運,平安幸福!

問題描述

  用兩個執行緒,一個輸出數字,一個輸出字母,交替輸出 1A2B3C4D...26Z

  該如何實現?

解決方式

  據說解決方式有上百種,但有些是脫了褲子放屁,有些是民間偏方,所以沒必要全部都知道(其實樓主也不知道具體是哪一百多種)

  掌握常用的那幾個就好;為了方便,我們就以 1234567 和 ABCDEFG 為例進行演示

  synchronized + wait + notify

  如果我們對 JUC 不熟的話,那這種方式往往是我們最容易想到的

  這種方式,相信大家都能寫出來,但是這裡留三個問題(面試點)

  1、執行緒程式碼中, try 中的 notify() 能否與 wait() 交換位置,為什麼

  2、執行緒程式碼中, for 下的 notify() 能否去掉,為什麼

  3、上面的程式碼能否保證一定先輸出數字,為什麼,如何保證一定先輸出數字

  ReentrantLock + Condition + await + signal

  很多場景下,用 ReentrantLock 可以替代 synchronized ,而在交叉輸出這個場景中,同樣可以替代

  這種方式,寫出來應該也不難,同樣留三個問題(面試點)

  1、執行緒程式碼中, for 中的 signal() 能否與 await() 交換位置,為什麼

  2、執行緒程式碼中, for 下的 signal() 能否去掉,為什麼

  3、上面的程式碼能否保證一定先輸出數字,為什麼,如何保證一定先輸出數字

  LockSupport + park + unpark

  估計很多人都沒想到這種方式,直接上程式碼

  這是目前最優的解決方式,照樣留四個問題(面試點)

  1、 t1.start() 能否與 t2.start() 交換位置,為什麼

  2、執行緒 t1 中的 LockSupport.unpark(t2) 線上程 t2 中的 LockSupport.park() 之前執行會怎麼樣,為什麼

  3、上面的程式碼能否保證一定先輸出數字,為什麼

  4、 LockSupport 的 park 、 unpark 與  Object 的 wait 、 notify 有什麼異同

  CAS

  這種方式可能也比較難想到,直接上程式碼

  這種方式也許不太好理解,留四個問題(面試點)加深理解

  1、執行緒程式碼中, while 條件為什麼是 !=,而不是 ==

  2、上面的程式碼能否保證一定先輸出數字,為什麼

  3、CAS 的優缺點是什麼,適用於什麼場景

  CAS + AtomicInteger

  其實就是 CAS 的一個變種,直接上程式碼

  CAS + AtomicReference

  也是 CAS 的一個變種,直接上程式碼

  TransferQueue

  一般很難想象到這種方式,但卻是很有趣的一種實現方式

  如果不瞭解 TransferQueue ,那這種方式就想不到;同樣留一個問題(面試點)

  1、上面的程式碼能否保證一定先輸出數字,為什麼

  BlockingQueue

  一般也比較難想到這種方式,有所瞭解就好

  PipedStream

  效率很低,知道有這麼回事就好

總結

  1、示例程式碼地址:juc-demo

  2、需要掌握的實現方式

    synchronized、ReentrantLock、LockSupport、CAS、TransferQueue 這幾種實現方式必須掌握

    其他的瞭解就好

  3、如何保證一定先輸出數字

    上面介紹的那些方式中,有些是不能保證一定先輸出數字的,而有些是能保證一定先輸出數字的

    不能保證先輸出數字的,可以用 CountDownLatch 來控制,是一種比較理想的做法

相關文章