我希望理解《Java并发实践》中的这一句话:“出于薄空气的安全性是指当一个线程在没有同步的情况下读取变量时,它可能会看到一个过期的值,但该值将是由一个线程设置的,而不是一些随机值。”这里的“随机值”是什么意思?它如何进入这种状态?提供伪代码示例将非常有帮助。
现有的两个答案都描述了读写操作的撕裂,但在我看来这并不完全等同于虚构值。
撕裂基本上意味着计算机重新写入数据。
int g = 0x1234;
void threadA() {
g = 0xABCD;
}
void threadB() {
int local = g;
}
转化为
int g = 0x1234;
void threadA() {
g = 0xAB00; // "tearing"
g += 0x00CD;
}
void threadB() {
int local = g; // may read 0xAB00, which threadA never stored
}
int g1 = 0x1234;
bool g2 = true;
void threadA() {
g1 = (g2 ? 0xABCD : 0x5678); // since g2 is true, this stores 0xABCD
}
void threadB() {
int local = g1;
}
转换为
int g1 = 0x1234;
bool g2 = false;
void threadA() {
g1 = 0x5678;
if (g2) g1 = 0xABCD;
}
void threadB() {
int local = g1; // may read 0x5678, which threadA never stored
}
long
。long
必须是64位宽。32位CPU无法一次原子写入long
值,必须写入两个32位整数才能实现。Person
对象,它拥有address
, city
和state
三个字段吗?此人可能有旧地址或新地址,但永远不会以部分更改地址的方式返回,从而导致不存在的地址。 - Compassint value = 5;
情况下)。默认初始化在规范的第4.12.5节中描述。这意味着变量被初始化为对应类型的“零”值。通常,对变量的赋值是原子性的,即它们会立即发生,变量的值从一个值改变为新值。但对于long
和double
类型的变量可能有例外。这在规范中有所描述。实际上,这些值是64位宽的,可以分两步设置,每个32位半部分设置一次。因此,变量的值可能处于以下状态之一:默认值(“零”/null),由线程设置的值,对于非易失性长整型或双精度浮点数,是期望值的一半(0|half 或 half|0)。总的来说,这些要求意味着变量的值不会出现莫名其妙的情况,不会读取随机数据(先前在该内存位置的任何数据),这与C或C++等语言不同。请注意保留HTML标签。int a=0
int b=0
Thread1:
r1=a (1)
b=r1 (2)
Thread2:
r2=b (3)
a=r2 (4)