gpt4 book ai didi

java - 具有静态方法和初始化方法的类的并发

转载 作者:塔克拉玛干 更新时间:2023-11-02 18:58:43 26 4
gpt4 key购买 nike

如何使以下类成为线程安全的?

public class Helper
{
private static Map<String,String> map = null;

public static init()
{
map = new HashMap<String,String>();
// some loading stuff
}

public static getMap()
{
if(map==null) init();
return new HashMap<String,String>(map);
}
}

到目前为止我的想法:

  1. 使 getMap() 同步。问题:使程序比必要的慢,因为同步只在程序开始时需要,然后再也不会。

  2. 使用锁。问题是我在这里使用的方法“isLocked”不存在。那么最好的解决方案是什么?

    public class Helper
    {
    private static Map<String,String> map = null;
    private static Lock lock = new ReentrantLock();

    public static init()
    {
    lock.lock();
    map = new HashMap<String,String>();
    // some loading stuff
    lock.unlock();
    }

    public static getMap()
    {
    synchronized {if(map==null) init();}
    while(lock.isLocked()) {Thread.wait(1);]
    return new HashMap<String,String>(map);
    }

P.S.:抱歉第二个源码显示问题。在枚举之后使用代码似乎存在错误。

P.P.S.:我知道 HashMap 不是线程安全的。但这仅意味着我不能并行写入读取应该不是问题,不是吗?

P.P.P.S.:我的最终版本(只是内部类),遵循 John Vint:

protected static class LazyLoaded
{
static final Map<String,String> map;
static
{
Map<String,String> mapInit = new HashMap<>();
// ...loading...
map = Collections.unmodifiableMap(mapInit);
}
}

最佳答案

简单地同步对 map 引用的访问并不能解决问题。创建 map 后,您需要同步访问和可能修改 map 内容的操作。如果您知道映射在初始化期间被填充了一次,并且之后只执行读取操作,则会出现异常(exception)情况。在那种情况下,您可能不需要显式同步就可以,因为您的控制流会处理这一点(知道您的程序逻辑只允许在 map 初始化后读取)。

否则,我建议您使用 ConcurrentMap 实现之一,例如 ConcurrentHashMap,因为如果没有锁争用并且仍然提供必要的线程,它们相对便宜如果您确实在 map 的生命周期内执行读取和写入,则安全。

至于初始化,因为它是一个静态字段(所以只有一个实例)并且一次创建一个空映射的成本并不高,我建议您只需像这样声明您的映射:

private static final Map<String,String> map = new ConcurrentHashMap<String,String>();

这样您就不需要其他方法中的条件代码,不存在引用可见性问题并且代码变得更简单。

关于java - 具有静态方法和初始化方法的类的并发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9789247/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com