2017-05-02 62 views
2

我正在嘗試使用多線程來模擬單個銀行帳戶上的兩個用戶,提取和存款。我希望兩位用戶能夠使用一個共享變量,當然這代表了賬戶餘額。關於多線程訪問和編輯全局字段

存款或取款的操作是隨機選取的 - 1或2(分別存入和取出)。存款時,我要求存款操作需要1秒,撤回操作需要0.5秒。在這個時間間隔內,線程必須等待另一個線程完成一個動作,然後才能撤回/存放它自己。

然而,我最大的問題是兩個線程如何編輯單個共享數字字段,即餘額。我第一次嘗試時,每個線程都創建了自己的平衡實例,並分別對它們執行操作。我希望每個線程的行動(撤回/存款)影響全球領域的「平衡」 - 而不是實例領域。

線程類和驅動程序類我到目前爲止列出如下。

主題Creator類:

public class BankAccountSim extends Thread{ 
public double balance = 1000; 
public String threadName; 

BankAccountSim(String name){ 
    threadName = name; 
} 
public void run(){ 
    System.out.println(threadName + "account initiated."); 
    while(true){ 
     try{ 
      Random rand = new Random(); 
      int num = rand.nextInt(2) + 1; 
      if(num == 1){ 
       System.out.println(threadName + " is depositing in the bank."); 
       balance += 1; 
       System.out.println("The new balance is " + balance + " dollars"); 
       Thread.sleep(1000); 
       Thread.yield(); 
      } 
      else{ 
       System.out.println(threadName + " is withdrawing from the bank."); 
       balance -= 1; 
       System.out.println("The new balance is " + balance + " dollars."); 
       Thread.sleep(500); 
       Thread.yield(); 
       } 
     } 

     catch(InterruptedException e){ 
      System.out.println("Process terminated."); 
      } 
     } 
    } 
} 

主題Driver類:

import java.util.concurrent.ThreadLocalRandom; 
import java.util.Random; 

public class BankAccountSimDriver { 
    public static void main(String[] args){ 

    Thread user1 = new BankAccountSim("user1"); 
    Thread user2 = new BankAccountSim("user2"); 

    user1.start(); 
    user2.start(); 

    } 
} 
+0

您可以使'balance'靜態,甚至可以使用AtomicInteger –

+0

而不是使'BankAccountSim'從'Thread'擴展,只需將其設置爲一個簡單的類。創建此類的單個實例,然後將其傳遞給線程,然後線程應該對其執行操作。 'BankAccountSim'應該提供'同步'的方法'撤回'或'存入'賬戶 – MadProgrammer

+0

,如果你真的想要使用這個代碼,那麼金錢不應該是一個'雙' –

回答

0

這主要是一個設計問題。您最好創建一個銀行賬戶並與客戶分享,就像在現實世界中一樣。

interface BankAccount { 
    // Query the balance 
    BigDecimal balance(); 

    // Make a deposit and return the new balance 
    BigDecimal deposit(BigDecimal amount); 

    // Make a withdrawal and return the new balance 
    BigDecimal withdraw(BigDecimal amount); 
} 

// Implements the Runnable interface for run in another thread. 
class BankClient implements Runnable { 
    private final String clientName; 

    private final BankAccount bankAccount; 

    public BankClient(String clientName, BankAccount bankAccount) { 
     this.clientName = clientName; 
     this.bankAccount = bankAccount; 
    } 

    public void run() { 
     // while(true) ... 
    } 
} 

class SimpleBankAccount implements BankAccount { 
    private BigDecimal balance = BigDecimal.ZERO; 

    public SimpleBankAccount(BigDecimal initialBalance) { 
     this.balance = initialBalance; 
    } 

    public synchronized BigDecimal balance() { 
     return balance; 
    } 

    public synchronized BigDecimal deposit(BigDecimal amount) { 
     return balance = balance.add(amount); 
    } 

    public synchronized BigDecimal withdraw(BigDecimal amount) { 
     if (balance.compareTo(amount) < 0) { 
      throw new RuntimeException("Not enough balance."); 
     } 
     return balance = balance.subtract(amount); 
    } 
} 

public class SimDriver { 
    public static void main(String[] args) throws Exception { 
     BankAccount account = new SimpleBankAccount(BigDecimal.valueOf(1000)); 

     Thread t1 = new Thread(new BankClient("client-1", account)); 
     thread t2 = new Thread(new BankClient("client-2", account)); 

     t1.start(); 
     t2.start(); 

     t1.join(); 
     t2.join(); 
    } 
} 
+0

Hi Luke-非常有幫助,但有一個問題:如何在BankAccount類中編寫run()方法,以便我可以調用同步存款和提取方法?或者我錯過了什麼? –

0

想要一個在它自己的線程,但不認爲BankAccount爲主題的有意思的是,該行動是主題。關於這個設計的一個註釋。我個人的經驗法則是我只對原始類型使用volatile。如果您將balance更改爲Double或其他某個對象,請鎖定Object或使用AtomicReference或其他東西。

public class BankAccount { 
    static volatile double balance = 0; 

    public void deposit(double amount) { 
     class Deposit implements Runnable { 
      double amount; 
      Deposit(double d) { amount = d; } 
      public void run() { 
       balance += amount; 
      } 
     } 
     new Thread(new Deposit(amount)).run(); 
    } 
    public synchronized void withdraw(double amount) { 
     class Withdraw implements Runnable { 
      double amount; 
      public Withdraw(double d) { amount = d; } 
      public void run() { 
       balance -= amount; 
      } 
     } 
     new Thread(new Withdraw(amount)).run(); 
    } 

    // 
    // A little Test 
    // 
    public static void main(String[] args) { 
     BankAccount ba = new BankAccount(); 

     ba.deposit(34576.2); 
    } 
} 
0

一個簡單的解決辦法是通過改變做出平衡的AtomicInteger

public double balance = 1000; 

TO

public AtomicInteger balance = new AtomicInteger(1000); 

但是,您將需要稍微修改你如何更新餘額,例如添加到它:

balance.addAndGet(1);