2017-05-02 1 views
2

하나의 은행 계좌에서 돈을 인출하고 입금하는 두 명의 사용자를 시뮬레이트하기 위해 멀티 스레딩을 사용하려고합니다. 두 명의 사용자가 단일 공유 변수에 대해 조치를 취하고 물론 계정 잔액을 나타내는 것이 좋습니다.여러 스레드에서 전역 필드 액세스 및 편집

돈을 입금하거나 인출하기위한 조치는 무작위로 1 개 또는 2 개 선택됩니다 (입금 및 인출). 예금 할 때 예금 조치를 1 초, 철회 조치를 0.5 초로하고 싶습니다. 이 시간 간격에서 스레드는 다른 스레드가 자체를 철회/입금하기 전에 조치를 완료 할 때까지 기다려야합니다.

그러나 가장 큰 문제는 두 스레드가 각각 단일 공유 숫자 필드 인 저울을 편집 할 수 있다는 것입니다. 처음 시도했을 때, 각 쓰레드는 자체적 인 균형 인스턴스를 생성하고 별도로 작동했습니다. 인스턴스 필드가 아닌 전역 필드 "balance"에 영향을주는 각 스레드의 작업 (인출/입금)을 원합니다.

스레드 클래스 및 드라이버 클래스 지금까지 작성한 클래스는 다음과 같습니다.

스레드 작성자 클래스 :

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."); 
      } 
     } 
    } 
} 

나사 드라이버 클래스 :

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

을 사용할 수도 있습니다.'Thread'에서'BankAccountSim'을 확장하는 것보다는 간단하게 만드십시오. 이 클래스의 단일 인스턴스를 만든 다음 스레드에 전달하여 스레드에서 작업을 수행해야합니다. 'BankAccountSim'은 계좌에'withdraw' 또는'deposit'하는'synchronized' 메소드를 제공해야합니다. – MadProgrammer

+0

그리고 정말로이 코드를 사용하고 싶다면 Money는 절대로'double '이되어서는 안됩니다. –

답변

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

Luke- 매우 도움이되었지만 한 가지 문제가 있습니다. 동기화 된 입금을 호출하고 메소드를 인출 할 수 있도록 BankAccount 클래스에 run() 메소드를 작성하려면 어떻게해야합니까? 또는 나는 무엇인가 놓치고 있냐? –

0

그것은 당신이 스레드로 BankAccount 생각하지 않는다, 그것의 자신의 스레드를 원하는하지만 흥미는 작업은 스레드입니다. 이 디자인에 대한 한 가지 유의 사항. 내 개인적인 어림짐작은 원시 타입에 대해서만 volatile을 사용합니다. balanceDouble 또는 다른 객체로 변경하는 경우 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; 

public AtomicInteger balance = new AtomicInteger(1000); 

하는 그러나 약간 당신을 업데이트하는 방법을 수정해야합니다 추가 할 잔액 예 :

balance.addAndGet(1); 
관련 문제