【问题标题】:Can you lock on a local object in Java?你能锁定 Java 中的本地对象吗?
【发布时间】:2009-10-16 19:19:50
【问题描述】:

我有这段代码

private Templates retrieveFromCache(String name) {
        TemplatesWrapper t = xlCache.get(name);
        synchronized(t){
            if (!t.isValid()) {
                xlCache.remove(name);
                return null;
            }
        }
        return t.getTemplate();
    }

xlCache 是一个ConcurrentHashMap;我在t 上同步的原因是,当线程 1 验证谓词线程 2 已经从映射中删除对象时,2 个线程可能会交错,然后会抛出 NullPointerException我的假设是否正确,因为我知道并发是更难推理的事情之一。然后对于我最初的问题,我可以锁定t,即使它是本地的?

这也是从public 方法调用的private 方法,它会产生差异吗?

编辑:我最初的前提是抛出 NullPointerException 是不正确的,因为 remove() 返回 boolean 使得同步毫无意义;但是,我的问题是锁定本地对象已得到解答。

【问题讨论】:

    标签: java concurrency


    【解决方案1】:

    ConcurrentHashMap(和一般的Map/ConcurrentMap)不会在指定的键不存在时抛出异常。这就是remove 方法返回boolean 的原因,以指示是否有任何内容实际删除。

    但是是的,您可以锁定局部变量。毕竟,您实际上是通过 reference(以及与被引用对象关联的监视器)而不是变量锁定 - 并且其他同时运行的方法将具有相同的引用。

    【讨论】:

    • 在这种特定情况下,这可能是正确的,但您认为在本地(非字段)引用上同步是个好主意吗?
    • 我个人倾向于锁定一个私有的只读变量,但这取决于具体情况。
    • @Jon 在这里给出的推理是正确的:“xlCache 是一个 concurrentHashMap,所以我从地图中获取包装器,然后测试它是否有效,然后将其删除或从包装器中返回模板”。 ..是否有线程交错的可能性(因为这是我首先同步的全部原因)...如果键为
      null
      ,我的错误
      NullPointerException
      被抛出> 不是价值。
    • 完全正确 - 所以我认为您首先不需要任何锁定。
    • 正是我的想法,因为我原来的前提是有缺陷的。是否存在这样的情况,即 xlCache.remove(name) 会影响 TemplatesWrapper t = xlCache.get(name) 给定 diff 线程正在作用于该方法?
    【解决方案2】:

    您可以锁定任何您想要的对象。但是,在您的情况下,您似乎可以更清晰、更安全地解决它。

    同步应尽可能本地化。由于您从某个未知位置获取TemplatesWrapper,因此任何人都可能在其上进行同步,这使得控制并发性变得非常困难。也应该尽可能地通过查看代码为什么会被锁定。

    最好将同步放在 xlCache 中,例如 removeIfInvalid()

    【讨论】:

    • xlCache 是一个 concurrentHashMap,所以我从地图中获取包装器,然后测试它是否有效,然后将其删除或从包装器中返回模板
    • 我会一起放弃同步。允许删除不存在的对象
    【解决方案3】:

    是的,这样就可以了。

    您可以在 java 中的任何对象上进行同步,这样您的代码就可以工作并且是线程安全的。

    Appart 从你没有检查 t 是否为空的事实。我猜您只是在代码示例中错过了这一点?

    【讨论】:

      【解决方案4】:

      更好的方法是使用 ConcurrentMap 中的 2 arg remove 方法(假设 t 具有合理的 equals 实现)。那么你不需要任何同步:

      private Templates retrieveFromCache(String name) {
          TemplatesWrapper t = xlCache.get(name);
      
          if (!t.isValid()) {
              xlCache.remove(name, t);
              return null;
          }
          return t.getTemplate();
      }
      

      【讨论】:

      • 我应该添加 if(t == null) return null;' to see if TemplatesWrapper t = xlCache.get(name);` 返回 null 而不是 t
      【解决方案5】:

      如果 remove(null) 会调用空指针异常,这似乎是合理的。如果您不希望冲突成为常见问题,您还可以实现可能更快的代码版本,只需将 try/catch 包裹起来而不是同步。

      无论哪种情况,我都会在此处添加一条评论,以解释您为什么这样做,这样一个月后,它仍然有意义。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-09-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多