来自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.获取数据时,使用易失性读取。如果易失性读取导致未命中,则获得该段的锁定以获得成功读取的最后一次尝试。这是什么意思?什么是易失性读取?
答案 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下不可能。