天天看點

Java并發中正确使用volatile并發 – 定義Java的并發Java記憶體模型Safe publication案例JSR-133

一個線性在執行一個操作時持有對一個資源的獨占鎖。(互斥)

一般用在沖突比較可能發生的場景下

嘗試采用原子操作,而不需要持有鎖;沖突可被檢測,如果發生沖突,具有相應的重試邏輯

通常用在沖突較少發生的場景下

算法確定對線程間競争共享資源時候,不會因為互斥而使任一線程的執行無限延遲;

如果系統整個流程的執行是無阻塞的(系統某一部分可能被短暫阻塞),這種非阻塞算法就是無鎖的。

無鎖算法比傳統的基于鎖的算法對系統的開銷更小,且更容易在多核多cpu處理器上擴充;

在實時系統中可以避免鎖帶來的延遲;

cas (compare and swap)或ll/sc(load linked/store conditional),以及記憶體屏障相關的指令經常被用在算法實作中。

如果每個線程的執行都是無阻塞的,這種非阻塞算法就是無等待的(比無鎖算法更好)

java的記憶體模型并不保證一個線程可以一直以程式執行的順序看到另一個線程對變量的修改,除非兩個線程都跨越了同一個記憶體屏障。(safe publication)

一個線程内的每個動作 happens-before 同一個線程内在代碼順序上在其後的所有動作

對一個volatile變量的讀,總是能看到(任意線程)對這個volatile變量最後的寫入

如果a happens-before b, b happens-before c,那 a happens-before c

<code>01</code>

<code>class</code> <code>volatileexample {</code>

<code>02</code>

<code>    </code><code>int</code> <code>x =</code><code>0</code><code>;</code>

<code>03</code>

<code>    </code><code>volatile</code> <code>int</code> <code>b =</code><code>0</code><code>;</code>

<code>04</code>

<code>05</code>

<code>    </code><code>private</code> <code>void</code> <code>write() {</code>

<code>06</code>

<code>        </code><code>x =</code><code>5</code><code>;</code>

<code>07</code>

<code>        </code><code>b =</code><code>1</code><code>;</code>

<code>08</code>

<code>    </code><code>}</code>

<code>09</code>

<code>10</code>

<code>    </code><code>private</code> <code>void</code> <code>read() {</code>

<code>11</code>

<code>        </code><code>int</code> <code>dummy = b;</code>

<code>12</code>

<code>        </code><code>while</code> <code>(x !=</code><code>5</code><code>) {</code>

<code>13</code>

<code>        </code><code>}</code>

<code>14</code>

<code>15</code>

<code>16</code>

<code>    </code><code>public</code> <code>static</code> <code>void</code> <code>main(string[] args)</code><code>throws</code> <code>exception {</code>

<code>17</code>

<code>        </code><code>final</code> <code>volatileexample example =</code><code>new</code> <code>volatileexample();</code>

<code>18</code>

<code>        </code><code>thread thread1 =</code><code>new</code> <code>thread(</code><code>new</code> <code>runnable() {</code>

<code>19</code>

<code>            </code><code>public</code> <code>void</code> <code>run() {</code>

<code>20</code>

<code>                </code><code>example.write();</code>

<code>21</code>

<code>            </code><code>}</code>

<code>22</code>

<code>        </code><code>});</code>

<code>23</code>

<code>        </code><code>thread thread2 =</code><code>new</code> <code>thread(</code><code>new</code> <code>runnable() {</code>

<code>24</code>

<code>25</code>

<code>                </code><code>example.read();</code>

<code>26</code>

<code>27</code>

<code>28</code>

<code>        </code><code>thread1.start();</code>

<code>29</code>

<code>        </code><code>thread2.start();</code>

<code>30</code>

<code>        </code><code>thread1.join();</code>

<code>31</code>

<code>        </code><code>thread2.join();</code>

<code>32</code>

<code>33</code>

<code>}</code>

Java并發中正确使用volatile并發 – 定義Java的并發Java記憶體模型Safe publication案例JSR-133

x并不需要定義為<code>volatile</code>, 程式裡可以有需要類似x的變量,我們隻需要一個volatile變量b來確定線程a能看到線程1對x的修改:

根據代碼順序規則,線程1的<code>x=5;</code> happens-before <code>b=1;</code>; 線程2的<code>int dummy = b;</code> happens-before <code>while(x!=5);</code>

根據volatile變量規則,線程2的<code>b=1;</code> happens-before <code>int dummy=b;</code>

根據傳遞性,<code>x=5;</code> happens-before <code>while(x!=5);</code>

在jsr-133之前的舊java記憶體模型中,雖然不允許volatile變量之間重排序,但舊的java記憶體模型仍然會允許volatile變量與普通變量之間重排序。jsr-133則增強了volatile的記憶體語義:嚴格限制編譯器(在編譯器)和處理器(在運作期)對volatile變量與普通變量的重排序,確定volatile的寫-讀和螢幕的釋放-擷取一樣,具有相同的記憶體語義。