msk*_*msk 15 java concurrency multithreading
内存一致性错误和线程干扰之间有什么区别?如何使用同步来避免它们的不同?请举例说明.我无法从sun Java教程中得到这个.任何阅读材料的建议,只是在java的上下文中理解这将是有帮助的.
blu*_*ucz 16
内存一致性错误不能完全在java的上下文中理解 - 多CPU系统上的共享内存行为的细节是高度特定于体系结构的,并且更糟糕的是,x86(今天大多数人编码学习代码)与从一开始就为多处理器机器设计的架构(如POWER和SPARC)相比,它具有相当程序友好的语义,因此大多数人真的不习惯于考虑内存访问语义.
我将给出一个常见的例子,说明内存一致性错误会让你遇到麻烦.假设这个例子,初始值x是3.几乎所有架构都保证如果一个CPU执行代码:
STORE 4 -> x // x is a memory address
STORE 5 -> x
Run Code Online (Sandbox Code Playgroud)
并执行另一个CPU
LOAD x
LOAD x
Run Code Online (Sandbox Code Playgroud)
要么看到3,3,3,4,4,4,4,5,或者5,5从这个角度它的两个LOAD指令.基本上,CPU保证从所有CPU的角度保持对单个存储器位置的写入顺序,即使允许其他CPU已知的每个写入的确切时间也可以变化.
CPU彼此不同的地方往往是它们所做的保证LOAD和STORE涉及不同内存地址的操作.假设这个例子,两个x和的初始值y是4.
STORE 5 -> x // x is a memory address
STORE 5 -> y // y is a different memory address
Run Code Online (Sandbox Code Playgroud)
然后另一个CPU执行
LOAD x
LOAD y
Run Code Online (Sandbox Code Playgroud)
在这个例子中,在一些系统上,第二个线程可以看到4,4,5,5,4,5,或5,4.哎哟!
大多数架构处理在32位或64位字的粒度记忆-这意味着一个32位POWER/SPARC机器上,你不能更新64位整数内存位置和安全地从另一个线程读取它永远不显式同步.高飞,是吗?
线程干扰要简单得多.基本思想是java不保证java代码的单个语句以原子方式执行.例如,递增值需要读取值,递增值,然后再次存储.所以你可以int x = 1在两个线程执行之后x++,x可以最终为2或者3取决于低级代码如何交错(这里的低级抽象代码可能看起来像LOAD x, INCREMENT, STORE x).这里的基本思想是将java代码分解为更小的原子片段,除非明确使用同步原语,否则不能假设它们如何交错.
欲了解更多信息,请查看此文件.它是漫长而干燥的,由一个臭名昭着的混蛋写的,但是,嘿,这也很不错.另外看看这个(或只是谷歌"双重检查锁定被打破").这些内存重新排序问题为许多C++/java程序员带来了丑陋的头脑,这些程序员几年前试图让他们的单例初始化变得有点过于聪明.
内存一致性问题通常表现为破坏的发生前关系。
Time A: Thread 1 sets int i = 1
Time B: Thread 2 sets i = 2
Time C: Thread 1 reads i, but still sees a value of 1, because of any number of reasons that it did not get the most recent stored value in memory.
Run Code Online (Sandbox Code Playgroud)
volatile您可以通过在变量上使用关键字或使用包中的 AtomicX 类来防止这种情况发生java.util.concurrent.atomic。这些消息中的任何一个都确保没有第二个线程会看到部分修改的值,并且没有人会看到不是内存中最新实际值的值。
(同步 getter 和 setter 也可以解决问题,但对于其他不知道为什么这样做的程序员来说可能看起来很奇怪,并且在面对使用反射的绑定框架和持久性框架等情况时也可能会崩溃。)
--
线程交错是指两个线程清理一个对象并看到不一致的状态。
我们有一个带有 itemQuantity 和 itemPrice 的 PurchaseOrder 对象,自动逻辑生成发票总额。
Time 0: Thread 1 sets itemQuantity 50
Time 1: Thread 2 sets itemQuantity 100
Time 2: Thread 1 sets itemPrice 2.50, invoice total is calculated $250
Time 3: Thread 2 sets itemPrice 3, invoice total is calculated at $300
Run Code Online (Sandbox Code Playgroud)
线程 1 执行了错误的计算,因为其他一些线程在其操作之间弄乱了该对象。
您可以通过使用synchronized关键字来解决此问题,以确保一次只有一个人可以执行整个过程,或者使用包中的锁java.util.concurrent.locks。使用 java.util.concurrent 通常是新程序的首选方法。
| 归档时间: |
|
| 查看次数: |
4978 次 |
| 最近记录: |