4

データベースに接続するプロジェクトに取り組んでいます。そして、もしあれば何回見る必要exception is happeningがあります。つまり、Multithreaded code複数のスレッドがデータベースに接続し、データベースに挿入します。そのため、ある時点で接続が失われる可能性があるため、これらの例外が何回発生したかを確認する必要があります。

だから私は以下のコードを書き、catchブロックで例外をキャッチし、例外がある場合は毎回カウンターを増やしてConcurrentHashMap.

class Task implements Runnable {

     public static final AtomicInteger counter_sql_exception = new AtomicInteger(0);
     public static final AtomicInteger counter_exception = new AtomicInteger(0);
     public static ConcurrentHashMap<String, Integer> exceptionMap = new ConcurrentHashMap<String, Integer>();

     @Override
     public void run() {

     try {

         //Make a db connection and then executing the SQL-

         } catch (SQLException e) {
              synchronized(this) {
                   exceptionMap.put(e.getCause().toString(), counter_sql_exception.incrementAndGet());
              }
              LOG.Error("Log Exception")
          } catch (Exception e) {
              synchronized(this) {
                   exceptionMap.put(e.getCause().toString(), counter_exception.incrementAndGet());
              }
              LOG.Error("Log Exception")
        }
      }
  }

私の質問は - 今日、私はコード レビューを行い、私の上級チーム メンバーの 1 人が、あなたは必要ないと言っsynchronized(this)ていexceptionMapましたcatch block。カウンターのインクリメントはアトミックであるため、必要になると私は言いました。マップに新しい値を入れることはアトミックです。しかし、同期せずに両方を行うことはアトミックではありません。そして彼はConurrentHashMapあなたのためにこれをすると言った。

それで、私はそれをsynchronized(this)ブロックする必要がありexceptionMapますか?そうでない場合、なぜですか?はいの場合、どのような理由を彼に引用する必要がありますか.

4

4 に答える 4

0

そして、この方法もうまくいくはずです。

private static final ConcurrentMap<String, Integer> exceptionMap = new ConcurrentHashMap<String, Integer>();

private static void addException(String cause) {
    Integer oldVal, newVal;
    do {
      oldVal = exceptionMap .get(cause);
      newVal = (oldVal == null) ? 1 : (oldVal + 1);
    } while (!queryCounts.replace(q, oldVal, newVal)); 
}
于 2013-04-11T06:41:56.193 に答える
0

各例外が発生した回数を数えようとしている場合は、次のようなものが必要です。

private static final ConcurrentMap<String, AtomicInteger> exceptionMap = new ConcurrentHashMap<String, AtomicInteger>();

private static void addException(String cause) {
  AtomicInteger count = exceptionMap.get(cause);
  if(count == null) {
    count = new AtomicInteger();
    AtomicInteger curCount = exception.putIfAbsent(cause, count);
    if(curCount != null) {
      count = curCount;
    }
  }
  count.incrementAndGet();
}

定期的にクリーンアップしない限り、例外の静的マップを持つことはリソースリークであることに注意してください。

@dnault が述べたように、グアバの AtomicLongMapを使用することもできます。

更新: オリジナルに関するいくつかのコメント:

  • 最新の値が実際にマップに確実に組み込まれるようにするために、別のラッピング同期ブロックが必要あることは正しいです。ただし、@Perception がコメントで既に指摘しているように、間違ったオブジェクト インスタンスで同期しています(静的マップを更新しているため、などの静的インスタンスが必要ですTask.class) 。
  • ただし、静的カウンターを使用していますが、例外ごとに異なる可能性がある文字列キーを使用しているため、実際には各例外の原因を数えるのではなく、さまざまなマップ値として乱数を貼り付けています
  • 最後に、私の例で示したように、ConcurrentMap を適切に使用することで、前述の問題を解決し、同期ブロックを完全に破棄できます。
于 2013-02-12T01:41:21.923 に答える