2017-05-03 19 views
1

これは私が以前に質問したのと同じコードですが、別の問題に対処しています。基本的に私は2つのスレッドを持つ銀行口座を作ろうとしており、それぞれが口座のユーザーを表しています。ユーザーはアカウントから20ドルを入金して引き出します(ランダムに)。スレッドを1つずつ実行する(パラレルの代わりに)

ただし、これらのスレッドは両方とも同時に実行され、引き出し/デポジットは同時にに発生します。私は両方のスレッドを制限して、別のスレッドが独自のrunメソッドを実行する前に終了するのを待ちます。

以下はコードです。

スレッドの作成クラス

import java.util.Random; 
import java.util.concurrent.atomic.AtomicInteger; 

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

BankAccount(String name){ 
    threadName = name; 
} 
public void run(){ 
    System.out.println(threadName + "account initiated."); 
    for(int i = 0; i < 10; i++){ 
     try{ 
      Random rand = new Random(); 
      int num = rand.nextInt(2) + 1; 
      if(num == 1){ 
       Thread.sleep(200); //0.2 seconds to deposit 
       System.out.println(threadName + " is depositing 20$ in the bank."); 
       balance += 20; 
       System.out.println("The new balance is " + balance + "dollars"); 
      } 
      else{ 
       Thread.sleep(500); //half a second to withdraw 
       System.out.println(threadName + " is withdrawing 20$ from the bank."); 
       balance -= 20; 
       System.out.println("The new balance is " + balance + "dollars."); 
       } 
     } 
     catch(InterruptedException e){ 
      System.out.println("Process terminated."); 
      } 
     } 
    } 
} 

スレッド・ドライバクラス

public class BankAccountSimDriver { 
    public static void main(String[] args){ 
    Thread user1 = new BankAccountSIm("user1"); 
    Thread user2 = new BankAccountSIm("user2"); 

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

出力現在:現在

user1 initiated. 
user2 initiated. 
user1 is depositing 20$ in the bank. 
user2 is depositing 20$ in the bank. 
The new balance is 1020.0 dollars 
The new balance is 1040.0 dollars 
user2 is depositing 20$ in the bank. 
The new balance is 1060.0 dollars 
user1 is withdrawing 20$ from the bank. 
The new balance is 1040.0 dollars. 

、user1とuser2の実行を同時に。私は、コードを編集したいのですが、そのような唯一のユーザーは、堆積させることができること/だから、理想的な出力(スリープ()の時間間隔で示されている)時間

で撤退:

user1 initiated. 
//wait 0.2 seconds 
user1 is depositing 20$ in the bank. 
The new balance is 1020.0 dollars 
user2 initiated. 
//wait 0.2 seconds 
user2 is depositing 20$ in the bank. 
The new balance is 1040.0 dollars 
//wait 0.5 seconds 
user1 is withdrawing 20$ from the bank. 
The new balance is 1020.0 dollars. 
... 
+2

スレッドを同時に実行したくない場合は、どうしてですか? –

+0

ランダムな値に基づいて1つのスレッドで預金と引き出しを行っています。なぜ、2番目のスレッドuser2.start()を開始しますか? –

+0

スレッドを使用して2人の異なる人物が1つのアカウントでアクションを実行します。より単純で効率的な選択肢がありますか? (New to Java、あなたが分かるように) –

答えて

2

はあなたが必要なものがありますスレッドをシリアル化するのではなく、balanceへの同時アクセスを管理するには、少なくともbalanceへのアクセスをシリアル化する必要があります。それに取り組むには多くの方法があります。基本的にはのロックが必要です。これは、一方のスレッドのみがbalanceの変更を行うために使用され、もう一方のスレッドはロックが解除されるまでブロックされます。

まず、BanckAccountとそのユーザーを分ける必要があります。

class BankAccount { ... } 

class User implements Runnable { 
    private BankAccount account; 
    public User(BankAccount account) { 
     this.account = account; 
    } 
    public void run() { 
     // do something... 
    } 
} 

class Test { 
    public static void main(String []a) { 
     // One account 
     BankAccount a = new BankAccount(); 
     // Shared by 2 users 
     User user1 = new User(a); 
     User user2 = new User(a); 
     // Make users behave concurrently 
     Thread t1 = new Thread(user1); 
     Thread t2 = new Thread(user2); 
     t1.start(); 
     t2.start(); 
     // Wait 'til the end of the users activity 
     t1.join(); 
     t2.join(); 
    } 
} 

ここで、ユーザーから同じ銀行口座の同時アクセスを管理する方法はありますか?

class BankAccount { 
    private int balance; 
    public BankAccount(int initialBalance) { 
     balance = initialBalance; 
    } 
    public synchronized int deposit(int amount) { 
     balance += amount; 
     return balance; 
    } 
    public synchronized int withdraw(int amount) { 
     balance -= amount; 
     return balance; 
    } 
} 

そうな方法は、このように何の2つのスレッドがでバランスを変更することはできません、​​をマーク内部には2つのスレッドが同時になることはできませんことを保証します:あなたはBankAccount方法​​を行うことで、暗黙的なロックとしてBankAccountオブジェクトを使用することができます同じ時間。

しかし...(同時実行は微妙な問題につながる)...それぞれのスレッドがbalanceのキャッシュされたコピーを使用するので、volatileとしてそのフィールドをマークするために、一般的にはより適切であることが起こる可能性があります

private volatile int balance; 

このような単純な状況では、いくつかのことが単純化されるかもしれないが、私はあなたに何が問題であり、どのように解決できるかを示してみた。また、このコードでも奇妙な出力が発生する可能性がありますが、残高が正しいことが保証されています(現在は並行処理を掘り下げています)。

関連する問題