關於多線程中可能出現的問題


一.內存模型的相關概念(高速緩存是每個線程特有的,也稱本地緩存)
 大家都知道,計算機在執行程序時,每條指令都是在CPU中執行的,而執行指令過程中,勢必涉及到數據的讀取和寫入。
 由於程序運行過程中的臨時數據是存放在主存(物理內存)當中的,這時就存在一個問題,由於CPU執行速度很快,而從內存讀取數據和向內存寫入數據的過程跟CPU執行指令的速度比起來要慢的多,因此如果任何時候對數據的操作都要通過和內存的交互來進行,會大大降低指令執行的速度。因此在CPU里面就有了高速緩存

二.並發編程中的三個概念
在並發編程中,我們通常會遇到以下三個問題:原子性問題,可見性問題,有序性問題
  1.原子性:即一個操作或者多個操作 要么全部執行並且執行的過程不會被任何因素打斷,要么就都不執行。
例如,如果i=32;不具備原子性的話,當給它的低16賦值完時,突然中斷,其他線程在去讀這個值時,就是錯誤的值.

  2.可見性:指當多個線程訪問同一個變量時,一個線程修改了這個變量的值,其他線程能夠立即看得到修改的值。
這就是可見性問題,線程1對變量i修改了之后,線程2沒有立即看到線程1修改的值。

  3.有序性:即程序執行的順序按照代碼的先后順序執行,首先什么是指令重排序,一般來說,處理器為了提高程序運行效率,可能會對輸入代碼進行優化,
它不保證程序中各個語句的執行先后順序同代碼中的順序一致,但是它會保證程序最終執行結果和代碼順序執行的結果是一致的。處理器在進行重排序時也是會考慮指令之間的數據依賴性
  指令重排序不會影響單個線程的執行,但是會影響到線程並發執行的正確性。

三.Java內存模型
  在Java虛擬機規范中試圖定義一種Java內存模型(Java Memory Model,JMM)來屏蔽各個硬件平台和操作系統的內存訪問差異,以實現讓Java程序在各種平台下都能達到一致的內存訪問效果。那么Java內存模型規定了哪些東西呢,它定義了程序中變量的訪問規則,往大一點說是定義了程序執行的次序。注意,為了獲得較好的執行性能,Java內存模型並沒有限制執行引擎使用處理器的寄存器或者高速緩存來提升指令執行速度,也沒有限制編譯器對指令進行重排序。也就是說,在java內存模型中,也會存在緩存一致性問題和指令重排序的問題。

對並發編程中常見的三問題JMM的解決方法:
1.原子性:
  在Java中,對基本數據類型的變量的讀取和賦值操作是原子性操作,即這些操作是不可被中斷的,要么執行,要么不執行。
例如:
  int i = 10; 是原子操作.
  int j = i; 不是原子操作
可以通過synchronized和Lock來實現。由於synchronized和Lock能夠保證任一時刻只有一個線程執行該代碼塊,
那么自然就不存在原子性問題了,從而保證了原子性。

2.可見性
  對於可見性,Java提供了volatile關鍵字來保證可見性。
  另外,通過synchronized和Lock也能夠保證可見性,synchronized和Lock能保證同一時刻只有一個線程獲取鎖然后執行同步代碼,
並且在釋放鎖之前會將對變量的修改刷新到主存當中。因此可以保證可見性。

3.有序性
  在Java里面,可以通過volatile關鍵字來保證一定的“有序性”,因為可以禁止指令重排序。
  另外可以通過synchronized和Lock來保證有序性,
  很顯然,synchronized和Lock保證每個時刻是有一個線程執行同步代碼,相當於是讓線程順序執行同步代碼,自然就保證了有序性。

補充:外,Java內存模型具備一些先天的“有序性”,即不需要通過任何手段就能夠得到保證的有序性,這個通常也稱為 happens-before 原則。
如果兩個操作的執行次序無法從happens-before原則推導出來,那么它們就不能保證它們的有序性,虛擬機可以隨意地對它們進行重排序。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM