繁体   English   中英

是地图 <String,AtomicLong> 足以确保线程安全?

[英]Is Map<String,AtomicLong> enough to be thread safe?

我有一堂很简单的课:

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,还是我需要选择其他方法?

有多种方法可以确保此线程安全,但是我认为以下是最简单的方法。 首先,您需要安全地发布初始地图。 然后,您需要确保对该映射线程的每次访问都是安全的。

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中的实际术语,请查找。)

而且,只要同步整个方法是同时提供同步性和原子性的最简单方法,而且就不会太麻烦了。 除非您可以分析此代码并确定它实际上是性能瓶颈,否则您不应该尝试做更多的事情。 把事情简单化。

这不是线程安全的。

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();
}

使方法同步以避免可能的不良交织和数据争用。

当您需要使用多个提供程序同时处理同一组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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM