1. 程式人生 > >剛從螞蟻金服面試出來的被問到的10道面試題

剛從螞蟻金服面試出來的被問到的10道面試題

下面的例子演示了100個執行緒同時向一個銀行賬戶中存入1元錢,在沒有使用同步機制和使用同步機制情況下的執行情況。     銀行賬戶類: /**  * 銀行賬戶  * @author 駱昊  *  */ public class Account {     private double balance;     // 賬戶餘額     /**      * 存款      * @param money 存入金額      */     public void deposit(double money) {         double newBalance = balance + money;         try {             Thread.sleep(10);   // 模擬此業務需要一段處理時間         }         catch(InterruptedException ex) {             ex.printStackTrace();         }         balance = newBalance;     }     /**      * 獲得賬戶餘額      */     public double getBalance() {         return balance;     } }     存錢執行緒類: /**  * 存錢執行緒  * @author 駱昊  *  */ public class AddMoneyThread implements Runnable {     private Account account;    // 存入賬戶     private double money;       // 存入金額     public AddMoneyThread(Account account, double money) {         this.account = account;         this.money = money;     }     @Override     public void run() {         account.deposit(money);     } }     測試類: import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Test01 {     public static void main(String[] args) {         Account account = new Account();         ExecutorService service = Executors.newFixedThreadPool(100);         for(int i = 1; i <= 100; i++) {             service.execute(new AddMoneyThread(account, 1));         }         service.shutdown();         while(!service.isTerminated()) {}         System.out.println("賬戶餘額: " + account.getBalance());     } } 在 沒有同步的情況下,執行結果通常是顯示賬戶餘額在10元以下,出現這種狀況的原因是,當一個執行緒A試圖存入1元的時候,另外一個執行緒B也能夠進入存款的方 法中,執行緒B讀取到的賬戶餘額仍然是執行緒A存入1元錢之前的賬戶餘額,因此也是在原來的餘額0上面做了加1元的操作,同理執行緒C也會做類似的事情,所以最 後100個執行緒執行結束時,本來期望賬戶餘額為100元,但實際得到的通常在10元以下(很可能是1元哦)。解決這個問題的辦法就是同步,當一個執行緒對銀 行賬戶存錢時,需要將此賬戶鎖定,待其操作完成後才允許其他的執行緒進行操作,程式碼有如下幾種調整方案:     在銀行賬戶的存款(deposit)方法上同步(synchronized)關鍵字 /**  * 銀行賬戶  * @author 駱昊  *  */ public class Account {     private double balance;     // 賬戶餘額     /**      * 存款      * @param money 存入金額      */     public synchronized void deposit(double money) {         double newBalance = balance + money;         try {             Thread.sleep(10);   // 模擬此業務需要一段處理時間         }         catch(InterruptedException ex) {             ex.printStackTrace();         }         balance = newBalance;     }     /**      * 獲得賬戶餘額      */     public double getBalance() {         return balance;     } }     線上程呼叫存款方法時對銀行賬戶進行同步 /**  * 存錢執行緒  * @author 駱昊  *  */ public class AddMoneyThread implements Runnable {     private Account account;    // 存入賬戶     private double money;       // 存入金額     public AddMoneyThread(Account account, double money) {         this.account = account;         this.money = money;     }     @Override     public void run() {         synchronized (account) {             account.deposit(money);          }     } }     通過Java 5顯示的鎖機制,為每個銀行賬戶建立一個鎖物件,在存款操作進行加鎖和解鎖的操作 import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /**  * 銀行賬戶  *   * @author 駱昊  *  */ public class Account {     private Lock accountLock = new ReentrantLock();     private double balance; // 賬戶餘額     /**      * 存款      *       * @param money      *            存入金額      */     public void deposit(double money) {         accountLock.lock();         try {             double newBalance = balance + money;             try {                 Thread.sleep(10); // 模擬此業務需要一段處理時間             }             catch (InterruptedException ex) {                 ex.printStackTrace();             }             balance = newBalance;         }         finally {             accountLock.unlock();         }     }     /**      * 獲得賬戶餘額      */     public double getBalance() {         return balance;     } } 按照上述三種方式對程式碼進行修改後,重寫執行測試程式碼Test01,將看到最終的賬戶餘額為100元。當然也可以使用Semaphore或CountdownLatch來實現同步。