英文:
How can this BitSet example print (false,true) or (true, false)?
问题
我试图通过遵循Aleksey Shipilëv的博客文章来理解JMM。
上面的示例让我感到困惑。
解释:有3个线程,前两个线程(第1列和第2列)在没有任何锁定的情况下运行
set()
,而第3个线程(第3列)等待前两个线程终止,然后尝试读取前两个线程写入的值。
如果两个线程分别运行bs.set(1)
和bs.set(2)
而没有任何锁定,它们如何可能产生不一致的结果?
根据内部结构,BitSet
是使用long[]
和位移实现的。
位移操作是一个常数时间操作,对吗?我根本无法理解这是如何可能的。
英文:
I am trying to understand the JMM by following the blog post by Aleksey Shipilëv
The above example is breaking my mind.
> Explanation: There are 3 threads the first 2 threads (the 1st and 2nd column) run set()
without any locking and the 3rd thread (3rd column) waits for the previous threads to terminate and then tries to read the values written by the previous threads.
If 2 threads run bs.set(1)
and bs.set(2)
respectively without any locking how can they give inconsistent results?
According to the internals the BitSet
is implemented using long[]
and bitshifts.
Bit shifting is a constant time operation, right? I simply cannot work out how this is even possible.
答案1
得分: 1
假设位被存储在一个长整型变量 v
中。
- 当只设置第1位时,
v
等于2。 - 当只设置第2位时,
v
等于4。 - 当两个位都被设置时,
v
等于6(即2|4
)。
如果按顺序设置它们,会得到如下结果:
v
起始值为0。bs.set(1)
- 读取
v
(0) - 加上2以表示第1位开启
- 更新
v
(2)
- 读取
bs.set(2)
- 读取
v
(2) - 加上4以表示第2位开启
- 更新
v
(6)
- 读取
现在 v
等于6,所以两个位都是开启的。
如果同时设置它们,可以得到如下结果:
v
起始值为0- 线程1:
bs.set(1)
- 线程2:
bs.set(2)
- 线程1:读取
v
(0) - 线程2:读取
v
(0) - 线程1:将
v
设置为2(即0|2
) - 线程2:将
v
设置为4(即0|4
)
现在 v
设置为4,所以第2位是开启的,而第1位是关闭的。
英文:
Suppose bits are stored inside a long variable v
.
- When just bit 1 is set,
v
would equal 2. - When just bit 2 is set,
v
would equal 4. - When both bits are set,
v
would equal 6 (i.e.2|4
).
If you set them sequentially, you get something like this:
v
starts at 0.bs.set(1)
- Read
v
(0) - Add
2
to indicate that bit 1 is on - Update
v
(2)
- Read
bs.set(2)
- Read
v
(2) - Add
4
to indicate that bit 2 is on - Update
v
(6)
- Read
Now v
is 6, so both bits are on.
If you set them simultaneously, you can get something like this:
v
starts at 0- Thread 1:
bs.set(1)
- Thread 2:
bs.set(2)
- Thread 1: Read
v
(0) - Thread 2: Read
v
(0) - Thread 1: Set
v
to 2 (i.e.0|2
) - Thread 2: Set
v
to 4 (i.e.0|4
)
Now v
is set to 4, so bit 2 is on and bit 1 is off.
答案2
得分: 0
根据作者的陈述:BitSet Javadocs 表示多线程使用应该同步,因此这可以说是一个人工示例。
JVM 不保证 Bitwise OR: ior, lor
的操作是原子的。
参见:https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html#jvms-2.11.3
BitSet 也不尝试进行原子更改。
参见:https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/util/BitSet.java
/**
* 将指定索引处的位设置为 {@code true}。
*
* @param bitIndex 位索引
* @throws IndexOutOfBoundsException 如果指定的索引为负
* @since 1.0
*/
public void set(int bitIndex) {
if (bitIndex < 0)
throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
int wordIndex = wordIndex(bitIndex);
expandTo(wordIndex);
words[wordIndex] |= (1L << bitIndex); // 恢复不变性
checkInvariants();
}
在多处理器系统中无法确定 lor
何时被执行。
更准确地说:
`lload` words[wordIndex]
`lor` (1L << bitIndex)
`lstore` words[wordIndex]
这3个命令可以在两个线程之间随时切换。
英文:
As the Author stated: BitSet Javadocs say multi-threaded usages should be synchronized, so this is arguably an artificial example
The JVM makes no guarantees of atomic operations for Bitwise OR: ior, lor.
See: https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html#jvms-2.11.3
The BitSet make not attempt to make atomic changes either.
See: https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/util/BitSet.java
/**
* Sets the bit at the specified index to {@code true}.
*
* @param bitIndex a bit index
* @throws IndexOutOfBoundsException if the specified index is negative
* @since 1.0
*/
public void set(int bitIndex) {
if (bitIndex < 0)
throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
int wordIndex = wordIndex(bitIndex);
expandTo(wordIndex);
words[wordIndex] |= (1L << bitIndex); // Restores invariants
checkInvariants();
}
When the lor
is carried can not be determined in a multiprocessor system.
To be more precise:
`lload` words[wordIndex]
`lor` (1L << bitIndex)
`lstore` words[wordIndex]
These 3 commands can switch at anytime between the 2 threads.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论