標籤:turn 提醒 最小 cte print 解決方案 數組下標 throw array
1、這段代碼大多數情況下運行正常,但是某些情況下會出問題。什麼時候會出現什麼問題?如何修正?
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);這句代碼有可能引發數組下標越界
原因(答案來源互連網,非本人回答):
假設其中一種情形呵!出問題的情形可能很多,但原理都差不多。下面的標號代表程式時序的先後順序。
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),越界錯誤就產生了。
改進:
改進1,——最小代碼改動,就在remove之前再檢查list.size==0
改進2,——去掉push和pop方法內的第二重鎖檢查,我確實沒有發現這個鎖會有什麼用,反而耗效能。 當然這裡還是要有方案1的判斷(謝謝一樓提醒)。
改進3,——重新設計,如果是我來設計這麼一個生產者,消費者模式。我更願意用LinkedBlockingQueue,它有take方法阻塞消費者直到隊列可用。而且還有offer方法阻塞生產者直到隊列可以插入,可以有效阻止OOM。
2、寫一段代碼實現銀行轉帳功能,從轉出帳號中扣除轉帳金額,給轉入帳號增加轉帳金額,保證兩個操作 要麼同時成功,要麼同時失敗
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);}
這道題考察對事務的理解。如果轉出和轉入操作都在同一個應用裡面進行,使用資料庫的事務特性就可以做到“要麼同時成功,要麼同時失敗”;否則就要用分散式交易的方案來解決,先消化一下這篇文章《分布式系統事務一致性解決方案》。
3、實現統計某一目錄下每個檔案中出現的字母個數、數字個數、空格個數及行數?
/*常值內容僅限數字,字母,及空格*/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 ); } }}
4、假如有字串“6sabcsfs33” ,用最有快速的方法去掉字元“ab3”,不能用java內建字串方法(indeOf,substring,replaceAll等)
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()); }
Java面試題和解答(三)