2016-08-06 12 views
1

すべてのアカウントが同期されていると、自分のコードに競合状態が存在するのはなぜですか?どのように競合状態がありますか?

class Transfer implements Runnable { 

    Konto fromAccount; 
    Konto toAccount; 
    Integer amount; 

    public void run() { 
     synchronized (fromAccount) { 
      if (fromAccount.book(-amount)) { 
       toAccount.book(amount); 
      } 
     } 
    } 
} 
public class Main { 
    public static void main(String[] args) throws InterruptedException 

     Account thomas = new Account(1234, 100); 
     Account mathias = new Account(5678, 100); 
     Thread transfer1 = new Thread(new Transfer(80, thomas, mathias)); 
     Thread transfer2 = new Thread(new Transfer(95, mathias, thomas)); 
     transfer1.start(); 
     transfer2.start(); 
     transfer1.join(); 
     transfer2.join(); 
} 

そのfromAccount(トーマス)をロックし、transfer2はそのfromAccount(マティアス)をロックしますので、彼らの両方がデッドロックに終わるべきではないtransfer1私の理解から、?

+1

デッドロックや競合状態がありますか?あなたは両方に言及しますが、彼らは異なっています。潜在的なレースをしているように見えますが、一目見てデッドロックではありません。 – Brick

答えて

1

コードtoAccount.book(amount)が同期保護で実行されないという問題があります。

だから、技術的にそれが起こる可能性があり、そのスレッド1はthomasAccountにロックを保持し、スレッド2はmathiasAccountのロックを保持しているが、スレッド1がthomasAccount上で本を実行してスレッド2がまだ同時にthomasAccountの本を実行します。これは、スレッドの1つが第2のスレッドからの結果を無視できるため、矛盾する可能性があります。

アカウントで操作しているスレッドは、プラスかマイナスかにかかわらず、まずアカウントをロック(同期化)する必要があります。

デッドロックを回避するには、アカウントを同等にするか(またはアカウントのIDを使用する)、アカウントを常に昇順にロックします。または、ハッシュを使用することもできますが、ハッシュが同じ場合はグローバルロックが必要です。

+0

答えに感謝しますが、私はまだ完全に理解していません。 thread1が 'thomasAccount'でロックを保持している場合、thread2は' thomasAccount'で本をどのように実行できますか? – Numb3rs

+0

スレッド2は、同じロックを取得しようとするときにのみ停止します。 'book()'の呼び出し自体はロックを行いません。 –

+0

もう一度おねがいします、あなたは本当にここで私を助けています! それを正しく理解すれば、ロックされたオブジェクトは、ロックを取得しようとしていない限り、他のスレッドからメソッド呼び出しなどでアクセスできます。そうですか? – Numb3rs

1

runメソッドはfromAccountでのみ同期し、toAccountでは同期しません。同期されていないコードは、同期コードによってブロックされません。何かにアクセスしようとしている2つのスレッドは、の両方でアクセスをシリアライズするためにはに同期する必要があります。

だからあなたrun方法はそれを待つようにするtoAccount上の任意の同期のための順序で、fromAccountにするだけでなく、toAccount上だけではなく、同期する必要があります。

関連する問題