5

部門のドキュメントを表示するプロジェクトがあります。すべてのドキュメント (データベースから取得) を静的 arrayList に格納します。X 時間ごとに、データベースからの新しいドキュメント (存在する場合) に基づいて、その arrayList を再構築します。その配列を再構築するかどうかを制御する静的変数もあり、再構築タスクを実行するメソッドで設定および設定解除します。各 Web ブラウザがサーバーにヒットすると、このクラスのインスタンスが作成されますが、doc arrayList とその制御変数はすべてのクラス インスタンス間で共有されます。

Find-Bugs ツールは、「インスタンス メソッド someClassMethod から静的フィールド someArrayName および someVariableName に書き込みます」と文句を言います。これは良いことではないようです (クラス インスタンス メソッドが静的フィールドに書き込むようにします)。この問題を回避するための良い推奨事項はありますか? ありがとう。

4

5 に答える 5

7

FindBugsのバグの説明によると:

ST:インスタンスメソッドから静的フィールドに書き込みます(ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD)

このインスタンスメソッドは静的フィールドに書き込みます。複数のインスタンスが操作されている場合、これを正しく行うには注意が必要であり、一般的には悪い習慣です。

同時実行性の問題は別として、JVM内のすべてのインスタンスが同じデータにアクセスしており、2つの別々のインスタンスグループを許可しないことを意味します。シングルトンの「マネージャー」オブジェクトがあり、それをコンストラクターパラメーターとして、または少なくともsetManager()メソッド引数として各インスタンスに渡した方がよいでしょう。

並行性の問題について:静的フィールドを使用する必要がある場合は、静的フィールドが最終である必要があります。明示的な同期は困難です。(Javaの知識を超えて、非最終静的フィールドを初期化する場合にも、いくつかのトリッキーな側面がありますが、Javaパズルの本でそれらを見たと思います。)これに対処するには、少なくとも3つの方法があります(警告、テストされていないコードが続きます。使用する前にまず確認してください):

  1. スレッドセーフなコレクションを使用します。たとえばCollections.synchronizedList、他の方法でアクセスされないリストをラップします。

    static final List<Item> items = createThreadSafeCollection();
    
    
    static List<Item> createThreadSafeCollection()
    {
       return Collections.synchronizedList(new ArrayList());
    }
    

    その後、このコレクションをインスタンスから置き換える場合は、次のようにします。

    List<Item> newItems = getNewListFromSomewhere();
    items.clear();
    items.add(newItems);
    

    これに伴う問題は、2つのインスタンスが同時にこのシーケンスを実行している場合、次のようになる可能性があることです。

    Instance1:items.clear(); Instance2:items.clear(); インスタンス1:items.addAll(newItems); Instance2:items.addAll(newItems);

    そして、目的のクラス不変条件を満たさないリストを取得します。つまり、静的リストにnewItemの2つのグループがあります。したがって、リスト全体を1つのステップとしてクリアし、アイテムを2番目のステップとして追加する場合、この方法は機能しません。(ただし、インスタンスがアイテムを追加するだけでよい場合はitems.add(newItem)、各インスタンスから安全に使用できます。)

  2. コレクションへのアクセスを同期します。

    ここで同期するための明示的なメカニズムが必要になります。同期されたメソッドは、インスタンス間で一般的ではない「this」で同期するため、機能しません。あなたが使用することができます:

    static final private Object lock = new Object();
    static volatile private List<Item> list;
    // technically "list" doesn't need to be final if you
    // make sure you synchronize properly around unit operations.
    
    
    static void setList(List<Item> newList)
    {
      synchronized(lock)
      {
          list = newList;
      }
    }
    
  3. AtomicReferenceを使用する

    static final private AtomicReference<List<Item>> list;
    
    
    static void setList(List<Item> newList)
    {
      list.set(newList);
    }
    
于 2010-12-16T03:43:25.060 に答える
1

あなたが Find Bugs から投稿したメッセージを正しく理解している場合、これは単なる警告です。

警告を非表示にする場合は、静的メソッドから変更を行います。これは通常エラーであるため、Find Bugs は警告を発しています。プログラマーは、インスタンスの状態を変更していると考えていますが、実際には、すべてのインスタンスに影響を与える状態を変更しています。

于 2010-12-16T03:31:38.993 に答える
0

毎回リストを削除する必要はありません。上記のように、複数のスレッドを処理する必要がありますが、ArrayList を一度作成してから、clear() および addAll() メソッドを使用してワイプして再入力することができます。スタティックを設定していないため、FindBugs はこれで満足するはずです。

みんな-このテクニックに問題がある場合は、気軽に参加してください:-)

2 番目の考えは、休止状態を介してデータベースから物事を追い出すことです。したがって、リストを維持しないでください。休止状態にはキャッシュが組み込まれているため、ほぼ同じくらい高速です。データベース レベルでデータを更新する場合 (つまり、休止状態が認識されないことを意味します)、休止状態にキャッシュをクリアし、次にクエリが実行されたときにデータベースから更新するように指示できます。

于 2010-12-16T03:10:41.743 に答える
0

シングルトンデザイン パターンを使用するのも 1 つの方法です。必要な値を保持するオブジェクトのインスタンスを 1 つだけ持つことができ、グローバル プロパティを通じてそのインスタンスにアクセスできます。利点は、後でインスタンスを増やしたい場合に、既存のコードの変更が少なくて済むことです (静的フィールドをインスタンス フィールドに変更しないため)。

于 2010-12-16T02:52:39.893 に答える
-1

あなたはこれをしたくありません。すべてのリクエストは独自のスレッドで実行されます。ブラウザー アクションで実行されるコードがリストを変更する場合、2 つの要求が同時にリストを変更し、データが破損する可能性があります。そのため、非静的コンテキストから静的リソースにアクセスすることはお勧めできません。おそらく、ツールから警告が表示されるのはそのためです。

これを見て

http://download.oracle.com/javase/6/docs/api/index.html?java/util/concurrent/package-summary.html

具体的には、ArrayList が同期されない方法に関する部分です。また、私が言及した段落には解決策があることに注意してください。具体的には

List list = Collections.synchronizedList(new ArrayList(...));

それはそれを行う1つの方法です。しかし、それはまだ良い考えではありません。つまり、遅くなる可能性があるからです。それが商用グレードのアプリケーションではなく、大量に扱っていない場合は、おそらくそれを改善しなくても取得できます. これが 1 日に数回しかヒットしないタイプのアプリである場合は、2 つの要求が相互に衝突すると何か問題が発生する可能性があることを理解して、警告を無視できます。

より良い解決策: データベースがあるので、必要に応じて、つまり要求が入ったときにデータベースから情報を取得するだけです。パフォーマンスのためにいくつかのキャッシュテクノロジを使用できます。

シングルトン パターンのアイデアが気に入らない理由は、それによって警告が消えたとしても、それだけでは基本的な同期の問題に対処できないからです。スレッド セーフなhttp://en.wikipedia.org/wiki/Singleton_pattern#Traditional_simple_way_using_synchronizationがありますが、この場合はうまくいく可能性があります。

于 2010-12-16T02:55:56.147 に答える