java多線程(四)
使用synchronized鎖實現線程同步
為什麽要用線程同步
我們先來看下這段代碼的運行結果:
在多線程上篇博客已經介紹過了,JVM采用的是搶占式調度模型,當一個線程sleep的時候,其它線程會搶占CPU資源。如果發生在數據庫中,就是“臟讀”。synchronized鎖就是用來解決這個問題的,多線程的線程同步機制實際上是靠鎖的概念來控制的。
第一種方式:synchronized關鍵字修飾函數方法
第二種方式:synchronized關鍵字修飾代碼塊
多個對象多個鎖的情況
三個線程同時進行,每個線程只打印一個字母,交替打印ABCABC...
prev代表前一個對象,self代表自身。線程先持有前一個對象的鎖和本次要打印的對象的鎖,執行打印,然後喚醒一個正在等待當前對象鎖的線程(剩下的那個線程),並讓它拿到對象鎖。prev.wait()方法讓本線程進入等待狀態,讓本線程休眠,線程自動釋放其占有的對象鎖,並等待notify。如此循環反復打印8次ABC。
總結一下
-
當多個線程訪問同一對象的時候,只能有一個線程取得對象的鎖,多個對象需要多個對象的鎖。
-
哪個線程執行了帶synchronized關鍵字的方法,哪個線程就持有該方法所屬對象的鎖,其他的線程要訪問這個對象鎖內的內容,都只能等待這個鎖被釋放後,再去搶占資源獲得對象的鎖。
-
synchronized修飾非static的方法時,鎖的就是對象本身,也就是this。
-
synchronized修飾static的方法時,方法中無法使用this,所以它鎖的不是this,而是這個類。所以,static synchronized方法也相當於全局鎖。
-
使用synchronized關鍵字,應盡量縮小代碼塊的範圍,最好能在代碼塊上加同步,而不是在整個方法上加同步。因為你鎖的範圍大的話,時間又長,別的線程就不會獲得相應的資源。
A線程持有對象的鎖,B線程可以以異步方式調用對象中的非synchronized同步的方法。
java多線程(四)