我有一个非常简单的课程:
public class IdProvider {
private Map<String,AtomicLong> idMap;
public IdProvider(){
idMap = new HashMap<>();
}
public long getAvailableId(String conversation){
AtomicLong id = idMap.get(conversation);
if(id == null){
id = new AtomicLong(0);
idMap.put(conversation,id);
}
return id.getAndIncrement();
}
}
异步的不同方法可以传递相同的会话标识符,并调用getAvailableId()
,返回唯一 ID。
这个线程安全吗?我保证没有两种方法可以获得相同的ID,或者我需要选择其他方法吗?
答案 0 :(得分:2)
有多种方法可以使这个线程安全,但我认为下面是最简单的。首先,您需要安全地发布初始Map。然后,您需要使该映射线程的每次访问都安全。
public class IdProvider {
private final Map<String,AtomicLong> idMap;
public IdProvider(){
idMap = new HashMap<>();
}
public synchronized long getAvailableId(String conversation){
AtomicLong id = idMap.get(conversation);
if(id == null){
id = new AtomicLong(0);
idMap.put(conversation,id);
}
return id.getAndIncrement();
}
}
final
关键字是提供“安全发布”的一种方式。 (这是Java中的一个实际术语,请查阅。)
并且没有棘手,只需同步整个方法是提供同步和原子性的最简单方法。你不应该尝试做更多的事情,除非你可以分析这些代码并确定它实际上是一个性能瓶颈。保持简单。
答案 1 :(得分:0)
这不是线程安全的。
public long getAvailableId(String conversation){
AtomicLong id = idMap.get(conversation);
// Thread could be paused here, causing bad interleavings
// If now a similar call to "getAvailableId" is done you will have two times the same id
if(id == null){
id = new AtomicLong(0);
idMap.put(conversation,id);
}
return id.getAndIncrement();
}
使方法同步,以避免可能的错误交错和数据争用。
答案 2 :(得分:0)
当您需要同时使用多个提供商处理同一组ID时,
public class IdProvider {
private static Map<String,Long> idMap;
static
{
idMap = new HashMap<>();
}
public Object lock=new Object();
public IdProvider(Object l){
lock=l;
}
public long getAvailableId(String conversation){
// do other work
synchronized(lock)
{
Long id = idMap.get(conversation);
if(id == null){
id = new Long(0);
idMap.put(conversation,id);
}
return idMap.put(conversation,id+1);
}
}
}
Object lock=new Object();
... in a thread:
IdProvider provider=new IdProvider(lock); // providing from a thread
... in another thread:
IdProvider provider2=new IdProvider(lock); // providing from another