CountDownLatch
以下は、これらのマップで書き込みが発生するたびに、プライマリ、セカンダリ、およびターシャリ マップで初めて読み取りが発生しないようにするために使用するクラスです。
public class ClientData {
public static class Mappings {
public final Map<String, Map<Integer, String>> primary;
public final Map<String, Map<Integer, String>> secondary;
public final Map<String, Map<Integer, String>> tertiary;
public Mappings(
Map<String, Map<Integer, String>> primary,
Map<String, Map<Integer, String>> secondary,
Map<String, Map<Integer, String>> tertiary
) {
this.primary = primary;
this.secondary = secondary;
this.tertiary = tertiary;
}
}
private static final AtomicReference<Mappings> mappings = new AtomicReference<>();
private static final CountDownLatch hasBeenInitialized = new CountDownLatch(1);
public static Mappings getMappings() {
try {
hasBeenInitialized.await();
return mappings.get();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IllegalStateException(e);
}
}
public static void setMappings(
Map<String, Map<Integer, String>> primary,
Map<String, Map<Integer, String>> secondary,
Map<String, Map<Integer, String>> tertiary
) {
setMappings(new Mappings(primary, secondary, tertiary));
}
public static void setMappings(Mappings newMappings) {
mappings.set(newMappings);
hasBeenInitialized.countDown();
}
}
以下は、3 つのマップすべての設定のみを担当するバックグラウンド スレッド クラスです(以下の parseResponse メソッドを探してください)。10分おきに運行しています。
public class TempBackgroundThread {
// parse the response and store it in a variable
private void parseResponse(String response) {
//...
Map<String, Map<Integer, String>> primaryTables = null;
Map<String, Map<Integer, String>> secondaryTables = null;
Map<String, Map<Integer, String>> tertiaryTables = null;
//...
// store the three map data in ClientData class variables if anything has changed
// which can be used by other threads, this will be updated once every four or five months
if(changed) {
ClientData.setMappings(primaryTables, secondaryTables, tertiaryTables);
}
}
}
問題文:
マッピング オブジェクトとプライマリ、セカンダリ、およびターシャリ マップに対してあらゆる種類の null チェックまたはサニティ チェックを実行すると、パフォーマンスが大幅に低下します (理由は不明です)。しかし、健全性チェックや null チェックを行わなければ、パフォーマンスは非常に良くなります。誰が何が間違っているのか、なぜそれが起こるのか説明できますか?
以下は例です -
ClientData
メインスレッドですべてのマッピングを取得するためにクラスを使用しています。mappings
以下に示すように、 、mappings.primary
、mappings.secondary
およびmappings.tertiary
が空でないことを確認するために、あらゆる種類の健全性チェックを行っています。それらが空の場合、エラーをログに記録して戻ります
class Task implements Callable<String> {
public Task() {
}
public String call() throws Exception {
int compId = 100;
String localPath = "hello";
String remotePath = "world";
Mappings mappings = ClientData.getMappings();
if (MyUtilityClass.isEmpty(mappings)
|| (MyUtilityClass.isEmpty(mappings.primary) && MyUtilityClass
.isEmpty(mappings.secondary))
|| MyUtilityClass.isEmpty(mappings.tertiary)) {
// log error and return
}
// otherwise extract values from them
String localPAddress = null;
String remotePAddress = null;
if (MyUtilityClass.isNotEmpty(mappings.primary)) {
String localPId = mappings.primary.get(localPath).get(compId);
localPAddress = mappings.tertiary.get(localPath).get(
Integer.parseInt(localPId));
String remotePId = mappings.primary.get(remotePath).get(compId);
remotePAddress = mappings.tertiary.get(remotePath).get(
Integer.parseInt(remotePId));
}
String localSAddress = null;
String remoteSAddress = null;
if (MyUtilityClass.isNotEmpty(mappings.secondary)) {
String localSId = mappings.secondary.get(localPath).get(compId);
localSAddress = mappings.tertiary.get(localPath).get(
Integer.parseInt(localSId));
String remoteSId = mappings.secondary.get(remotePath).get(compId);
remoteSAddress = mappings.tertiary.get(remotePath).get(
Integer.parseInt(remoteSId));
}
// now use - localPAddress, remotePAddress, localSAddress and remoteSAddress
}
}
1 次、2 次、および 3 次マッピングに対する上記のサニティーおよびヌル・チェックにより、アプリケーションの全体的なパフォーマンス (95 パーセンタイル) は 4 ミリ秒になります。
しかし、1 次、2 次、および 3 次マッピングのサニティー・チェックまたはヌル・チェックなしでこのようにすると、全体的なパフォーマンス (95 パーセンタイル) は 0.87 ミリ秒になります。
class Task implements Callable<String> {
public Task() {
}
public String call() throws Exception {
int compId = 100;
String localPath = "hello";
String remotePath = "world";
Mappings mappings = ClientData.getMappings();
String localPId = mappings.primary.get(localPath).get(compId);
String localPAddress = mappings.tertiary.get(localPath).get(Integer.parseInt(localPId));
String remotePId = mappings.primary.get(remotePath).get(compId);
String remotePAddress = mappings.tertiary.get(remotePath).get(Integer.parseInt(remotePId));
String localSId = mappings.secondary.get(localPath).get(compId);
String localSAddress = mappings.tertiary.get(localPath).get(Integer.parseInt(localSId));
String remoteSId = mappings.secondary.get(remotePath).get(compId);
String remoteSAddress = mappings.tertiary.get(remotePath).get(Integer.parseInt(remoteSId));
// now use - localPAddress, remotePAddress, localSAddress and remoteSAddress
}
}
以下は私の isEmpty と isNotEmpty メソッドです -
public static boolean isNotEmpty(Object obj) {
return !isEmpty(obj);
}
public static boolean isEmpty(Object obj) {
if (obj == null)
return true;
if (obj instanceof Collection)
return ((Collection<?>) obj).size() == 0;
final String s = String.valueOf(obj).trim();
return s.length() == 0 || s.equalsIgnoreCase("null");
}