1

Android アプリでクラス オブジェクトのリストを一元的に更新してアクセスするためのスレッド セーフな方法を実装する際に問題が発生しています。これは公開タイプの質問であり、多くのソース コードを提供することはできません。

基本的に、アクティビティとサービスを備えたアプリがあります。サービスは、UDP ブロードキャスト タスクと UDP ブロードキャスト リスニング タスクを実装します。ブロードキャストされた情報は、基本的に、デバイスを表すクラスの JSON シリアル化されたコピーです。例: UUID、IP、ユーザー セット名、説明などの管理情報。JSON は UDP パケットに格納されて送信され、UDP パケットは受信され、デシリアライズされて処理されます。その逆シリアル化されたクラスは Hashtable に格納され、現在のインスタンスは Service に属します。たとえば、データへのアクセスを希望するすべての人は、サービスを通過する必要があります。全体が非常に非同期です。

Activity は (Binder の拡張を介して) サービスにバインドされるため、UDP タスクの開始/停止などの Service メソッドを呼び出すことができます。アクティビティは、更新または新しいデバイス データが受信されたときにサービスが発行する Android インテントをリッスンし、受信した UDP パケット データに関連する情報を UI に表示します。パケット データは、Service に属するコンテナ クラスに格納されていることに注意してください。

問題は、受信したデータのハッシュテーブルをスレッドセーフにする適切な方法を見つけられないことです。Service メソッドからデータを取得して処理すると、java.util.ConcurrentModificationException エラーが発生します。ループ (反復子または for) でデータを処理している間にデータが更新されると、ConcurrentModificationException が発生します。どこで、いつ、なぜなのかはわかっていますが、lock() または ReentrantLock() の使用は、通常、そのコンテナー クラスの外部で処理するために返される単一ポイント データではなく、データをロックするクラスのメソッド呼び出し内で利用されます。次のようなもの: (ReentrantLock() ではなく syncronized を使用している場合、これは単なる例です)

public class sampleLockClass {
    private Hashtable<String, String> sampleData = new Hashtable<String, String>();
    public sampleLockClass() {}
    public synchronized put(String s1, String s2) {
        this.sampleData().put(s1, s2);
    }
    public synchronized Hashtable<String, String> getAll() {
        return this.sampleData; // This is returned for the processing outside the class
    }
}

この場合、 getAll() メソッドは、クラス自体の外部での処理に必要な sampleData Hashtable を返しています。この理由は、私が利用している他の A​​PI にデータが渡され、それらの API がこのアプローチと互換性がないためです。たとえば、その使用のために単一のスレッドセーフなコピーがあることを期待しています。

これはばかげているか問題ではないかもしれませんが、返された sampleData を必要な期間だけスレッドセーフにするにはどうすればよいでしょうか? 現時点では、Service だけが sampleData に書き込むことに注意してください。それ以外はすべて読み取り専用であり、Intent を介して CommService を介して Activity から sampleData への更新をコミットしようとする可能性があります。

get() メソッドごとに Hashtable sampleData のコピーを作成する方が安全でしょうか?

4

1 に答える 1

0

http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ConcurrentHashMap.html

取得の完全な同時実行性と更新の調整可能な予想同時実行性をサポートするハッシュ テーブル。このクラスは、Hashtable と同じ機能仕様に従い、Hashtable の各メソッドに対応するバージョンのメソッドを含みます。

通常、取得操作 (get を含む) はブロックされないため、更新操作 (put および remove を含む) と重複する場合があります。検索は、開始時に保持されている最新の更新操作の結果を反映します。putAll や clear などの集計操作の場合、同時取得では、一部のエントリのみの挿入または削除が反映される場合があります。

更新操作間で許可される同時実行数は、オプションの concurrencyLevel コンストラクター引数 (デフォルト 16) によってガイドされます。これは、内部サイズ設定のヒントとして使用されます。テーブルは内部的に分割され、指定された数の同時更新を競合なしで許可しようとします。ハッシュ テーブル内の配置は基本的にランダムであるため、実際の同時実行数は異なります。

パブリック コレクション値()

このマップに含まれる値の Collection ビューを返します。コレクションはマップによって支えられているため、マップへの変更はコレクションに反映され、その逆も同様です。コレクションは、Iterator.remove、Collection.remove、removeAll、retainAll、および clear 操作を介して、このマップから対応するマッピングを削除する要素の削除をサポートしています。add または addAll 操作はサポートされていません。ビューの反復子は、 ConcurrentModificationExceptionを決してスローしない「弱い一貫性のある」反復子であり、反復子の構築時に存在していた要素をトラバースすることを保証し、構築後の変更を反映する可能性があります (ただし保証はされません)。

于 2013-07-17T16:40:07.260 に答える