一道面试题,欢迎大家指正
题目
同时有N个商品(用long类型的商品id表示),
每个商品都可以被任何一个用户(long类型的用户id)订阅,
每被订阅一次,该商品的订阅数加1,
同一个用户对同一个商品只能订阅一次 编辑写一个类,
用3个方法提供以下功能(这3个方法都是在单机多线程环境下调用):
1)为指定的用户id订阅指定的商品id
2)返回所有商品的订阅总数
3)根据商品ID返回这个商品的订阅数
代码
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
/**
* 同时有N个商品(用long类型的商品id表示),
* 每个商品都可以被任何一个用户(long类型的用户id)订阅,
* 每被订阅一次,该商品的订阅数加1,
* 同一个用户对同一个商品只能订阅一次 编辑写一个类,
* 用3个方法提供以下功能(这3个方法都是在单机多线程环境下调用):
*
* 1)为指定的用户id订阅指定的商品id
* 2)返回所有商品的订阅总数
* 3)根据商品ID返回这个商品的订阅数
*/
public class AliSubscribeGoods {
private ConcurrentHashMap<Long, ConcurrentHashMap<Long, Long>> goodsSubscribeMap = new ConcurrentHashMap<>();
private ConcurrentHashMap<Long, AtomicLong> goodsSubscribeCountMap = new ConcurrentHashMap<>();
private final Object goodsSubscribeMapLock = new Object();
private final Object goodsSubscribeCountMapLock = new Object();
public boolean subscribe(Long goodId, Long userId) {
ConcurrentHashMap<Long, Long> userSubscribeMap = goodsSubscribeMap.get(goodId);
if (userSubscribeMap == null) {
synchronized (goodsSubscribeMapLock) {
userSubscribeMap = goodsSubscribeMap.get(goodId);
if (userSubscribeMap == null) {
userSubscribeMap = new ConcurrentHashMap<>();
goodsSubscribeMap.put(goodId, userSubscribeMap);
}
}
}
Long put = userSubscribeMap.putIfAbsent(userId, userId);
if (put != null) {
// 说明之前订阅过
return true;
}
AtomicLong subscribeCount = goodsSubscribeCountMap.get(goodId);
if (subscribeCount == null) {
synchronized (goodsSubscribeCountMapLock) {
subscribeCount = goodsSubscribeCountMap.get(goodId);
if (goodsSubscribeCountMap == null) {
subscribeCount = new AtomicLong(1);
goodsSubscribeCountMap.put(goodId, subscribeCount);
}
}
} else {
subscribeCount.addAndGet(1);
}
return true;
}
public long sumSubscribe() {
long sum = 0;
for (AtomicLong item : goodsSubscribeCountMap.values()) {
sum += item.get();
}
return sum;
}
public long sumSubscribe(Long goodId) {
return Optional.ofNullable(goodsSubscribeCountMap.get(goodId)).map(AtomicLong::get).orElse(0L);
}
}