一、這段代碼大多數狀況下運行正常,可是某些狀況下會出問題。何時會出現什麼問題?如何修正?css
public class MyStack { private List<String> list = new ArrayList<String>(); public synchronized void push(String value) { synchronized (this) { list.add(value); notify(); } } public synchronized String pop() throws InterruptedException { synchronized (this) { if (list.size() <= 0) { wait(); } return list.remove(list.size() - 1); } } }
list.remove(list.size() - 1);這句代碼有可能引起數組下標越界html
緣由(答案來源互聯網,非本人回答):
假設其中一種情形呵!出問題的情形可能不少,但原理都差很少。下面的標號表明程序時序的前後順序。
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),越界錯誤就產生了。java
改進:git
改進1,——最小代碼改動,就在remove以前再檢查list.size==0
改進2,——去掉push和pop方法內的第二重鎖檢查,我確實沒有發現這個鎖會有什麼用,反而耗性能。 固然這裏仍是要有方案1的判斷(謝謝一樓提醒)。
改進3,——從新設計,若是是我來設計這麼一個生產者,消費者模式。我更願意用LinkedBlockingQueue,它有take方法阻塞消費者直到隊列可用。並且還有offer方法阻塞生產者直到隊列能夠插入,能夠有效的阻止OOM。數據庫
二、寫一段代碼實現銀行轉賬功能,從轉出賬號中扣除轉賬金額,給轉入賬號增長轉賬金額,保證兩個操做 要麼同時成功,要麼同時失敗數組
public interface ITransfer { /** * fromAccountId 轉出賬號 toAccountId 轉入賬號 amount 轉賬金額 **/ public void transferInner(String fromAccountId, String toAccountId, BigDecimal amount); /** * 外部轉賬-轉出,從轉出賬號中扣除轉賬金額 fromAccountId 轉出賬號 amount 轉賬金額 **/ public void transferOut(String fromAccountId, BigDecimal amount); /** * 外部轉賬-轉入,給轉入賬號增長轉賬金額 toAccountId 轉入賬號 amount 轉賬金額 */ public void transferIn(String toAccountId, BigDecimal amount); }
這道題考察對事務的理解。若是轉出和轉入操做都在同一個應用裏面進行,使用數據庫的事務特性就能夠作到「要麼同時成功,要麼同時失敗」;不然就要用分佈式事務的方案來解決,先消化一下這篇文章《分佈式系統事務一致性解決方案》。分佈式
三、實現統計某一目錄下每一個文件中出現的字母個數、數字個數、空格個數及行數?性能
/*文本內容僅限數字,字母,及空格*/ import java.io.*; class Ex6_5 { public static void main ( String[] args ) { String fileName = "C:/Hello.txt" , line; int i,j,f,k; try { BufferedReader in = new BufferedReader(new FileReader( fileName ) ); line = in.readLine(); //讀取一行內容 while ( line != null ) { if(Character.isLetter(line)) i++; else if(Character.isDigit(line)) j++; else f++; line = in.readLine(); k++ } in.close(); System.out.println("字母"+i+"數字"+j+"空格"+j+"行數"+k) } catch ( IOException iox ) { System.out.println("Problem reading " + fileName ); } } }
四、假若有字符串「6sabcsfs33」 ,用最有快速的方法去掉字符「ab3」,不能用java內置字符串方法(indeOf,substring,replaceAll等)this
String regx = "[^a|b|3]"; String temp = "6sabcsssfsfs33"; Pattern p = Pattern.compile(regx); Matcher m = p.matcher(temp); while (m.find()) { System.out.print(m.group()); }