8

依存性注入を介してWebアプリケーションに注入される以下に定義されたJavaクラスがある場合:

public AccountDao
{
   private NamedParameterJdbcTemplate njt;
   private List<Account> accounts;

   public AccountDao(Datasource ds)
   {
       this.njt = new NamedParameterJdbcTemplate(ds);
       refreshAccounts();
   }

   /*called at creation, and then via API calls to inform service new users have 
     been added to the database by a separate program*/
   public void refreshAccounts()
   {
      this.accounts = /*call to database to get list of accounts*/
   }

   //called by every request to web service
   public boolean isActiveAccount(String accountId)
   {
       Account a = map.get(accountId);
       return a == null ? false : a.isActive();
   }
}

スレッドセーフが気になります。Springフレームワークは、あるリクエストがリストから読み取られ、現在別のリクエストによって更新されている場合を処理しませんか?以前、他のアプリケーションで読み取り/書き込みロックを使用したことがありますが、上記のようなケースについてはこれまで考えたことがありません。

データベースの負荷を減らすために、Beanをシングルトンとして使用することを計画していました。

ちなみに、これは以下の質問のフォローアップです:

データベースの負荷を軽減するJavaメモリストレージ-安全ですか?

編集:

したがって、このようなコードでこの問題を解決できますか?

/*called at creation, and then via API calls to inform service new users have 
         been added to the database by a separate program*/
       public void refreshAccounts()
       {
          //java.util.concurrent.locks.Lock
          final Lock w = lock.writeLock();
          w.lock();
          try{
               this.accounts = /*call to database to get list of accounts*/
          }
          finally{
             w.unlock();
          }
       }

       //called by every request to web service
       public boolean isActiveAccount(String accountId)
       {
           final Lock r = lock.readLock();
           r.lock();

           try{
               Account a = map.get(accountId);
           }
           finally{
               r.unlock();
           }
           return a == null ? false : a.isActive();
       }
4

4 に答える 4

13

Springフレームワークは、シングルトンBeanのマルチスレッド動作に関して内部的には何もしません。シングルトンBeanの同時実行性の問題とスレッドセーフに対処するのは開発者の責任です。

以下の記事を読むことをお勧めします:Spring Singleton、Request、Session Beans、およびThread Safety

于 2013-03-13T21:27:03.597 に答える
3

あなたは私の最初の答えについて説明を求めることができたでしょう。SpringはBeanへのアクセスを同期しません。デフォルトのスコープ(シングルトン)にBeanがある場合、そのBeanのオブジェクトは1つだけであり、すべての同時リクエストはそのオブジェクトにアクセスするため、そのオブジェクトはスレッドセーフである必要があります。

ほとんどの春の豆には変更可能な状態がないため、スレッドセーフです。Beanの状態は変更可能であるため、他のスレッドが現在アセンブルしているアカウントのリストがスレッドに表示されないようにする必要があります。

これを行う最も簡単な方法は、アカウントフィールドを作成することですvolatile。これは、新しいリストをフィールドに入力した後で(実行しているように見えるように)フィールドに割り当てることを前提としています。

private volatile List<Accounts> accounts;
于 2013-03-13T21:31:12.940 に答える
1

シングルトンで同期されていないため、Springは任意の数のスレッドがとを同時に呼び出すことを許可しisActiveAccountますrefreshAccounts。したがって、このクラスはスレッドセーフではなく、データベースの負荷を軽減しません。

于 2013-03-13T21:20:15.647 に答える
0

そのようなメタデータがたくさんあり、11個のノードが実行されています。各アプリノードには、そのようなデータの静的マップがあるため、その1つのインスタンスのみが、起動時に毎日オフピーク時に1回、またはサポート担当者がトリガーしたときにdbから初期化されます。リアルタイムで更新が必要なデータの一部について、1つのノードから他のノードに更新を送信するための単純なhttppostベースのAPIがあります。

public AccountDao
{
   private static List<Account> accounts;
   private static List<String> activeAccounts;
   private NamedParameterJdbcTemplate njt;

   static {
       try{
        refreshAccounts();
       }catch(Exception e){
        //log but do not throw. any uncaught exceptions in static means your class is un-usable
       }
   }


   public AccountDao(Datasource ds)
   {
       this.njt = new NamedParameterJdbcTemplate(ds);
       //refreshAccounts();
   }

   /*called at creation, and then via API calls to inform service new users have 
     been added to the database by a separate program*/
   public void refreshAccounts()
   {
      this.accounts = /*call to database to get list of accounts*/
   }

   public void addAccount(Account acEditedOrAdded)
   {
      //add or reove from map onr row
      //can be called from this node or other node
      //meaning if you have 2 nodes, keep IP port of each or use a internal web service or the like to tell 
      //node B when a account id added or changed in node A ...
   }   

   //called by every request to web service
   public static boolean isActiveAccount(String accountId)
   {
       Account a = map.get(accountId);
       return a == null ? false : a.isActive();
   }
}
于 2013-03-13T21:45:20.303 に答える