6

アカウントの状態を管理するAccountServiceというクラスがあるとします。

AccountServiceは次のように定義されます

interface AccountService{
 public void debit(account);
 public void credit(account);
 public void transfer(Account account, Account account1);

}

この定義を前提として、transfer()を実装して、transferがアトミック操作であることを保証できるようにするための最良の方法は何ですか。

Java 1.4コードを参照する回答と、Java5のjava.util.concurrentのリソースを使用する可能性のある回答に興味があります。

4

5 に答える 5

11

両方のAccountオブジェクトで同期し、転送を実行します。常に同じ順序で同期するようにしてください。これを行うには、Accountsを実装Comparableし、2つのアカウントを並べ替えて、この順序で同期します。

アカウントを注文しない場合、1つのスレッドがAからBに転送され、別のスレッドがBからAに転送されると、デッドロックが発生する可能性があります。

この正確な例は、マルチスレッドJava開発を行うすべての人にとって重要な本であるJava ConcurrencyinPracticeの207ページで説明されています。サンプルコードは、発行元のWebサイトから入手できます。

于 2010-06-02T14:31:39.010 に答える
3

ここで非常によく説明されている古典的な例-http ://www.javaworld.com/javaworld/jw-10-2001/jw-1012-deadlock.html?page=4

于 2010-06-02T14:34:26.967 に答える
2

おそらく完全なトランザクションサポートが必要です(もちろん実際のアプリケーションの場合)。

ソリューションの難しさは、環境にほとんど依存しません。システムについて詳しく説明してください。サポートを提供します(どのようなアプリケーションですか?Webサーバーを使用しますか?どのWebサーバーを使用しますか?データの保存に何を使用しますか?など)。

于 2010-06-02T14:31:41.117 に答える
1

すべてのアクセスが転送メソッドを介して行われることを保証できる場合、おそらく最も簡単なアプローチは、転送を同期メソッドにすることです。これにより、一度に1つのスレッドのみが転送メソッドを実行することが保証されるため、これはスレッドセーフになります。

他のメソッドもAccountServiceにアクセスする可能性がある場合は、それらすべてに単一のグローバルロックを使用させることを決定できます。これを行う簡単な方法は、AccountServiceにアクセスするすべてのコードを同期(X){...}ブロックで囲むことです。ここで、Xは共有/シングルトンオブジェクトインスタンス(AccountServiceインスタンス自体である可能性があります)です。異なるメソッドにある場合でも、一度に1つのスレッドのみがAccountServiceにアクセスするため、これはスレッドセーフになります。

それでも十分でない場合は、より高度なロック方法を使用する必要があります。一般的なアプローチの1つは、アカウントを変更する前に個別にロックすることです...しかし、一貫した順序で(たとえば、アカウントIDによって)ロックを取得するように非常に注意する必要があります。そうしないと、デッドロックが発生します。

最後に、AccountServiceがリモートサービスである場合は、分散ロック領域にいます。コンピュータサイエンスの博士号と何年にもわたる研究予算がない限り、おそらくそこに行くことは避けてください。

于 2010-06-02T14:50:16.157 に答える
0

AtomicReference<Double>一緒に、アカウントの残高にを使用して同期する必要がありませんか?get()set()

于 2010-06-02T14:42:05.540 に答える