In multiprocessor systems, processors generally have one or more layers of memory cache, which improves performance both by speeding access to data (because the data is closer to the processor) and reducing traffic on the shared memory bus (because many memory operations can be satisfied by local caches.) Memory caches can improve performance tremendously, but they present a host of new challenges. What, for example, happens when two processors examine the same memory location at the same time? Under what conditions will they see the same value?程序員
多核處理器通常有多級緩存,在緩存中,因爲離處理器更近,使得訪問數據速度更快速,並且本地緩存也能夠知足大部分的內存操做,所以處理器與共享內存總線的交互也會變少。能夠說,緩存大大提升了程序性能。編程
可是,緩存也隨之帶來了一大堆新的挑戰,好比,兩個處理器同時查詢相同的一塊內存,什麼狀況下才能看到相同的值呢?緩存
At the processor level, a memory model defines necessary and sufficient conditions for knowing that writes to memory by other processors are visible to the current processor, and writes by the current processor are visible to other processors. Some processors exhibit a strong memory model, where all processors see exactly the same value for any given memory location at all times. Other processors exhibit a weaker memory model, where special instructions, called memory barriers, are required to flush or invalidate the local processor cache in order to see writes made by other processors or make writes by this processor visible to others. These memory barriers are usually performed when lock and unlock actions are taken; they are invisible to programmers in a high level language.多線程
在處理器層面,內存模型定義了充要條件,以搞清楚多個處理器和惟一的內存之間的可見關係,如什麼狀況下其餘處理器對內存的寫入對當前處理器是可見的,或者什麼狀況下當前處理器對內存的寫入對其餘處理器是可見的。架構
部分處理器有着很是強的內存模型,使得全部核心在任什麼時候間任何的內存位置,查詢到的值都是同樣的。但其他的處理器並不會有這麼強的內存模型,它們爲了看到別的處理器的寫入,或者讓別的處理器看到本身的寫入,就須要用到內存屏障這樣的特殊指令。併發
It can sometimes be easier to write programs for strong memory models, because of the reduced need for memory barriers. However, even on some of the strongest memory models, memory barriers are often necessary; quite frequently their placement is counterintuitive. Recent trends in processor design have encouraged weaker memory models, because the relaxations they make for cache consistency allow for greater scalability across multiple processors and larger amounts of memory.app
若是處理器是強內存模型的,那編程起來自當容易,由於根本不用理會內存屏障。然而,即便是強內存模型,也是會用到內存屏障的,由此致使極頻繁的內存屏障指令也是不合常理的。ide
所以,處理器設計趨向於更加弱的內存模型,由於對保持內存一致的放寬,可讓多核處理器和大內存有更大的可擴展性。性能
The issue of when a write becomes visible to another thread is compounded by the compiler's reordering of code. For example, the compiler might decide that it is more efficient to move a write operation later in the program; as long as this code motion does not change the program's semantics, it is free to do so. If a compiler defers an operation, another thread will not see it until it is performed; this mirrors the effect of caching.flex
相比於處理器,對於一個線程寫入操做,可否對其餘線程可見的問題,同時受到編譯器重排序的影響。例如,編譯器也許會把一條寫入操做放到程序最後,由於它以爲這樣能夠提升程序效率,這麼看, 編譯器仍是很任性的嘛...不過只要移動代碼不影響程序語義,那也就由着編譯器了...可一旦編譯器推遲了一行代碼,在執行以前其餘線程就都不會看到了,這也反映了緩存的效果。
Moreover, writes to memory can be moved earlier in a program; in this case, other threads might see a write before it actually "occurs" in the program. All of this flexibility is by design -- by giving the compiler, runtime, or hardware the flexibility to execute operations in the optimal order, within the bounds of the memory model, we can achieve higher performance.
此外,對內存的寫入也可能被放到程序的前面,這種狀況下,其餘線程會在這個寫入操做本應發生前看到它。設計如此靈活的重排序,就是爲了賦予編譯器、運行時或者硬件以最佳的順序靈活的執行程序命令。利用重排序和內存模型的約束,咱們可讓程序表現的更好。
A simple example of this can be seen in the following code:
如下代碼是一個重排序的簡例:
Class Reordering { int x = 0, y = 0; public void writer() { x = 1; y = 2; } public void reader() { int r1 = y; int r2 = x; } }
Let's say that this code is executed in two threads concurrently, and the read of y sees the value 2. Because this write came after the write to x, the programmer might assume that the read of x must see the value 1. However, the writes may have been reordered. If this takes place, then the write to y could happen, the reads of both variables could follow, and then the write to x could take place. The result would be that r1 has the value 2, but r2 has the value 0.
在兩條線程併發執行這段代碼,而且讀到y的值是2的狀況下,程序員可能會假定x的值一定是1,由於y=2在x=1後面。但writer方法可能發生重排序,先y=2,後執行reader方法,而後x=1,致使r1=2,而r2=0。
The Java Memory Model describes what behaviors are legal in multithreaded code, and how threads may interact through memory. It describes the relationship between variables in a program and the low-level details of storing and retrieving them to and from memory or registers in a real computer system. It does this in a way that can be implemented correctly using a wide variety of hardware and a wide variety of compiler optimizations.
JMM描述了多線程編碼中那些行爲是合法的,以及線程間如何經過內存進行交互。它描述了在計算機中,程序中的變量,與變量在內存或寄存器中讀寫的底層細節,之間的關係。在某種程度上,JMM可使用多種硬件和多種編譯器優化來正確實現。
Java includes several language constructs, including volatile, final, and synchronized, which are intended to help the programmer describe a program's concurrency requirements to the compiler. The Java Memory Model defines the behavior of volatile and synchronized, and, more importantly, ensures that a correctly synchronized Java program runs correctly on all processor architectures.
Java在語言層面上有幾個概念,包括volatile,final,synchronized,用來幫助程序員告訴編譯器,程序應該如何併發運行。JMM中,volatile和synchronized尤其重要,它們確保了一個同步的程序在全部多核架構中正確運行。