私は最近、一意の負の数を生成するために使用されるコードをリファクタリングしました。
編集:複数のスレッドがこれらの ID を取得し、キーとして DB に追加します。簡単に識別できるようにするには、数値を負にする必要があります。テスト セッションの終了時に、数値は DB から削除されます。
私のJavaアルゴリズムは次のようになります。
private final Set<Integer> seen = Collections.synchronizedSet(new HashSet<Integer>());
public Integer generateUniqueNegativeIds() {
int result = 0;
do {
result = random.nextInt();
if (result > 0) {
result *= -1;
}
} while (!seen.add(result));
return result;
}
上記のコード構造は、セットと「再試行」ループに投機的に追加されているため、同期されたセットをアトミック変数のいずれかに置き換える、同等のノンブロッキング アルゴリズムがあると思われます。
アトミック変数を使用して書き直そうと何度か試みましたが、すべてマルチスレッド攻撃テストに失敗しました。
エレガントなノンブロッキングの同等物はありますか?
編集:好奇心のために、アトミック整数をガードとして使用する欠陥のある試みを次に示します
private final AtomicInteger atomi = new AtomicInteger(0);
public Integer generateUniqueNegativeIdsWithAtomicAlgo() {
boolean added = false;
int result = 0;
do {
result = random.nextInt();
if (result > 0) {
result *= -1;
}
if (atomi.compareAndSet(0, result)) {
added = cache.add(result);
}
} while (!added);
return atomi.getAndSet(0);
}
編集:以下のテストハーネス:
public static void main(String[] args) {
final int NUMBER_OF_THREADS = 10000;
final Set<Integer> uniques = Collections.synchronizedSet(new HashSet<Integer>());
final List<Integer> positives = Collections.synchronizedList(new ArrayList<Integer>());
final NegativeUniqueIdGenerator nuig = new NegativeUniqueIdGenerator();
Thread[] workers = new Thread[NUMBER_OF_THREADS];
long start = System.nanoTime();
for (int i = 0; i < workers.length; i++) {
Runnable runnable = new Runnable() {
public void run() {
int number = nuig.generateUniqueNegativeIds();
if (number > 0) {
positives.add(number);
}
uniques.add(number);
}
};
workers[i] = new Thread(runnable);
workers[i].start();
}
for (int i = 0; i < workers.length; i++) {
try {
workers[i].join();
} catch (InterruptedException ie) {}
}
long end = System.nanoTime();
System.out.println(String.format("duration = %dns", (end - start)));
System.out.println(String.format("#threads = %d", NUMBER_OF_THREADS));
System.out.println(String.format("#uniques = %d", uniques.size()));
System.out.println(String.format("#positives = %d", positives.size()));
System.out.println(String.format("#duplicates = %d", NUMBER_OF_THREADS - uniques.size()));
System.out.println(String.format("ratio = %f",
((double) NUMBER_OF_THREADS - uniques.size())
/ NUMBER_OF_THREADS));
assert uniques.size() == NUMBER_OF_THREADS;
}