ajax 示例_通过示例了解挥发
ajax 示例
我們已經(jīng)花了幾個月的時間來穩(wěn)定Plumbr中的鎖定檢測功能 。 在此期間,我們遇到了許多棘手的并發(fā)問題。 許多問題是獨特的,但是一種特殊類型的問題一直反復出現(xiàn)。
您可能已經(jīng)猜到了–濫用volatile關(guān)鍵字。 我們已經(jīng)發(fā)現(xiàn)并解決了許多問題,其中大量使用volatile使應用程序的任意部分變慢,延長了鎖定保持時間,最終使JVM屈服。 反之亦然-授予過于寬松的訪問策略會引發(fā)一些令人討厭的并發(fā)問題。
我想每個Java開發(fā)人員都會回想起該語言的第一步。 使用手冊和教程的日子和日子。 這些教程都有關(guān)鍵字列表,其中volatile是最可怕的關(guān)鍵字之一。 隨著時間的流逝,越來越多的代碼不需要使用此關(guān)鍵字,我們很多人都忘記了volatile的存在。 直到生產(chǎn)系統(tǒng)開始以無法預測的方式破壞數(shù)據(jù)或死亡。 調(diào)試這種情況迫使我們中的一些人真正理解了這個概念。 但是我敢打賭,這并不是一個令人愉快的課程,因此也許我可以通過一個簡單的例子來闡明一些概念,從而節(jié)省一些時間。
揮發(fā)作用的例子
該示例模擬了一個銀行辦公室。 銀行辦公室的類型,您可以在該辦公室中從售票機中選擇隊列編號,然后在您前面的隊列得到處理后等待邀請。 為了模擬這樣的辦公室,我們創(chuàng)建了以下示例,該示例由兩個線程組成。
這兩個線程中的第一個被實現(xiàn)為CustomerInLine。 這是一個線程,除了等待NEXT_IN_LINE中的值與客戶的票證匹配外,什么也不做。 票號被硬編碼為#4。 時間到時( NEXT_IN_LINE> = 4),線程宣布等待已結(jié)束并結(jié)束。 這模擬了有一些客戶在排隊的到達辦公室的客戶。
排隊實現(xiàn)在Queue類中,該類運行一個循環(huán),該循環(huán)調(diào)用下一個客戶,然后通過為每個客戶Hibernate200ms來模擬與該客戶的工作。 呼叫下一個客戶后,存儲在類變量NEXT_IN_LINE中的值將增加1。
public class Volatility {static int NEXT_IN_LINE = 0;public static void main(String[] args) throws Exception {new CustomerInLine().start();new Queue().start();}static class CustomerInLine extends Thread {@Overridepublic void run() {while (true) {if (NEXT_IN_LINE >= 4) {break;}}System.out.format("Great, finally #%d was called, now it is my turn\n",NEXT_IN_LINE);}}static class Queue extends Thread {@Overridepublic void run() {while (NEXT_IN_LINE < 11) {System.out.format("Calling for the customer #%d\n", NEXT_IN_LINE++);try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}}}} }因此,運行此簡單程序時,您可能希望該程序的輸出類似于以下內(nèi)容:
Calling for the customer #1 Calling for the customer #2 Calling for the customer #3 Calling for the customer #4 Great, finally #4 was called, now it is my turn Calling for the customer #5 Calling for the customer #6 Calling for the customer #7 Calling for the customer #8 Calling for the customer #9 Calling for the customer #10看來,這個假設是錯誤的。 取而代之的是,您將看到通過10個客戶的列表進行的隊列處理,并且不幸的線程模擬了4號客戶,從不提醒它已經(jīng)看到邀請。 發(fā)生了什么,為什么客戶仍然坐在那里無休止地等待著呢?
分析結(jié)果
您在此處面臨的是將JIT優(yōu)化應用于代碼,該代碼將對NEXT_IN_LINE變量的訪問進行緩存。 兩個線程都有自己的本地副本,并且CustomerInLine線程從不看到Queue實際增加了線程的值。 如果現(xiàn)在您認為這是JVM中的一種可怕的錯誤,那么您就不完全正確了-允許編譯器這樣做以避免每次都重新讀取該值。 因此,您可以提高性能,但要付出代價–如果其他線程更改狀態(tài),則緩存副本的線程將不知道該狀態(tài),并使用過時的值進行操作。
對于volatile正是這種情況。 有了此關(guān)鍵字,編譯器將被警告特定狀態(tài)是易失的,并且每次執(zhí)行循環(huán)時,代碼都被強制重新讀取該值。 有了這些知識,我們就可以進行簡單的修復-只需將NEXT_IN_LINE的聲明更改為以下內(nèi)容,您的客戶就不會永遠坐在隊列中:
static volatile int NEXT_IN_LINE = 0;對于那些只了解volatile用例而感到滿意的人,您將很高興。 只是要知道附加的成本–當您開始聲明所有內(nèi)容都是易失性時,您正在迫使CPU忽略本地緩存并直接進入主內(nèi)存,從而減慢了代碼的速度并阻塞了內(nèi)存總線。
引擎蓋下易揮發(fā)
對于那些希望詳細了解該問題的人,請和我在一起。 要查看底層發(fā)生了什么,讓我們打開調(diào)試以查看JIT從字節(jié)碼生成的匯編代碼。 通過指定以下JVM選項可以實現(xiàn)此目的:
-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly在啟用和禁用volatile的情況下啟用這些選項的情況下運行程序,可以為我們提供以下重要見解:
運行不帶volatile關(guān)鍵字的代碼,表明我們在指令0x00000001085c1c5a上可以比較兩個值。 當比較失敗時,我們繼續(xù)從0x00000001085c1c60到0x00000001085c1c66,后者跳回到0x00000001085c1c60,并產(chǎn)生無限循環(huán)。
0x00000001085c1c56: mov 0x70(%r10),%r11d0x00000001085c1c5a: cmp $0x4,%r11d0x00000001085c1c5e: jge 0x00000001085c1c68 ; OopMap{off=64};*if_icmplt; - Volatility$CustomerInLine::run@4 (line 14)0x00000001085c1c60: test %eax,-0x1c6ac66(%rip) # 0x0000000106957000;*if_icmplt; - Volatility$CustomerInLine::run@4 (line 14); {poll}0x00000001085c1c66: jmp 0x00000001085c1c60 ;*getstatic NEXT_IN_LINE; - Volatility$CustomerInLine::run@0 (line 14)0x00000001085c1c68: mov $0xffffff86,%esi使用volatile關(guān)鍵字后,我們可以看到在指令0x000000010a5c1c40上我們將值加載到寄存器,在0x000000010a5c1c4a上將其與保護值4進行比較。如果比較失敗,則從0x000000010a5c1c4e跳回0x000000010a5c1c40,再次為新的值加載值檢查。 這確保了我們將看到NEXT_IN_LINE變量的更改后的值。
0x000000010a5c1c36: data32 nopw 0x0(%rax,%rax,1)0x000000010a5c1c40: mov 0x70(%r10),%r8d ; OopMap{r10=Oop off=68};*if_icmplt; - Volatility$CustomerInLine::run@4 (line 14)0x000000010a5c1c44: test %eax,-0x1c1cc4a(%rip) # 0x00000001089a5000; {poll}0x000000010a5c1c4a: cmp $0x4,%r8d0x000000010a5c1c4e: jl 0x000000010a5c1c40 ;*if_icmplt; - Volatility$CustomerInLine::run@4 (line 14)0x000000010a5c1c50: mov $0x15,%esi現(xiàn)在,希望說明能使您擺脫幾個討厭的錯誤。
翻譯自: https://www.javacodegeeks.com/2014/08/understanding-volatile-via-example.html
ajax 示例
總結(jié)
以上是生活随笔為你收集整理的ajax 示例_通过示例了解挥发的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OCA第1部分中的Java难题
- 下一篇: 维纳斯是什么神 希腊神话中维纳斯是什么神