在ConcurrentHashMap中锁定和锁定方案之前重试

时间:2013-09-05 11:15:19

标签: java multithreading

来自ConcurrentHashMap的源代码

/**
  171        * Number of unsynchronized retries in size and containsValue
  172        * methods before resorting to locking. This is used to avoid
  173        * unbounded retries if tables undergo continuous modification
  174        * which would make it impossible to obtain an accurate result.
  175        */
  176       static final int RETRIES_BEFORE_LOCK = 2;

1.我读过迭代没有锁定,那么上面的语句是什么意思? 像get这样的操作也可以锁定吗?请提供方案。

2.如果尚未对该元素进行迭代,那么在线程1中运行的更新操作是否可见于线程2中的迭代?(波动性和可见性?)

3.除了更新锁定之外还有其他任何情况吗?

4.获取数据时,使用易失性读取。如果易失性读取导致未命中,则获得该段的锁定以获得成功读取的最后一次尝试。这是什么意思?什么是易失性读取?

1 个答案:

答案 0 :(得分:3)

  

我已经读过迭代没有持有锁,所以上面的语句是什么   手段?

有人可以争辩说,size方法可以继续进行而且永远不会锁定。但是这个实现将获得两次ConcurrentHashMap的大小,如果first的大小不等于second将重试。如果相同,它将锁定所有段并最后一次获得大小。

  

像get这样的操作也可以锁定吗?请提供方案   还

技术上是的它可以,但可能永远不会发生。如果JVM在条目可用后发布CHM的条目条目值之一,则CHM将在段锁定下执行读取(这可能永远不会发生)。

Java 8正在发布一个新的CHM实现,因此很快就会过时。

  

在线程1中运行的更新操作是否对迭代可见   在线程2中,如果还没有对该元素进行迭代   制成?(波动?)

如果线程1在发出get的线程2之前发出put,则线程2将看到更新的条目。

如果,当线程2正在进行同时线程1正在执行put时,则线程2可能会或可能不会看到该条目(或者它可能是时间问题)。这是因为get是非阻塞的。这仍然是线程安全的,因为CHM表示它将在您搜索地图时返回该条目。

  

除了更新锁定之外还有其他情况吗?

除了所有修改方法外,序列化还需要锁定。

  

获取数据时,使用易失性读取。如果挥发性读   导致未命中,然后获得该段的锁定   成功阅读的最后一次尝试。这意味着什么?什么是不稳定的   读?

我已经用“技术上的”答案来避免这种情况。你所指的是readValueUnderLock方法。根据JMM,在对象可用于另一个线程之后,可以在对象内部写入非最终字段(无论是内联构造还是构造函数内)。

所以

public Entry{
 volatile Object value;
 public Entry(Object v){
     value = v;
 }
}

Thread 1
Entry e = new Entry(new Object());

Thread 2
if(e != null)
    Object value =  e.value; // here, according to the JMM, value can be null.  
                             // If value were final it would never be null

读取锁定下的值会将读取与来自另一个线程的先前写入同步,以便始终阻止空值。

尽管如此,这种情况要么非常不可能,要么在x86 arch下不可能。