我的理解,同步就是爲了解決重排序的問題。內存屏障的意思就是程序正常讀寫內存時,遇到了happen before,就像遇到一堵牆同樣,必須排隊過去緩存
Synchronization has several aspects. The most well-understood is mutual exclusion -- only one thread can hold a monitor at once, so synchronizing on a monitor means that once one thread enters a synchronized block protected by a monitor, no other thread can enter a block protected by that monitor until the first thread exits the synchronized block.app
Synchronization有多種含義。最廣爲人知的是互斥————同一時刻一條線程只能持有一個監視器,所以能夠在這個監視器上實現同步,這意味着,對於由一個監視器保護着的同步塊,只要有一個線程進入,其它線程就進不去了,由於拿不到監視器。ui
But there is more to synchronization than mutual exclusion. Synchronization ensures that memory writes by a thread before or during a synchronized block are made visible in a predictable manner to other threads which synchronize on the same monitor. After we exit a synchronized block, we release the monitor, which has the effect of flushing the cache to main memory, so that writes made by this thread can be visible to other threads. Before we can enter a synchronized block, we acquire the monitor, which has the effect of invalidating the local processor cache so that variables will be reloaded from main memory. We will then be able to see all of the writes made visible by the previous release.this
但Synchronization並不止互斥。Synchronization能夠確保可見性,在相同的監視器下,一條線程在同步塊以前或當中向內存寫入時,其它線程會看到這個寫入。這是因爲在離開同步塊後,線程會釋放這個監視器,而釋放監視器會將緩存刷進主內存。在進入同步塊以前,線程會獲取監視器,而獲取監視器會清空本地處理器緩存,這樣變量值就會從主內存從新加載。這樣的話,全部以前的寫入都是可見的了。線程
Discussing this in terms of caches, it may sound as if these issues only affect multiprocessor machines. However, the reordering effects can be easily seen on a single processor. It is not possible, for example, for the compiler to move your code before an acquire or after a release. When we say that acquires and releases act on caches, we are using shorthand for a number of possible effects.code
以上是在有緩存的狀況下討論的,聽起來好像只會發生在多核處理器中,可是,單核處理器中也很容易出現重排序。在獲取監視器以前,以及釋放監視器以後,編譯器是不會移動代碼的。這裏只提到獲取和釋放二詞,但實際上會有不少細節在其中的。orm
The new memory model semantics create a partial ordering on memory operations (read field, write field, lock, unlock) and other thread operations (start and join), where some actions are said to happen before other operations. When one action happens before another, the first is guaranteed to be ordered before and visible to the second. The rules of this ordering are as follows:排序
在新的內存模型語義下, 在內存操做(讀、寫、加鎖、解鎖),以及其餘線程操做(啓動、中止)時,會進行局部排序,這被稱做happen before語義,一些操做會先於其餘操做以前進行。當A操做happen before 操做B,則A會被強制排序在B前面,而且對B是可見的。其中排序規則以下:ip
Each action in a thread happens before every action in that thread that comes later in the program's order.內存
線程中每一個操做,happen before,此線程中以後的按序操做
An unlock on a monitor happens before every subsequent lock on that same monitor.
監視器的解鎖,happen before,此監視器隨後的加鎖
A write to a volatile field happens before every subsequent read of that same volatile.
volatile字段的寫入,happen before,此字段隨後的讀取
A call to start() on a thread happens before any actions in the started thread.
調用start(),happen before,所啓動線程的每一個操做
All actions in a thread happen before any other thread successfully returns from a join() on that thread.
線程中全部操做,happen before,其它線程調用此線程的join()成功返回
This means that any memory operations which were visible to a thread before exiting a synchronized block are visible to any thread after it enters a synchronized block protected by the same monitor, since all the memory operations happen before the release, and the release happens before the acquire.
Happen before的語義意味着,同一個監視器保護着的同步塊,對於一條線程,在該線程進入同步塊以後、離開以前,任何對其可見的內存操做,對其餘線程也是可見的。由於全部的內存操做 hapen before 監視器的釋放,監視器的釋放 happen before 監視器的獲取。
簡而言之,外面的能看到裏面的。監視器的釋放先於獲取,解釋了以上「而釋放監視器會將緩存刷進主內存」,由於按時間順序,寫入主內存 --> 釋放 --> 獲取。
Another implication is that the following pattern, which some people use to force a memory barrier, doesn't work:
Synchronization的另外一個含義,是以以下的方式,製造一個內存屏障,雖然不少人這樣用,但其實是錯的:
synchronized (new Object()) {}
This is actually a no-op, and your compiler can remove it entirely, because the compiler knows that no other thread will synchronize on the same monitor. You have to set up a happens-before relationship for one thread to see the results of another.
以上其實是一個空操做no-operation,編譯器會將synchronized徹底移除,由於這不是同一個監視器,其它線程不會在這裏同步。爲了看到一條線程對內存中數據的修改,你必須將它與其它線程設置happen-before關係,也就是要讓這條線程先進入同步塊。
Important Note: Note that it is important for both threads to synchronize on the same monitor in order to set up the happens-before relationship properly. It is not the case that everything visible to thread A when it synchronizes on object X becomes visible to thread B after it synchronizes on object Y. The release and acquire have to "match" (i.e., be performed on the same monitor) to have the right semantics. Otherwise, the code has a data race.
注意:爲了合理的經過同步,讓兩條線程產生happen before關係,必須使用相同的監視器。