【问题标题】:Synchronised VS Striped Lock同步 VS 条带锁
【发布时间】:2017-06-18 17:15:30
【问题描述】:

我有一个由多个线程访问的类,我想确保它是线程安全的。另外,它需要尽可能快。这只是一个例子:

public class SharedClass {
  private final Map<String, String> data = new HashMap<>();
  private final Striped<ReadWriteLock> rwLockStripes = Striped.readWriteLock(100);

  public void setSomethingFastVersion(String key, String value) {
    ReadWriteLock rwLock = rwLockStripes.get(key);
    try {
      rwLock.lock();
    } finally{
      rwLock.unLock();
    }

    data.put(key, value);
  }

  public synchronized void setSomethingSlowVersion(String key, String value) {
    data.put(key, value);
  }
}

我在一个版本中使用来自 Google Guava 的 StripedLock,在另一个版本中使用普通的 synchronized

Guava 版本应该更快吗?

如果是这样,什么是 synchronized 的好用例,而 StripedLocks 不适合?

顺便说一句,我知道我可以在这里使用简单的ConcurrentHashMap,但我正在添加示例代码以确保您理解我的问题。

【问题讨论】:

  • 首先,您的data.put(k,v) 需要在您的try 块内。通常,托管的特定锁比同步更快。基准测试将确定您的情况是否属实。您还在这里使用了读写锁。你需要那种行为吗?我在这里没有看到任何读取,您将如何实现它们?
  • @WillD 那么你可以用什么来代替ReadWriteLock 呢?
  • 这里要考虑的其他一点是您是否需要锁定/同步。即使像这样同步,最后一个调用者也会设置值。如果您无法控制方法访问顺序,则无法确定结果。通常,我们锁定地图以确保基于get(k) 的某些功能在get(k)put(k,v) 之间没有任何变化。像putIfAbsent() on ConcurrentMap 这样的方法会在内部为您进行锁定,但put(k,v) 不是并发的。

标签: java multithreading locking


【解决方案1】:

让我这样说。假设您有 1000 个类的实例,并且您有 1000 个线程试图访问这些实例。每个实例将为每个线程获取一个锁。所以1000个锁会导致巨大的内存消耗。在这种情况下,剥离锁可能会派上用场。

但是在正常情况下,如果你有一个单例类,你可能不需要剥离锁,可以继续使用 synchronized 关键字。

所以,我希望我回答了何时使用什么。

【讨论】:

    【解决方案2】:

    同步已经存在很长时间了。我们现在拥有更先进的并发编程机制,这并不奇怪。

    但是,条带锁仅在可以分区或条带化的情况下才有优势,例如锁定地图的部分允许同时操作不同的部分,但阻止对同一条带的同时操作。在许多情况下,您没有那种分区,您只是在寻找互斥锁。在这些情况下,synchronized 仍然是一个可行的选择,尽管根据具体情况,ReadWriteLock 可能是更好的选择。

    ConcurrentHashMap 具有类似于条带的内部分区,但它仅适用于映射操作,例如 put()。使用显式StripedLock,您可以使更长的操作成为原子操作,同时在操作不涉及相同条带时仍允许并发。

    【讨论】:

    • 嗨,你认为在这种特定情况下ReadWriteLock 更快吗?另外,我可以使用与ReadWriteLock 不同的东西吗?在我的情况下,它实际上是 HashMap,但我需要做很多工作,所以即使是 ConcurrentHashMap 也不符合要求,这就是为什么我正在考虑退回到正常的 HashMap并使用锁
    • 不,我是在解释条带锁没有优势的情况,而synchronized 仍然是一个可行的选择。
    • 哦好的,我明白了,对不起。在我的情况下,它是一个哈希映射,所以是的,一个锁可以做到这一点
    • ConcurrentHashMap 在内部使用条带化。
    • 是的,但正如我所说,在我的真实示例中,我无法对地图进行原子更新。我需要做非原子操作,所以在这种情况下我需要一个锁,不是吗?
    【解决方案3】:

    使用ConcurrentHashMap,这样您就不必自己进行任何同步了。

    【讨论】:

    • 阅读我的问题,我说:BTW, I know I could use a simple ConcurrentHashMap here, but I'm adding the example code to make sure you understand my question.
    猜你喜欢
    • 1970-01-01
    • 2017-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-29
    • 1970-01-01
    • 2012-02-24
    相关资源
    最近更新 更多