摘要:重溫一個面試題內(nèi)容數(shù)組內(nèi)容為數(shù)組內(nèi)容為個英文字母,使用兩個線程分別輸入兩個數(shù)組,打印內(nèi)容為這樣的規(guī)律提取一下核心內(nèi)容,去除次要內(nèi)容兩個線程需要交替執(zhí)行,打印數(shù)字的線程需要先執(zhí)行,數(shù)組打印完畢后線程需要結(jié)束。
一道多線程面試題引起的自我救贖
近日去一個知名互聯(lián)網(wǎng)企業(yè)參加面試,之前準(zhǔn)備多多信心滿滿,但是面試一開始就是一道不起眼的編程題
數(shù)組A內(nèi)容為 1,2,3,4...52 ,數(shù)組B內(nèi)容為26個英文字母,使用兩個線程分別輸入兩個數(shù)組,
打印內(nèi)容為:12a34b56c78e....... 這樣的規(guī)律
當(dāng)時看了一下覺得so easy, 第一思路就是使用wait()/notify() 通過判斷已打印的數(shù)量讓兩個線程交替等待。
但是裝逼情緒一下來了,突然想起了沒怎么使用的CyclicBarrier ,直觀認(rèn)為這種線程閂也能等待,還能計數(shù)
估計也能解決這個問題,于是開始設(shè)計算法,思考了很久,在紙上也推演邏輯,可怎么也想不出來,突然有種
直覺我肯定沒理解透CyclicBarrier的原理,當(dāng)時時間已經(jīng)很緊張了,這道題就這樣被我的裝逼情緒給毀了,
情緒已經(jīng)受到了影響,之后的面試可想而知。
CyclicBarrier 字面意思回環(huán)柵欄,通過它可以實現(xiàn)讓一組線程等待至某個狀態(tài)之后再全部同時執(zhí)行。叫做回環(huán)是因為當(dāng)所有等待線程都被釋放以后,CyclicBarrier可以被重用。我們暫且把這個狀態(tài)就叫做barrier,當(dāng)調(diào)用await()方法之后,線程就處于barrier了。
就像賽馬場上所有騎手都準(zhǔn)備就位后才開始起跑一樣,把這類用于解決上面的面試題完全不合適。:<
回到家里越想越氣,明明幾道題可以回答好卻因為第一道題影響情緒,進(jìn)入了防御思維方式,不能很好的發(fā)揮自己。為了懲罰,我要自己用三種解法解決上面那道面試題。
好吧,進(jìn)入解決的正題。
重溫一個面試題內(nèi)容:
數(shù)組A內(nèi)容為 1,2,3,4...52 ,數(shù)組B內(nèi)容為26個英文字母,使用兩個線程分別輸入兩個數(shù)組,
打印內(nèi)容為:12a34b56c78e....... 這樣的規(guī)律
提取一下核心內(nèi)容,去除次要內(nèi)容
兩個線程需要交替執(zhí)行,打印數(shù)字的線程需要先執(zhí)行,數(shù)組打印完畢后線程需要結(jié)束。
轉(zhuǎn)換成模型,可以理解為 數(shù)字線程先執(zhí)行,字母線程先等待,每次打印相當(dāng)于一個子任務(wù),任務(wù)完畢后
通知另一個線程工作,自己進(jìn)入等待狀態(tài),如此交替往復(fù)直到子任務(wù)全部完畢,再次通知彼此以防對方卡住。
轉(zhuǎn)換成Java中的組件,可以讓線程停下/啟動的方式有如下幾種: suspend/resume(已廢棄),wait/notify(需要鎖對象有點浪費) 或者 Lock/Condition, LockSupport(非常好直接等待和恢復(fù)),自旋鎖(對于這個場景也不錯)
下面是具體實現(xiàn)
自旋鎖
Java代碼
package interview; import java.util.concurrent.atomic.AtomicBoolean; public class PrintNumAndChar1 { public static void main(String[] args) { AtomicBoolean isNum = new AtomicBoolean(true); int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; char[] chars = { "a", "b", "c", "d", "e" }; new PrintNums(nums, isNum).start(); new PrintChars(chars, isNum).start(); } public static class PrintNums extends Thread { private int[] nums; private AtomicBoolean isNum; public PrintNums(int[] a1, AtomicBoolean isNum) { this.nums = a1; this.isNum = isNum; } public void run() { int count = 0; for (int i = 0; i < nums.length; i++) { while (!isNum.get()) { Thread.yield(); } System.out.print(nums[i]); count++; if (count == 2) { isNum.set(false); count = 0; } } isNum.set(false); } } public static class PrintChars extends Thread { private char[] chars; private AtomicBoolean isNum; public PrintChars(char[] a2, AtomicBoolean isNum) { this.chars = a2; this.isNum = isNum; } public void run() { int count = 0; for (int i = 0; i < chars.length; i++) { while (isNum.get()) { Thread.yield(); } System.out.print(chars[i]); count++; if (count == 1) { isNum.set(true); count = 0; } } isNum.set(true); } } }
`
LockSupport(直接等待和恢復(fù))
Java代碼
package interview; import java.util.concurrent.locks.LockSupport; public class PrintNumAndChar2 { public static void main(String[] args) { int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; char[] chars = { "a", "b", "c", "d", "e" }; PrintNums t1 = new PrintNums(nums); PrintChars t2 = new PrintChars(chars); t1.setPrintChars(t2); t2.setPrintNums(t1); t1.start(); t2.start(); } public static class PrintNums extends Thread { private int[] nums; private PrintChars printChars; public PrintNums(int[] a1) { super(); this.nums = a1; } public void setPrintChars(PrintChars printChars) { this.printChars = printChars; } public void run() { int count = 0; for (int i = 0; i < nums.length; i++) { if(count==2){ count = 0; LockSupport.unpark(printChars); LockSupport.park(); } System.out.print(nums[i]); count++; } LockSupport.unpark(printChars); } } public static class PrintChars extends Thread { private char[] chars; private PrintNums printNums; public PrintChars(char[] chars) { super(); this.chars = chars; } public void setPrintNums(PrintNums printNums) { this.printNums = printNums; } public void run() { LockSupport.park(); int count = 0; for (int i = 0; i < chars.length; i++) { if(count==1){ count = 0; LockSupport.unpark(printNums); LockSupport.park(); } System.out.print(chars[i]); count++; } LockSupport.unpark(printNums); } } }
wait/notify(需要鎖對象有點浪費) 或者 Lock/Condition ,我認(rèn)為最渣的實現(xiàn)
Java代碼
package interview; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class PrintNumAndChar3 { public static void main(String[] args) { int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; char[] chars = { "a", "b", "c", "d", "e" }; Lock canPrint = new ReentrantLock(); Condition printNum = canPrint.newCondition(); Condition printChar = canPrint.newCondition(); new PrintNums(nums, canPrint, printNum, printChar).start(); new PrintChars(chars, canPrint, printNum, printChar).start(); } public static class PrintNums extends Thread { private int[] nums; private Condition printNum; private Condition printChar; private Lock canPrint; public PrintNums(int[] nums, Lock canPrint, Condition printNum, Condition printChar) { super(); this.nums = nums; this.printNum = printNum; this.printChar = printChar; this.canPrint = canPrint; } public void run() { int count = 0; try { for (int n : nums) { if (count == 2) { canPrint.lock(); count = 0; printChar.signal(); printNum.await(); canPrint.unlock(); } System.out.print(n); count++; } canPrint.lock(); printChar.signal(); canPrint.unlock(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public static class PrintChars extends Thread { private char[] chars; private Condition printNum; private Condition printChar; private Lock canPrint; public PrintChars(char[] chars, Lock canPrint, Condition printNum, Condition printChar) { super(); this.chars = chars; this.printNum = printNum; this.printChar = printChar; this.canPrint = canPrint; } public void run() { int count = 0; try { Thread.sleep(100); for (char n : chars) { if (count == 1) { canPrint.lock(); count = 0; printNum.signal(); printChar.await(); canPrint.unlock(); } System.out.print(n); count++; } canPrint.lock(); printNum.signal(); canPrint.unlock(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
使用Lock鎖的方式有個問題,我使用了sleep 讓打印字符的線程等待了100毫秒,我沒有找到合適的方式控制兩個同時運行的線程的順序,如果你有什么好方法希望也能分享出來。
記得有個朋友告訴我,要想不斷提高自己就去面試吧,即使你不想換工作,在面試中確實能發(fā)現(xiàn)自己的不足和薄弱的地方。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/65067.html
摘要:一篇文章和一道面試題最近,有篇名為張圖幫你一步步看清和的執(zhí)行順序的文章引起了我的關(guān)注。作者用一道年今日頭條的前端面試題為引子,分步講解了最終結(jié)果的執(zhí)行原因。從字面意思理解,讓我們等等。當(dāng)前的最新版本,在這里的執(zhí)行順序上,的確存在有問題。 一篇文章和一道面試題 最近,有篇名為 《8張圖幫你一步步看清 async/await 和 promise 的執(zhí)行順序》 的文章引起了我的關(guān)注。 作者用...
摘要:前言三年后端開發(fā)經(jīng)驗,面的目標(biāo)崗位是的高級后端開發(fā)。面試結(jié)束,應(yīng)該沒有后續(xù)。 前言 三年Java后端開發(fā)經(jīng)驗,面的目標(biāo)崗位是20k-35k的高級后端Java開發(fā)。 第一場,基本裸面,關(guān)于曾經(jīng)的項目部門答的不好,所以還是得好好準(zhǔn)備。 某C輪在線旅游公司 筆試 先做半個小時的筆試題,一共六個題目,兩道go語言的基礎(chǔ)題,一道斐波那契相關(guān),一道數(shù)據(jù)庫行列轉(zhuǎn)置,一道實現(xiàn)一個棧,還有一道是百萬計...
摘要:這個時候查了下正則表達(dá)式的文檔文檔點擊這里,發(fā)現(xiàn)有一個方法,可以返回匹配成功的結(jié)果。那么我來總結(jié)下文章想表達(dá)的內(nèi)容對于具有固定格式的字符串,可以考慮使用正則表達(dá)式來識別和匹配。 今天在認(rèn)真干(劃)活(水)的時候,看到群里有人發(fā)了一道頭條的面試題,就順便看了一下,發(fā)現(xiàn)挺有意思的,就決定分享給大家,并且給出我的解決方案和思考過程。 題目如下: 實現(xiàn)一個get函數(shù),使得下面的調(diào)用可以輸出正確...
摘要:這個時候查了下正則表達(dá)式的文檔文檔點擊這里,發(fā)現(xiàn)有一個方法,可以返回匹配成功的結(jié)果。那么我來總結(jié)下文章想表達(dá)的內(nèi)容對于具有固定格式的字符串,可以考慮使用正則表達(dá)式來識別和匹配。 今天在認(rèn)真干(劃)活(水)的時候,看到群里有人發(fā)了一道頭條的面試題,就順便看了一下,發(fā)現(xiàn)挺有意思的,就決定分享給大家,并且給出我的解決方案和思考過程。 題目如下: 實現(xiàn)一個get函數(shù),使得下面的調(diào)用可以輸出正確...
閱讀 3258·2021-10-11 10:59
閱讀 2812·2021-10-11 10:58
閱讀 2244·2021-09-04 16:45
閱讀 2717·2019-08-30 15:44
閱讀 671·2019-08-30 15:44
閱讀 3199·2019-08-30 10:51
閱讀 1597·2019-08-29 18:46
閱讀 2749·2019-08-29 13:57