天天看點

java多線程(四)

使用synchronized鎖實作線程同步

為什麼要用線程同步

我們先來看下這段代碼的運作結果:

java多線程(四)
java多線程(四)

Java學習交流群:495273252

在多線程上篇部落格已經介紹過了,JVM采用的是搶占式排程模型,當一個線程sleep的時候,其它線程會搶占CPU資源。如果發生在資料庫中,就是“髒讀”。synchronized鎖就是用來解決這個問題的,多線程的線程同步機制實際上是靠鎖的概念來控制的。

第一種方式:synchronized關鍵字修飾函數方法

java多線程(四)

第二種方式:synchronized關鍵字修飾代碼塊

java多線程(四)

多個對象多個鎖的情況

三個線程同時進行,每個線程隻列印一個字母,交替列印ABCABC...

java多線程(四)
java多線程(四)

prev代表前一個對象,self代表自身。線程先持有前一個對象的鎖和本次要列印的對象的鎖,執行列印,然後喚醒一個正在等待目前對象鎖的線程(剩下的那個線程),并讓它拿到對象鎖。prev.wait()方法讓本線程進入等待狀态,讓本線程休眠,線程自動釋放其占有的對象鎖,并等待notify。如此循環反複列印8次ABC。

總結一下

當多個線程通路同一對象的時候,隻能有一個線程取得對象的鎖,多個對象需要多個對象的鎖。

哪個線程執行了帶synchronized關鍵字的方法,哪個線程就持有該方法所屬對象的鎖,其他的線程要通路這個對象鎖内的内容,都隻能等待這個鎖被釋放後,再去搶占資源獲得對象的鎖。

synchronized修飾非static的方法時,鎖的就是對象本身,也就是this。

synchronized修飾static的方法時,方法中無法使用this,是以它鎖的不是this,而是這個類。是以,static synchronized方法也相當于全局鎖。

使用synchronized關鍵字,應盡量縮小代碼塊的範圍,最好能在代碼塊上加同步,而不是在整個方法上加同步。因為你鎖的範圍大的話,時間又長,别的線程就不會獲得相應的資源。

A線程持有對象的鎖,B線程可以以異步方式調用對象中的非synchronized同步的方法。