hjr-MUD遊戲(六):多線程鎖ThreadLocal和Synchronized

假設 怪物g 有100點血量
勇士a和勇士b 分別有1點攻擊力

使用情景

現在兩種情況

  1. a與b未組隊,我們需要保證a與b對g的攻擊後,g的血量變化對兩個人是獨立的,那麼我們對g加鎖就要用ThreadLocal
  2. a與b組隊,a與b對g攻擊後,g的血量對兩個人是共享的,那麼我們對g加鎖就要用Synchronized

拿spring舉例,我們都知道spring每個請求會創建一個線程,默認又是單例模式

所以每個用戶的請求可以理解爲一個線程,

現在我們定義一個全局變量 gHP,怪物g的血量

爲什麼加鎖

由於是gHP全局變量,會存在多線程競爭問題,先說爲什麼要加鎖。

  1. 比如a與b沒有組隊,a 和 b同時攻擊g,a只有1點攻擊力,打了g一下,卻發現g血量下降的多了一倍(因爲b也在攻擊g)

我們用ThreadLocal(以空間換時間)修飾gHP變量,那麼a與b對g的攻擊導致的gHP變化就是獨立的
因爲gHP會被創建一個副本。a與b單獨操作各自的gHP副本。

  1. a與b組隊了,我們用Synchronized(以時間換空間)修飾gHP變量,表面上看是沒意義的,加不加鎖gHP都是共享 的

但是如果我們多了個判斷,比如 如果gHP==0 則給打敗g的勇士獎勵
現在a把g打到0滴血,結果在剛要做上面判斷的時候
b也打了g,結果還沒判斷完,gHp變成-1了,這樣就出現bug了。
用Synchronized加鎖後,a操作gHP時候b無法操作,就可以避免上面的bug。

使用範圍

所以Synchronized 修飾的是一個代碼段,該段中有對共享資源的讀取判斷等操作

ThreadLocal 修飾的是一個共享變量,會爲該變量在每個線程創建副本

順便一提

數據庫連接dao,也是全局變量

@Autowired
UserMapeer userMapper;

如果你看數據庫日誌,會發現爲每個用戶依舊開啓一個新連接

單例的controller中爲什麼會出現多例的dao

就是因爲spring對某些bean 使用了 ThreadLocal 修飾

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章