下面是我總結的關于鎖的思維導圖

synchronized 多線程并發編程

重量級鎖。JDK1.6對synchronized進行了優化。

JDK1.6為了減少獲得鎖和釋放鎖帶來的性能消耗,引入的偏向鎖和輕量級鎖。

synchronized有三種方式來加鎖,分別是:

(1)修飾實例方法,作用于當前實例加鎖,進入同步代碼之前要獲得當前實例的鎖

(2)修飾靜態方法,作用于當前類對象加鎖,進入同步代碼前要獲得的當前類對象的鎖。

(3)代碼塊、同步代碼塊。指定加鎖對象,對給定的對象加鎖,進入同步代碼塊之前,要獲得給定對象的鎖。

 

實例方法:調用該方法的實例

靜態方法:類對象(代碼如下)

this:代表該方法的實例對象。

同步代碼塊中可以用的結構

(1)創建一個對象

(2)類對象

(3)當前實例this

括號里的也可以叫同步監視器

操作共享數據的代碼

共享數據:多個縣城共同操作的變量,都可以充當鎖

當時用同步方法時,synchronized鎖的東西是this,this代表當前類的對象,也就是方法的調用者(默認的)

使用synchronized解決線程同步問題的兩種方式

關于同步方法:

  • 同步方法依然會涉及到同步鎖對象,只是不需要我們寫出來
  • 非靜態的同步方法,同步鎖就是this

靜態的同步方法,同步監視器就是類本身

關于同步代碼塊:

  • 首先要選好同步監視器(同步鎖),選好用哪一個對象,推薦使用類對象,第三方對象,this。
  • 在實現接口創建的線程類中,同步代碼塊是不可以用this來充當同步鎖的,推薦使用類對象。

同步的方式,解決線程安全的問題。

操作同步代碼時,只有一個線程能夠參與,其他線程等待。

相當于一個單線程的過程,效率低。

synchronized只針對于當前JVM虛擬機可以解決線程安全問題。

synchronized弊端:不能跨JVM解決問題。

死鎖

多個線程同時被阻塞,他們中的一個或者全部都在等待某個資源的釋放由于線程無限期的阻塞,程序就不可能正常終止。

在Java中死鎖產生的四個必要條件

  1. 互斥使用:當資源被一個線程使用(占用),別的線程不能使用
  2. 不可搶占:資源的請求者不能強制從占有者中搶奪資源,資源只能從占有者手動釋放
  3. 請求和保持
  4. 循環等待:通常會存在一個等待的隊列。例如P1占有了P2的資源,P2占有了P3的資源,P3占有了P1的資源。形成了一個等待環路。

線程重入

任意線程在拿到鎖之后,再次獲取該鎖不會被該鎖阻礙

線程不會被自己鎖死,這就叫線程的重入

synchronized又叫可重入鎖

JDK1.6以后鎖升級:

  1. 無鎖:不加鎖
  2. 偏向鎖:不鎖鎖,當只有一個線程爭奪時,偏向某一個線程,這個線程不加鎖
  3. 輕量級鎖:少量線程來了之后,先嘗試自旋(嘗試自己能不能解決問題),不掛起線程。
  4. 重量級鎖:排隊掛起(暫停)線程(synchronized是重量級鎖)

掛起線程和恢復線程需要轉入內核態中完成這些操作,會給系統的并發性帶來很大的壓力。

在許多應用上共享數據的鎖定狀態,一般情況下智慧持續很短的時間,為了這段時間去掛起和恢復并不值得。

我們可以讓后面的線程等待一下,不要放棄處理器的執行時間。

鎖是為了讓線程等待,我們只需要讓線程之星一個循環,自旋。【自旋鎖】

Object類對多線程的支持

wait()

wait(loong timeout):當前線程進入 等待狀態

notify():喚醒正在等待的下一個線程

notifyAll():喚醒正在等待的所有線程

不是線程類提供的方法

這兩種方法的使用前提,必須要有鎖,要有線程同步

線程間的通信

比如兩條線程共同運行。線程A如果先走,線程B就要等待,等到線程A走完,喚醒線程B,線程B再走。

方法的總結:

1.Thread的兩個靜態方法

??sleep方法釋放CPU資源,但是不會釋放鎖

??yield方法釋放CPU的執行權,保留了CPU的執行資格,不常用

2.join方法,出讓了執行權,join就加入進來

3.wait方法:釋放CPU資源,釋放鎖

??notify:喚醒等待中的線程

??notifyAll:喚醒等待中的所有線程

面試題:sleep和wait的區別

1.sleep是Thread中的方法;wait是Object中的方法

2.sleep不會釋放鎖,wait會釋放鎖并會加入到等待的隊列中

3.sleep不依賴synchronized同步器,wait需要依賴synchronized關鍵字

4.sleep不需要被喚醒(休眠之后退出阻塞),wait需要被喚醒(不指定時間需要被別人中斷)

案例:生產者與消費者模型

有兩條線程。一條線程生產產品,另一條線程消費產品

這兩條線程,初始狀態是什么情況

線程的退出

(1)使用退出標志,來讓線程正常退出,run方法結束后線程終止。不要使用stop方法

(2)interrupt方法:終端線程

調用interrupt方法會拋出InterruptdeException異常。捕獲后再做停止線程的邏輯即可。

如果線程while(true)

線程的常用方法:Thread類中的方法

start方法:啟動當前線程,執行run方法

run方法

currentThread方法:靜態方法,獲取當前正在執行的線程

getId():返回次線程的唯一標識

setName():設置當前線程的name

getName():獲取當前線程的name

getPriority():獲取當前線程的優先級

setPriority(int):設置當前線程的優先級

getState():獲取當前線程的生命周期

interrupt():中斷線程的執行

interrupted():查看當前線程是否中斷

 

懶漢式的最終版

?

推薦使用內部類枚舉的方式解決問題,因為枚舉天生就是單例的,天生構造器私有化。

枚舉天生就是用來做單例模式。

???????????????????????????