多線程一定快嗎
由於線程有創建和上下文切換的開銷,短時間的操作會比單線程更慢
如何減少上下文切換
- 無鎖併發編程:多線程競爭鎖,會引發上下文切換,所以可以減少鎖的使用,如,按照數據的ID按照Hash取模分段,不同的線程處理不同的段
- CAS算法:Java的Atomic包使用這個來更新數據,不需要加鎖
- 使用最少線程:避免創建不需要的線程
- 協程:單線程中實現多任務調度,在單線程中維持多任務間的切換
volatile
他在多處理器開發中保證了共享變量的“可見性”,可見性指當一個線程修改一個共享變量時,另外一個線程能讀到這個修改的值。
爲了提高處理速度,處理器不直接和內存進行通信,而是先將系統內存的數據讀到內部緩存後進行操作,但操作完成不知道何時回寫會內存,所以普通的操作會出現兩個處理器的數據不一致的情況,而導致多線程數據不統一,這時候可以使用volatile。
volatile會做兩件事情:
- 將當前處理器緩存的數據寫回到系統內存中
- 這個寫回內存的操作會使其他CPU裏緩存了該內存地址的數據無效
synchronized
Java中的內一個對象都可以作爲鎖,
- 對於普通同步方法,鎖是當前實例對象
- 對於靜態同步方法,鎖是當前類的Class對象
- 對於同步方法塊,鎖是Synchronized括號裏的對象
synchronized在JVM的實現原理,JVM進入和退出Monitor對象來實現方法同步和代碼塊的同步,包括monitorenter和monitorexit,在編譯後插入的同步代碼塊的開始和結束或者異常的位置,JVM保證這兩個是成對出現,當且一個monitor被持有後就鎖定。
synchronized的鎖是存在java對象頭裏的
原子操作
- 總線鎖
兩個處理器同時從各自的緩存中讀取變量i,分別進行加1,然後寫回系統內存,可能會出現覆蓋寫入的情況,結果不是3,而是2
處理器使用總線鎖可以處理:提供一個LOCK信號,當一個處理器在總線上輸出此信號時,其他處理器的請求被阻塞,處理器可以獨佔共享內存。
總線鎖,鎖住了所有的內存通信,開銷太大。 - 緩存鎖
內存區域如果被緩存在處理器緩存中,並且Lock操作期間被鎖定,當他執行鎖操作回寫到內存是,處理器不在總線上聲明lock,而是修改內部的內存地址,並允許他的緩存一致性機制來保證原子性。