synchronized是java的一種內部鎖,是一種排他鎖,一般也被稱爲悲觀鎖,它可以保障原子性,可見性,有序性。java
當多個線程去調用同一個方法的時候,若是不用加synchronized鎖,就可能出現線程不安全的問題。舉個經典的例子,好比兩夫妻一個用銀行卡,一個用網銀同時取同一個帳戶的錢,安全
取錢這個操做在銀行的後臺確定是一個方法,若是兩方同時調用,頗有可能形成取了兩份的錢,這樣確定是不行的。性能
1,synchronized加在方法上this
public class T { private int count = 10; public synchronized void m() { count--; System.out.println(Thread.currentThread().getName() + " count = " + count); } }
2,synchronized代碼塊spa
public class T { private int count = 10; public void m() { synchronized(this) { count--; System.out.println(Thread.currentThread().getName() + " count = " + count); } } }
這裏兩種方式達到的效果是同樣的,咱們須要關注如下幾點:操作系統
1,synchronized鎖,鎖的是什麼東西。實際上是鎖的一個對象,任意對象均可以(String常量,Integer,Long不能使用)。當一個線程拿到鎖以後,其餘的線程就只能等待當前線程執行完,線程
並釋放鎖以後,才能拿到鎖並執行。以此來保證線程的安全。code
2,這兩種方式咱們該用哪種呢?實際開發中,咱們應該用代碼塊的方式,爲何要加鎖,一般都是須要訪問共享變量纔會加鎖,一個方法中並非全部代碼都須要訪問共享變量,對象
其餘的業務邏輯是不須要加鎖的,因此代碼塊的方式能夠提升程序的性能。blog
3,synchronized是一種可重入的鎖,什麼意思呢,就是若是synchronized代碼塊中又調用了另一個加鎖的方法,原本若是鎖沒有釋放,是不能拿到鎖的。可是可重入鎖是能夠的,系統會自動識別。
jdk早期的時候,synchronized的底層實現是重量級的,重量到可能須要到操做系統去申請鎖的地步,因此形成synchronized的效率很是低。jdk1.5以後進行了改進,有了鎖升級的概念。
當咱們訪問synchronized的時候,HotSpot的實現是這樣的,當第一個線程來訪問的時候,先在鎖對象的頭上markword記錄這個線程,實際上只要一個線程來訪問的時候,是不會加鎖的,
只是記錄這個線程ID,此時稱之爲偏向鎖。
偏向鎖若是有線程競爭的話,好比我第一個線程尚未釋放鎖,第二個線程又來了,就會自動升級爲自旋鎖,自旋鎖的實現原理就是,線程會一直轉圈等待獲取鎖,若是轉圈十次以後,尚未獲取到鎖
就自動升級爲重量級鎖。
因此說從效率方面來說,CAS(後續文章會講解)並非必定就比synchronized鎖的效率高,理解synchronized的底層實現,咱們就能夠獲得以下結論:
爲何這樣說呢,假如我有1000個線程,用CAS自旋,那豈不是有999個線程會一直在旋轉等待,這樣是很是消耗資源的。