public class IdGeneratorService {
private final Map<String, AtomicLong> map = new ConcurrentHashMap<>();
public long nextId(String key) {
// 虽然采用了并发安全的容器,但是当 contains 语句通过后,有可能出现多线程先后 put,AtomicLong 值有可能给覆盖?
if (!map.containsKey(key)) {
AtomicLong atomicLong = new AtomicLong(0);
map.put(key, atomicLong);
return atomicLong.incrementAndGet();
}
return map.get(key).incrementAndGet();
}
}
代码如上,如果并发调用 nextId(),我感觉即使使用了并发安全的容器,实际上这段代码也不是线程安全的,如果多线程访问,还是会出现 nextId()重复的问题,有可能 nextId 会出现多个 1 ?但是实际经过测试,并不会重现这个问题。。请教一下,这段代码是不是线程安全的,是否会生成重复 id?
测试代码
public static void main(String[] args) throws InterruptedException {
int count=2000;
CountDownLatch cdl=new CountDownLatch(count);
IdGeneratorService service = new IdGeneratorService();
Map<Long, AtomicLong> countMap=new ConcurrentHashMap<>();
for(long i=1;i<=count;i++){
countMap.put(i,new AtomicLong());
}
for(int i=0;i<count;i++){
new Thread(()->{
long id = service.nextId("test");
countMap.get(id).incrementAndGet();
cdl.countDown();
}).start();
}
cdl.await();
boolean match = countMap.values().stream().mapToLong(AtomicLong::get).anyMatch(l->l>1);
System.out.printf("id 重复=%b\n",match);
}
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.