【问题标题】:synchronization of singleton state单例状态同步
【发布时间】:2017-02-23 08:00:05
【问题描述】:

我有这个单身人士。正如我所做的enum 一样,它对于getInstance 是线程安全的。

public enum ExtensionRegistry {
    REGISTRY;

    private static final Logger LOGGER = LoggerFactory.getLogger(ExtensionRegistry.class);

    // key is a class name
    private Map<String, Plugin> extensions = new HashMap<>();

    public void registerPlugin(Plugin plugin) {
        LOGGER.info("Register plugin: [{}].", plugin);
        extensions.put(plugin.getId(), plugin);
    }

    public Plugin getPlugin(String id) {
        return extensions.get(id);
    }

    public List<String> listAvailablePlugins() {
        return extensions.values().stream()
                .map(Plugin::getId)
                .collect(Collectors.toList());
    }

    public IPluggable getRegisteredClass(String id) {
        Plugin plugin = extensions.get(id);

        if (null == plugin) {
            LOGGER.debug("No class with id [{}] found in the registry!", id);
            return null;
        } else {
            IPluggable instance = null;
            try {
                instance = (IPluggable) Class.forName(plugin.getId()).newInstance(); // should exist!
            } catch (Exception exc) {
                LOGGER.error("Failed to create instance of class with id [{]].", id, exc);
            }
            return instance;
        }
    }
}

为了使其真正线程安全,我还应该更改/同步哪些内容?使用ConcurrentHashMap?为每个方法添加synchronized

【问题讨论】:

  • 同步公共方法。 HashMap 不是线程安全的;您需要在所有这些方法中独占访问它。
  • @AndyTurner 但如果我做到了ConcurrentHashMap 它不会有帮助吗?因为例如 registerPlugin 方法使其同步没有意义,因为它只有一个动作
  • 动作的数量无关紧要。执行该操作的线程数是相关的。不同步,没有锁,缺乏并发结构,那些对plugin的多次访问和返回它的方法注定要在并发上下文中。
  • 那我什么时候需要ConcurrentHashMap?因为据我了解,我可以将HashMap 留在那里
  • 绝不允许两个线程同时写入同一个 HashMap,绝不允许线程写入而另一个线程读取 HashMap。如果这两种情况中的任何一种都可能发生,请使用 ConcurrentHashMap

标签: java concurrency synchronized concurrenthashmap


【解决方案1】:

在这种情况下,我肯定会使用 ConcurrentMap 实现。当您进行顺序调用以检查和更改 Map 时,请记住使用并发方法。

并发很难。即使你做对了,其他人也可以很容易地在以后出现并把它搞砸。使用专家编写的类可以使其正确且更易于维护。

在此代码中,您仍然可以有竞争条件,因为 set 和 get 通过您的方法公开。 Map 将是安全的,但不能保证调用 get() 时会得到预期的结果。其他人可以在您调用 set() 之后立即调用,然后您的 get() 将返回“他们的”值。您允许覆盖 registerPlugin 中的值。如果你必须拥有它,那么这种情况几乎没有办法解决。如果你可以失去它,那么使用 putIfAbsent() 可以帮助你。

---(删除不适当的代码)---

【讨论】:

  • 所以我必须将ConcurrentHashMap 与同步的listAvailablePluginsgetRegisteredClass 一起使用?
  • 使用 ConcurrentHashMap 你不需要同步(在这个例子中)。 Synchronize 通常已经失宠,因为它很难正确有效地使用。 util.concurrent 中的 Lock 系列类通常是首选。
  • 据我所知lock 是可取的,因为它们允许解锁(不像内在锁,又名synchronized)并据我记得设置超时..所以如果我改为ConcurrentHashMap我根本不需要synchronized 任何方法?
  • 您需要自己管理锁。 ConMap 在内部为您完成。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-10
  • 1970-01-01
  • 1970-01-01
  • 2018-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多