程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java 多線程同步問題的探究(三、Lock來了,大家都讓開【2】)

Java 多線程同步問題的探究(三、Lock來了,大家都讓開【2】)

編輯:關於JAVA

【2. Fair or Unfair It is a question...】

讓我們繼續前面有關ReentrantLock的話題。

首先,ReentrantLock有一個帶布爾型參數的構造函數,在JDK官方文檔中對它是這樣描 述的:

“此類的構造方法接受一個可選的公平 參數。當設置為 true 時,在多個線程的爭用下,這些鎖傾向於將訪問權授予等待時間 最長的線程。否則此鎖將無法保證任何特定訪問順序。與采用默認設置(使用不公平鎖)相比,使用公平鎖的程序在許多線程訪問時表現 為很低的總體吞吐量(即速度很慢,常常極其慢),但是在獲得鎖和保證鎖分配的均衡性時差異較小。不過要注意的是,公平鎖不能保證 線程調度的公平性。因此,使用公平鎖的眾多線程中的一員可能獲得多倍的成功機會,這種情況發生在其他活動線程沒有被處理並且目前 並未持有鎖時。還要注意的是,未定時的 tryLock  方法並沒有使用公平設置。因為即使其他線程正在等待,只要該鎖是可用的,此方法 就可以獲得成功。”

簡單來講:公平鎖使線程按照請求鎖的順序依次獲得鎖;而不公平鎖則允許討價還價,在這種情況下,線程有 時可以比先請求鎖的其他線程先得到鎖。

觀察采用公平鎖和非公平鎖的例程運行效果發現:線程獲得鎖的順序發生了一些變化(見 下表)。

Unfair:

1 is running!

1 got lock1@Step1!

3 is running!

2 is running!

1 first Reading count:1

1 release lock1@Step1!

3 got lock1@Step1!

1 got lock2@Step2!

thread 1 set age to:18

thread 1 first read age is:18

3 first Reading count:2

3 release lock1@Step1!

2 got lock1@Step1!

thread 1 second read age is:18

1 release lock2@Step2!

3 got lock2@Step2!

thread 3 set age to:34

thread 3 first read age is:34

2 first Reading count:3

2 release lock1@Step1!

thread 3 second read age is:34

3 release lock2@Step2!

2 got lock2@Step2!

thread 2 set age to:72

thread 2 first read age is:72

thread 2 second read age is:72

2 release lock2@Step2!

成功生成( 總時間:20 秒) Fair:

1 is running!

1 got lock1@Step1!

2 is running!

3 is running!

1 first Reading count:1

1 release lock1@Step1!

1 got lock2@Step2!

thread 1 set age to:82

thread 1 first read age is:82

2 got lock1@Step1!

2 first Reading count:2

2 release lock1@Step1!

3 got lock1@Step1!

thread 1 second read age is:82

1 release lock2@Step2!

2 got lock2@Step2!

thread 2 set age to:65

thread 2 first read age is:65

3 first Reading count:3

3 release lock1@Step1!

thread 2 second read age is:65

2 release lock2@Step2!

3 got lock2@Step2!

thread 3 set age to:31

thread 3 first read age is:31

thread 3 second read age is:31

3 release lock2@Step2!

成功生成( 總時間:20 秒)

這樣的變化告訴我們:

采用非公平的鎖時,當一個線程釋放了第一個鎖以後,由於線程的搶占,剛剛被釋放的鎖馬上被下一個線程 占有。采用公平鎖時,由於公平鎖傾向於將訪問權授予等待時間最長的線程,所以,當第一個鎖被第一個線程釋放以後,第二個鎖馬上將 訪問權授予第一個線程,而第一個鎖將訪問權授予了第二個線程。這裡,公平鎖在平衡分配方面耗費了一定的時間,這使得第一個線程獲 得第二個鎖的時間優先於第二個線程獲得第一個鎖。這樣,采用不同的鎖,就出現了兩種不同的結果。

為了看到公平鎖和非公平鎖 性能上的差異,我們不妨將其中線程的睡眠時間設定為1毫秒,然後把循環產生的線程數提高到5000(修改後的代碼已忽略,自行修改), 可以發現,由於公平鎖要維持鎖分配的均衡性,所以,采用公平鎖的程序總運行時間更長一些。

根據運行環境的差異,有些朋友可 能並不一定能很直觀的從運行結果中看到兩種不同的鎖帶來的性能差異。不妨引用IBM開發者社區的一組測試結果來看一看就行有什麼樣的 差異吧:

4CPU情況下的同步、非公平鎖和公平鎖吞吐量比較:

單CPU情況下,同步、非公平鎖和公平鎖的吞吐量:

可以看到,同步和公平鎖的吞吐量都是最低的,公平鎖更低一些。但是同步內置的監控器鎖是不公平的,而且永遠都是不公平的。而 JVM 保證了所有線程最終都會得到它們所等候的鎖。確保統計上的公平性,對多數情況來說,這就已經足夠了,而這花費的成本則要比絕 對的公平保證的低得多。

既然Lock這麼近乎完美,那我們也許可以忘卻synchronized了。

但是任何事物都是有兩面性的。

1.使用Lock,你必須手動的在finally塊中釋放鎖。鎖的獲得和釋放是不受JVM控制的。這要求編程人員更加細心。

2.當 JVM 用 synchronized 管理鎖定請求和釋放時,JVM 在生成線程轉儲時能夠包括鎖定信息。這些對調試非常有價值,因為它們能標識死鎖或者其他 異常行為的來源。Lock 類只是普通的類,JVM 不知道具體哪個線程擁有 Lock 對象。

Lock提供了在多線程爭用的情況下更好的並 發性,但這是以犧牲一定的可維護性為代價的。

所以說,當大量線程發生爭用的時候,Lock來了,大家都讓開。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved