Pra*_*eek 33 java java.util.concurrent happens-before
在阅读有关内存一致性错误的Java文档时.我找到了与两个创造事件相关的点 - 在关系之前:
当一个语句调用时Thread.start()
,与该语句有一个before-before关系的每个语句也与新线程执行的每个语句都有一个before-before关系.新线程可以看到导致创建新线程的代码的影响.
当一个线程终止并导致Thread.join()
另一个线程返回时,终止
线程执行的所有语句
与成功连接后的所有语句都有一个before-before关系.现在,执行连接的线程可以看到线程中代码的效果.
我无法理解他们的意思.如果有人用一个简单的例子解释它会很棒.
Joa*_*son 33
现代CPU并不总是按照更新的顺序将数据写入内存,例如,如果运行伪代码(假设为了简单起见,变量总是存储在内存中);
a = 1
b = a + 1
Run Code Online (Sandbox Code Playgroud)
... CPU b
在写入内存之前可以很好地写入a
内存.只要你在一个线程中运行东西,这就不是一个真正的问题,因为一旦完成赋值,运行上面代码的线程将永远不会看到任一变量的旧值.
多线程是另一回事,您认为以下代码会让另一个线程获取繁重计算的值;
a = heavy_computation()
b = DONE
Run Code Online (Sandbox Code Playgroud)
......另一个线程......
repeat while b != DONE
nothing
result = a
Run Code Online (Sandbox Code Playgroud)
但问题是在将结果存储到存储器之前可以在存储器中设置完成标志,因此另一个线程可以在将计算结果写入存储器之前获取存储器地址a的值.
同样的问题 - 如果Thread.start
和Thread.join
没有"发生之前"保证 - 给你代码的问题,如;
a = 1
Thread.start newthread
...
newthread:
do_computation(a)
Run Code Online (Sandbox Code Playgroud)
...因为a
线程启动时可能没有存储到内存的值.
由于您几乎总是希望新线程能够使用在启动之前初始化的数据,Thread.start
因此具有"之前发生"保证,即,在Thread.start
保证可用于新线程之前已经更新的数据.同样的事情会Thread.join
在那里被新的线程写入的数据被保证是可见的,在终止之后加入它的线程.
它只是使线程更容易.
Evg*_*eev 21
考虑一下:
static int x = 0;
public static void main(String[] args) {
x = 1;
Thread t = new Thread() {
public void run() {
int y = x;
};
};
t.start();
}
Run Code Online (Sandbox Code Playgroud)
主线已改变字段x
.如果其他线程未与主线程同步,则Java内存模型不保证此更改对其他线程可见.但线程t
将看到此更改,因为调用的主线程t.start()
和JLS保证调用t.start()
使更改成为x
可见,t.run()
因此y
保证分配1
.
同样的担忧 Thread.join();
根据java内存模型未正确同步的代码中可能会出现线程可见性问题.由于编译器和硬件优化,一个线程的写入并不总是通过读取另一个线程可见.Java内存模型是一种正式模型,它使"正确同步"的规则变得清晰,以便程序员可以避免线程可见性问题.
Happens-before是在该模型中定义的关系,它指的是特定的执行.在读取R 之前证明发生的写入W 保证在读取之前是可见的,假设没有其他干扰写入(即没有发生与读取之前发生的写入,或者根据读取发生在它们之间的写入)那种关系).
最简单的发生 - 之前的关系发生在同一线程中的动作之间.线程P中的写入W到V发生在同一线程中的V读取R之前,假设W根据程序顺序到达R之前.
您引用的文本指出thread.start()和thread.join()也保证发生之前的关系.在thread.start()之前发生的任何操作也发生在该线程中的任何操作之前.类似地,线程内的操作发生在thread.join()之后出现的任何操作之前.
这有什么实际意义?例如,如果您启动一个线程并等待它以非安全方式终止(例如长时间休眠,或者测试一些非同步标志),那么当您尝试读取由此完成的数据修改时线程,您可能会部分地看到它们,因此存在数据不一致的风险.join()方法充当一个屏障,保证线程发布的任何数据片段由另一个线程完全可见.
归档时间: |
|
查看次数: |
12534 次 |
最近记录: |