Map <string,atomiclong>是否足以保证线程安全?

时间:2015-06-18 22:24:00

标签: java multithreading

我有一个非常简单的课程:

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,或者我需要选择其他方法吗?

3 个答案:

答案 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