synchronized锁
現在集群,分布式,微服務這么火,基本上也不會有單機服務了,所以synchronized基本上就廢了,但不影響我們再回憶一下他的一些思想,很多東西,萬變不離其宗。
概念:
能夠保證同一時刻最多只有一個線程執行該段代碼,以達到保證并發安全的作用。
核心思想:
1、一個鎖只能同時被一個線程獲取,沒拿到鎖的線程必須等待
2、每個實例都對應自己的一把鎖,不同實例的鎖互不影響。
3、如果鎖對象是*.class或者synchronized修飾靜態方法時,所有對象其實是共用一把鎖,這把鎖也叫類鎖。
4、鎖住的方法如果拋出異常,JVM會自動釋放鎖。
性質
1、可重入
同一線程的外層函數獲得鎖后,內層函數可以直接再次獲取該鎖
好處:避免死鎖,提高封裝線性
2、不可中斷
一旦這個鎖被別人獲得,那么我如果想獲得這個鎖,只能選擇等待或者阻塞,直到別人釋放了這個鎖
相比Lock可中斷,這個synchronized就是等到死。
原理
加鎖和釋放鎖,其實就是操作內置鎖,等價于lock的lock方法和unlock方法。
每個對象,都有一個對象頭,對象頭中可以存很多信息,其中有一個就是synchronized的信息。
javac test.java
javap -verbose test.class
對于加鎖的,我們可以在反編譯中看到兩個指令,monitorenter和monitorexit。
這兩個指令,就相當于Lock鎖的lock方法和unlock方法。
monitor可以理解是個計數器,
計數器初始為0,0代表可以獲取鎖。
當一個線程獲取鎖,對應的就是執行monitorenter指令,計數器+1
同一個線程如果重入,就繼續+1,多次重入就多次+1
當退出鎖方法,對應的就是執行monitorexit指令,計數器-1
如果有重入的,那就退一個就-1,計數器減到0,就代表釋放鎖。
如果計數器不為0,那么其他線程嘗試獲取鎖,就會獲取不到。
synchronized保證可見性
我們知道線程之間的通信,是通過主內存通信的,而其實每個線程都有自己的本地變量的副本,加這一層就是為了快,類似于緩存,那只要是緩存,就會出現緩存不一致。
而使用了synchronized關鍵字后,就會無視這層緩存,比如一個對象被鎖住,那么鎖住后任何修改,都會直接寫入主內存,所以不會出現線程的內存和主內存不一致的情況。
同樣的,得到鎖對象的時候,也是直接從主內存拿的。
synchronized缺點
1、效率低
鎖不能人為釋放,只能等執行完或者異常才能釋放
Lock能解決這個問題(Lock可以設置超時時間,trylock方法)。
2、不靈活
相比讀寫鎖,synchronized沒分開讀寫,那讀的時候也會加鎖,是在沒必要。
總結
單機服務,盡量少用synchronized
集群服務,禁止使用synchronized
雖然現在幾乎不用synchronized了,但他的原理都是可以借鑒的,比如計數器+1的思路,解決可重入等等,其實包括現在的分布式鎖,實現不一樣,但說白了最終都是一樣的,就是換個地方存計數器而已。redis分布式鎖,相當于把計數器存在redis中,zookeeper分布式鎖,相當于把計數器存在zookeeper中,數據庫實現的,也是一樣。
總結
以上是生活随笔為你收集整理的synchronized锁的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 秒杀业务的基础点
- 下一篇: mysql用户添加_MySQL用户添加