【问题标题】:Java - Synchronized Object/BlockJava - 同步对象/块
【发布时间】:2012-07-09 05:01:24
【问题描述】:

我正在寻找有关同步块的说明。考虑这个类 -

public class A{
Map map;

 public getValue(String key){
  return map.get(key);
 }

 public remove(String key){
  synchronized(map){
   map.remove(key);
  }
 }
}

A 是一个单例。 getValue 在整个应用程序中被多个线程大量访问。我正在添加一个新方法 remove,它从地图中删除一个键。如果按上述方式实现remove,则

  1. 当一个线程在 remove 方法的同步块中时,我假设它会在 map 对象上获得一个锁。这是否意味着尝试通过 getValue 方法访问地图的其他线程将被阻止? (我希望他们这样做。)
  2. 当 remove 方法的同步块中没有线程时,访问 getValue 方法的线程是否会照常运行,即不会相互阻塞? (我也想要)。

我希望 getValue 线程仅在有线程执行删除操作时才阻塞。

【问题讨论】:

  • 只有同步的块才会阻塞。

标签: java synchronization


【解决方案1】:

同步的一条规则是,对于同一个 foo,一次只能有一个线程在 synchronized(foo) 块中。这是synchronizedonly 规则。

嗯,关于内存屏障之类的东西有些复杂,一个单个线程可以同时在同一个foo的多个嵌套synchronized(foo)块中:

void thing() {
  synchronized(foo) {
    stuff(); // this works fine!
  }
}
void stuff() {
  synchronized(foo) {
    doMoreStuff();
  }
}

...但是上面所说的规则基本上是理解synchronized的关键。

【讨论】:

    【解决方案2】:

    如果我正确理解您的需求,您可以查看ConcurrentMap,当然还有ConcurrentHashMap,我认为它是随 Java 5.0 引入的并支持一定程度的并发性。

    【讨论】:

      【解决方案3】:

      你有鸡和蛋的问题

      我希望 getValue 线程仅在有线程执行删除操作时才阻塞。

      如果没有某种线程间交互,您无法确定是否有其他线程执行remove

      实现getValue(...)的正确方法是在地图上同步。

      我建议您放弃自己的锁定,并使用 ConcurrentHashMap 并将大量工作用于并发性能。

      【讨论】:

        【解决方案4】:

        1. getValue() 是不同步的,当一个线程获得一个对象的锁时,它拥有对所有同步块的控制......不是非同步的...... 所以当线程处于 sychronized(map) 块中时,其他线程可以访问 getValue()

        2。使用 HashTable,它是一个同步的 MAP

        【讨论】:

          【解决方案5】:

          您没有展示 Map 实例是如何实例化的,但假设它不是线程安全的集合实例,那么这段代码不是线程安全的。

          【讨论】:

          • 是一个普通的HashMap。感谢您的回答。我正在尝试使其线程安全而不影响性能。 remove 方法会很少被调用,而 getValue 会被调用很多。我将阅读 ConcurrentMap。
          【解决方案6】:

          当一个线程在 remove 方法的同步块中时,我假设它会在 map 对象上获得一个锁。这是否意味着尝试通过 getValue 方法访问地图的其他线程将被阻止?

          没有。这意味着你遇到了问题,除非你碰巧使用了线程安全的映射实现。

          当 remove 方法的同步块中没有线程时,访问 getValue 方法的线程是否会照常运行,即不会相互阻塞? (我也想要)。

          他们不会互相阻挡,不会。同样,您需要确保您使用的任何Map 实现都可以,尽管它可能比在写作的同时阅读要好得多。

          您应该考虑使用ConcurrentMap 实现(例如ConcurrentHashMap),此时您根本不需要任何同步。

          如果您不能使用它,我建议在 both getValueremove 中同步 - 并测量性能。获得一个非竞争锁相当便宜 - 你真的需要去无锁吗? (当然,使用ConcurrentHashMap 是避免该问题的一种相当简单的方法,但在开始微优化之前,您应该始终考虑是否需要额外的复杂性来获得所需的性能。)

          【讨论】:

          • 感谢您的快速回答。那么,当您说同步(对象)时,这是否意味着两个线程如果到达该代码块必须互相等待以使用同步对象?那是只有该方法中的线程会相互阻塞以访问对象?谢谢!
          • @septerr:不,不仅仅是该方法中的线程——任何试图在该对象的监视器上同步的线程。基本上,想象每个物体都附有一个挂锁。没有什么会自动锁定挂锁,但每次只有一个线程可以锁定它,无论它被要求锁定它的位置。
          • synchronized 的一个规则是对于同一个foo,一次只能有一个线程在synchronized(foo) 块中。这是synchronizedonly 规则。
          • @LouisWasserman:嗯,还有内存屏障方面的问题......并且foo 表达式只被评估一次,并且与获取的相同的监视器被释放,即使值foo 的变化...
          • 嗯,公平。改写:关于 synchronized 的 StackOverflow 问题 80% 可以通过该规则的一些特殊情况来回答。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2010-12-23
          • 2011-12-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多