25

Web サーバーの統計を収集するグローバル オブジェクトを実装する必要があります。methodを持つStatistics シングルトンがありaddSample(long sample)、その後 を呼び出しますupdateMax。これは明らかにスレッドセーフでなければなりません。統計全体の最大値を更新するこの方法があります。

AtomicLong max;

private void updateMax(long sample) {
    while (true) {
        long curMax = max.get();
        if (curMax < sample) {
            boolean result = max.compareAndSet(curMax, sample);
            if (result) break;
        } else {
            break;
        }
    }
}

この実装は正しいですか?シンプルよりも速いと思うので、私はjava.util.concurrentを使用していますsynchronized。これを実装するための他の/より良い方法はありますか?

4

5 に答える 5

13

正しいと思いますが、わかりやすくするために少し書き直して、間違いなくコメントを追加します。

private void updateMax(long sample) {
    while (true) {
        long curMax = max.get();
        if (curMax >= sample) {
            // Current max is higher, so whatever other threads are
            // doing, our current sample can't change max.
            break;
        }

        // Try updating the max value, but only if it's equal to the
        // one we've just seen. We don't want to overwrite a potentially
        // higher value which has been set since our "get" call.
        boolean setSuccessful = max.compareAndSet(curMax, sample);

        if (setSuccessful) {
            // We managed to update the max value; no other threads
            // got in there first. We're definitely done.
            break;
        }

        // Another thread updated the max value between our get and
        // compareAndSet calls. Our sample can still be higher than the
        // new value though - go round and try again.
    }
}

編集: 通常、私は少なくとも最初に同期バージョンを試し、問題を引き起こしていることがわかった場合にのみ、この種のロックフリー コードを使用します。

于 2011-05-20T12:53:45.573 に答える
3

あなたが答えを選んでいないかのように、ここに私の答えがあります:

// while the update appears bigger than the atomic, try to update the atomic.
private void max(AtomicDouble atomicDouble, double update) {
    double expect = atomicDouble.get();
    while (update > expect) {
        atomicDouble.weakCompareAndSet(expect, update);
        expect = atomicDouble.get();
    }
}

受け入れられた回答とほぼ同じですが、使用しないbreakwhile(true)、個人的には好きではありません。

編集: Java 8で発見されたばかりDoubleAccumulatorです。ドキュメントには、これはあなたのような要約統計の問題のためのものであるとさえ書かれています:

DoubleAccumulator max = new DoubleAccumulator(Double::max, Double.NEGATIVE_INFINITY);
parallelStream.forEach(max::accumulate);
max.get();
于 2016-09-03T09:48:22.503 に答える
2

あなたがしたことは正しいと思いますが、これはより単純なバージョンであり、私も正しいと思います。

private void updateMax(long sample){
      //this takes care of the case where between the comparison and update steps, another thread updates the max

      //For example:
      //if the max value is set to a higher max value than the current value in between the comparison and update step
      //sample will be the higher value from the other thread
      //this means that the sample will now be higher than the current highest (as we just set it to the value passed into this function)
      //on the next iteration of the while loop, we will update max to match the true max value
      //we will then fail the while loop check, and be done with trying to update.
      while(sample > max.get()){
          sample = max.getAndSet(sample);  
      }
}
于 2012-01-13T20:33:21.230 に答える