4
另一个question让我怀疑seqlock是否可以用Java中的易失版本计数器高效地实现。是否有可能在Java中有效地实现seqlock?
这里是一个典型的实现,对于情况下,将永远只能是一个作家线程:
class Seqlock {
private volatile long version = 0;
private final byte[] data = new byte[10];
void write(byte[] newData) {
version++; // 1
System.arraycopy(newData, 0, data, 0, data.length); // 2
version++; // 3
}
byte[] read() {
long v1, v2;
byte[] ret = new byte[data.length];
do {
v1 = version; // 4
System.arraycopy(data, 0, ret, 0, data.length); // 5
v2 = version; // 6
} while (v1 != v2 || (v1 & 1) == 1);
}
}
的基本思想是在写入前后递增的版本号,并供读者检查自己得了通过验证版本号是否相同甚至如奇数表示“正在写入”来读取“一致”读取。
由于版本是易失性的,因此在写入者线程和读取者线程中的关键动作之间存在各种各样的发生关系。但是,我不能看到什么阻止(2)处的写入在(1)上方向上移动,从而导致读者看到写入正在进行。
例如,使用每行旁边注释中的标签(也显示data
读取和写入不易变且因此不是同步顺序的一部分,缩进)的易失性读取和写入的以下同步顺序: :
1a (version is now 1)
2a (not part of the synchronization order)
3 (version is now 2)
4 (read version == 2, happens before 3)
5 (not part of the synchronization order)
6 (read version == 2, happens before 4 and hence 3)
1b (second write, version is now 3)
2b (not part of the synchronization order)
ISTM不存在之前发生5(数据的读出)和2b(该数据的第二写入之间,因此可能的是,读出和错误的数据之前发生2B
如果是这样,那么write()
是否宣告为有帮助吗?
我可以轻松回答最后一个问题:如果读取未同步,则声明写入同步是毫无意义的。至于挥发性是否独立发挥作用,我仍在思考这一点。 – jtahlborn
可能不是您正在寻找的内容,但是您可以使用对write()方法中指定的byte []的简单易失性引用,以非常简单的方式在java中解决此问题(具有相同的保证)。 – jtahlborn
我无法理解你的“同步顺序”。你有多少个线程?在第四行中,'4(读取版本== 2,3之前发生)'是什么意思?发生了什么事?我建议你画一个“表格”,每一列都是一个线程,每一行都是“一个瞬间”。 –