您如何看待我们是否需要使用synchronized块来更好地优化对Ad实例的访问? 可以从不同的线程中检索Ad.class的实例。 Synchronized通过ConcurrentHashMap中的一次get操作帮助一次获取实例。 ConcurrentHashMap将所有值存储为volatile。我在java 1.7 for android上使用它, computeIfAbsent 在java 1.8中可用。
获得详细答案很好,为什么不,或为什么是。 谢谢!
public final class Ad {
private final static Map<String, Ad> ads = new ConcurrentHashMap<>();
public static Ad get(@NonNull String appId) {
if (appId == null) appId = "";
boolean containsAd = ads.containsKey(appId);
Ad localInstance = containsAd ? ads.get(appId) : null;
if (localInstance == null) {
synchronized (Ad.class) {
containsAd = ads.containsKey(appId);
localInstance = containsAd ? ads.get(appId) : null;
if (localInstance == null) {
localInstance = new Ad();
localInstance.setAdId(appId);
ads.put(appId, localInstance);
}
}
}
return localInstance;
}
private Ad() {
}
}
更新:感谢所有人的帮助。我将ConcurrentHashMap替换为HashMap。
答案 0 :(得分:1)
这不是最佳选择。如果多个线程尝试同时初始化值,那么即使他们正在寻找不同的密钥,它们也会相互阻塞。
您应该使用ConcurrentHashMap.computeIfAbsent
检查添加并在一个步骤中创建缺失的添加。这样您就不会创建任何未使用的广告,如果他们尝试初始化相同的条目,则两个线程只会相互阻止:
public static Ad get(@NonNull String appId) {
if (appId == null) appId = "";
return ads.computeIfAbsent(appId, Ad::new);
}
private Ad(String appId) {
this();
setAdId(appId);
}
答案 1 :(得分:0)
根据我的理解,您实际想要实现的是putIfAbsent
,因此这比您做的更简单 (您正在使用双重检查锁定):
public static Ad get(String appId) {
String newId = appId == null ? "" : appId;
ads.putIfAbsent(newId, new Ad());
return map.get(newId);
}