java-多线程-一道阿里面试题分析
生活随笔
收集整理的這篇文章主要介紹了
java-多线程-一道阿里面试题分析
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
2019獨角獸企業重金招聘Python工程師標準>>>
傳說這是阿里的一道面試題: 也傳說發這道題出來的作者去了tmail。下面是關于題目的描述:
? ? ?這段代碼大多數情況下運行正常,但是某些情況下會出問題。什么時候會出現什么問題?如何修正?可見博客?http://yueyemaitian.iteye.com/blog/1387901?
Java代碼??下面是關于這道題的分析:
? ?list.remove(list.size() - 1);這句代碼有可能引發數組下標越界
原因:
假設其中一種情形呵!出問題的情形可能很多,但原理都差不多。下面的標號代表程序時序的先后順序。
?1,初始化時list的值為0,然后線程1調用了pop,于是被wait了,然后釋放了鎖。
?2,線程2調用push,在notify之前有線程3調用pop(記住這時候線程1還沒有被喚醒,還在wait住),此時線程3會因為等待鎖而掛起,或自旋,反正就是在等待鎖可用。 ?3,然后線程2繼續往下執行,notify被執行(但這時候線程1是不會喚醒的,因為鎖還在線程2占用),線程2退出push方法,釋放內置鎖,此時,線程1和線程3都在內置鎖等待隊列里面。由于synchronized是沒法保證線程競爭的公平性,所以線程1和線程3都可能得到鎖。
?4,假設線程1競爭到了鎖,不會出問題,正常去除list值,然后remove,執行完后線程3執行,同樣被wait住。
?5,假設線程3競爭到了鎖,問題來了,線程3會判斷到list的size不為0,于是remove,所以list的size就為0了,然后線程 3釋放鎖,這時候,線程1就得到鎖,于是從wait中醒來,繼續執行,然后直接調用list的remove,由于list的size=0,那么remove(-1),越界錯誤就產生了。
? ?還有同學說兩個線程都在wait處等候也會出問題,其實不會出問題的,因為是調用的notify而不是notifyAll,如果是調用notifyAll那么也會出同樣的問題。
? 至于改進: ? 看到這個題目我就很納悶,為什么要用雙重鎖,好像沒有必要雙重鎖。我第一眼看到雙重鎖的時候就在想,出題者是不是在模擬一個套管死鎖,我也確實為找這個死鎖付出了一些時間。但是這個雙重檢查都是可重入的鎖,都是對于this對象上的鎖。所以不存在套管死鎖。 改進1,——最小代碼改動,就在remove之前再檢查list.size==0 改進2,——去掉push和pop方法內的第二重鎖檢查,我確實沒有發現這個鎖會有什么用,反而耗性能。 當然這里還是要有方案1的判斷(謝謝一樓提醒)。 改進3,——重新設計,如果是我來設計這么一個生產者,消費者模式。我更愿意用LinkedBlockingQueue,它有take方法阻塞消費者直到隊列可用。而且還有offer方法阻塞生產者直到隊列可以插入,可以有效的阻止OOM。
? 這個題目出的好,難道是阿里有人犯過這個錯誤!呵呵!
? 關于本題的討論如有任何紕漏,請大家及時指出呵!
轉載于:https://my.oschina.net/u/176507/blog/137880
總結
以上是生活随笔為你收集整理的java-多线程-一道阿里面试题分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 梦到蛇和蝙蝠是什么意思
- 下一篇: 关于Binder的点点滴滴(二)