好習慣要堅持,這是我第二篇博文,任務(wù)略重,但是要堅持努力?。?!
1.競爭條件
首先,我們回顧一下《Java核心技術(shù)卷》里講到的多線程的“競爭條件”。由于各線程訪問數(shù)據(jù)的次序,可能會產(chǎn)生訛誤的現(xiàn)象,這樣一個情況通常稱為“競爭條件”。
那么,訛誤具體是怎么產(chǎn)生的呢?本質(zhì)上,是由于操作的非原子性。比如,假定兩個線程同時執(zhí)行指令 account[to] += amount;該指令可能會被處理如下:
1)將account[to]加載到寄存器。
2)增加amount[to]。
3)將結(jié)果寫回account[to]。
現(xiàn)在,假定第一個線程執(zhí)行步驟1和2,然后,它被剝奪了運行權(quán)。假定第二個線程被喚醒并修改了accounts數(shù)組中的同一項。然后,第1個線程被喚醒并完成第3步。這樣,這一動作擦去了第二個線程所做的更新。于是,總金額不再正確。
---------------------------------------------我是分割線---------------------------------------------------------------------------------------------
好,我們再從java的內(nèi)存模型來深層次講講“訛誤”,這里有個概念叫做“緩存一致性”。
大家都知道,計算機在執(zhí)行程序時,每條指令都是在CPU中執(zhí)行的,而執(zhí)行指令過程中,勢必涉及到數(shù)據(jù)的讀取和寫入。由于程序運行過程中的臨時數(shù)據(jù)是存放在主存(物理內(nèi)存)當中的,這時就存在一個問題,由于CPU執(zhí)行速度很快,而從內(nèi)存讀取數(shù)據(jù)和向內(nèi)存寫入數(shù)據(jù)的過程跟CPU執(zhí)行指令的速度比起來要慢的多,因此如果任何時候?qū)?shù)據(jù)的操作都要通過和內(nèi)存的交互來進行,會大大降低指令執(zhí)行的速度。因此在CPU里面就有了高速緩存。
也就是,當程序在運行過程中,會將運算需要的數(shù)據(jù)從主存復(fù)制一份到CPU的高速緩存當中,那么CPU進行計算時就可以直接從它的高速緩存讀取數(shù)據(jù)和向其中寫入數(shù)據(jù),當運算結(jié)束之后,再將高速緩存中的數(shù)據(jù)刷新到主存當中。舉個簡單的例子,比如下面的這段代碼:
i = i + 1;