1. 程式人生 > >Java 多執行緒加鎖的方式總結及對比

Java 多執行緒加鎖的方式總結及對比

一.Java多執行緒可以通過:

1. synchronized關鍵字

2. Java.util.concurrent包中的lock介面和ReentrantLock實現類

這兩種方式實現加鎖。

二.synchronized關鍵字加鎖的缺陷:

如果一個程式碼塊被synchronized修飾了,當一個執行緒獲取了對應的鎖,並執行該程式碼塊時,其他執行緒便只能一直等待,等待獲取鎖的執行緒釋放鎖,而這裡獲取鎖的執行緒釋放鎖只會有兩種情況:

  1)獲取鎖的執行緒執行完了該程式碼塊,然後執行緒釋放對鎖的佔有;

  2)執行緒執行發生異常,此時JVM會讓執行緒自動釋放鎖。

  那麼如果這個獲取鎖的執行緒由於要等待IO或者其他原因(比如呼叫sleep方法)被阻塞了,但是又沒有釋放鎖,其他執行緒便只能乾巴巴地等待,試想一下,這多麼影響程式執行效率。

  因此就需要有一種機制可以不讓等待的執行緒一直無期限地等待下去(比如只等待一定的時間或者能夠響應中斷),通過Lock就可以辦到。

  再舉個例子:當有多個執行緒讀寫檔案時,讀操作和寫操作會發生衝突現象,寫操作和寫操作會發生衝突現象,但是讀操作和讀操作不會發生衝突現象。

  但是採用synchronized關鍵字來實現同步的話,就會導致一個問題:

  如果多個執行緒都只是進行讀操作,所以當一個執行緒在進行讀操作時,其他執行緒只能等待無法進行讀操作。

  因此就需要一種機制來使得多個執行緒都只是進行讀操作時,執行緒之間不會發生衝突,通過Lock就可以辦到。

  另外,通過Lock可以知道執行緒有沒有成功獲取到鎖。這個是synchronized無法辦到的。

對比:

    1)Lock不是Java語言內建的,synchronized是Java語言的關鍵字,因此是內建特性。Lock是一個類,通過這個類可以實現同步訪問;

  2)Lock和synchronized有一點非常大的不同,採用synchronized不需要使用者去手動釋放鎖,當synchronized方法或者synchronized程式碼塊執行完之後,系統會自動讓執行緒釋放對鎖的佔用;而Lock則必須要使用者去手動釋放鎖,如果沒有主動釋放鎖,就有可能導致出現死鎖現象。

三.Lock和synchronized的選擇:

  總結來說,Lock和synchronized有以下幾點不同:

  1)Lock是一個介面,而synchronized是Java中的關鍵字,synchronized是內建的語言實現;

  2)synchronized在發生異常時,會自動釋放執行緒佔有的鎖,因此不會導致死鎖現象發生;而Lock在發生異常時,如果沒有主動通過unLock()去釋放鎖,則很可能造成死鎖現象,因此使用Lock時需要在finally塊中釋放鎖;

  3)Lock可以讓等待鎖的執行緒響應中斷,而synchronized卻不行,使用synchronized時,等待的執行緒會一直等待下去,不能夠響應中斷;(I/O和Synchronized都能相應中斷,即不需要處理interruptionException異常)

  4)通過Lock可以知道有沒有成功獲取鎖,而synchronized卻無法辦到。

  5)Lock可以提高多個執行緒進行讀操作的效率。

  在效能上來說,如果競爭資源不激烈,兩者的效能是差不多的,而當競爭資源非常激烈時(即有大量執行緒同時競爭),此時Lock的效能要遠遠優於synchronized。所以說,在具體使用時要根據適當情況選擇。


四. 鎖的種類介紹:

在前面介紹了Lock的基本使用,這一節來介紹一下與鎖相關的幾個概念。

  1.可重入鎖

  如果鎖具備可重入性,則稱作為可重入鎖。像synchronized和ReentrantLock都是可重入鎖,可重入性在我看來實際上表明瞭鎖的分配機制:基於執行緒的分配,而不是基於方法呼叫的分配。舉個簡單的例子,當一個執行緒執行到某個synchronized方法時,比如說method1,而在method1中會呼叫另外一個synchronized方法method2,此時執行緒不必重新去申請鎖,而是可以直接執行方法method2。

  看下面這段程式碼就明白了:

1 2 3 4 5 6 7 8 9 class MyClass { public synchronized void method1() { method2(); } public synchronized void method2() { } }

   上述程式碼中的兩個方法method1和method2都用synchronized修飾了,假如某一時刻,執行緒A執行到了method1,此時執行緒A獲取了這個物件的鎖,而由於method2也是synchronized方法,假如synchronized不具備可重入性,此時執行緒A需要重新申請鎖。但是這就會造成一個問題,因為執行緒A已經持有了該物件的鎖,而又在申請獲取該物件的鎖,這樣就會執行緒A一直等待永遠不會獲取到的鎖。

  而由於synchronized和Lock都具備可重入性,所以不會發生上述現象。

  2.可中斷鎖

  可中斷鎖:顧名思義,就是可以相應中斷的鎖。

  在Java中,synchronized就不是可中斷鎖,而Lock是可中斷鎖。

  如果某一執行緒A正在執行鎖中的程式碼,另一執行緒B正在等待獲取該鎖,可能由於等待時間過長,執行緒B不想等待了,想先處理其他事情,我們可以讓它中斷自己或者在別的執行緒中中斷它,這種就是可中斷鎖。

  在前面演示lockInterruptibly()的用法時已經體現了Lock的可中斷性。

  3.公平鎖

  公平鎖即儘量以請求鎖的順序來獲取鎖。比如同是有多個執行緒在等待一個鎖,當這個鎖被釋放時,等待時間最久的執行緒(最先請求的執行緒)會獲得該所,這種就是公平鎖。

  非公平鎖即無法保證鎖的獲取是按照請求鎖的順序進行的。這樣就可能導致某個或者一些執行緒永遠獲取不到鎖。

  在Java中,synchronized就是非公平鎖,它無法保證等待的執行緒獲取鎖的順序。

  而對於ReentrantLock和ReentrantReadWriteLock,它預設情況下是非公平鎖,但是可以設定為公平鎖。

  看一下這2個類的原始碼就清楚了:

  

  在ReentrantLock中定義了2個靜態內部類,一個是NotFairSync,一個是FairSync,分別用來實現非公平鎖和公平鎖。

  我們可以在建立ReentrantLock物件時,通過以下方式來設定鎖的公平性:

1 ReentrantLock lock = new ReentrantLock(true);

   如果引數為true表示為公平鎖,為fasle為非公平鎖。預設情況下,如果使用無參構造器,則是非公平鎖。

  

  另外在ReentrantLock類中定義了很多方法,比如:

  isFair()        //判斷鎖是否是公平鎖

  isLocked()    //判斷鎖是否被任何執行緒獲取了

  isHeldByCurrentThread()   //判斷鎖是否被當前執行緒獲取了

  hasQueuedThreads()   //判斷是否有執行緒在等待該鎖

  在ReentrantReadWriteLock中也有類似的方法,同樣也可以設定為公平鎖和非公平鎖。不過要記住,ReentrantReadWriteLock並未實現Lock介面,它實現的是ReadWriteLock介面。

  4.讀寫鎖

  讀寫鎖將對一個資源(比如檔案)的訪問分成了2個鎖,一個讀鎖和一個寫鎖。

  正因為有了讀寫鎖,才使得多個執行緒之間的讀操作不會發生衝突。

  ReadWriteLock就是讀寫鎖,它是一個介面,ReentrantReadWriteLock實現了這個介面。

  可以通過readLock()獲取讀鎖,通過writeLock()獲取寫鎖。


ReadWriteLock

  ReadWriteLock也是一個介面,在它裡面只定義了兩個方法:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public interface ReadWriteLock { /** * Returns the lock used for reading. *

相關推薦

Java 執行方式總結對比

一.Java多執行緒可以通過: 1. synchronized關鍵字 2. Java.util.concurrent包中的lock介面和ReentrantLock實現類 這兩種方式實現加鎖。 二.synchronized關鍵字加鎖的缺陷: 如

java執行的實現方式總結

一個專案所用的技術往往是由業務所驅動的,平常我們寫的最多的是業務的CRUD,這是一個普遍的現象,要想往上提升,往往繞不開多執行緒知識,這篇文章是LZ對多執行緒實現的一些看法 多執行緒的三種實現方式 目前多執行緒的實現方式有三種,讓我帶您一一看來 繼承Thre

執行 的三種方式

加鎖的第一種方式: public class RootBeanDefinition{ final Object constructorArgumentLock = new Object(); fin

java執行,執行以及Condition類的使用

看了網上非常多的執行程式碼,很多都是重複的再說一件事,可能對於java老鳥來說,理解java的多執行緒是非常容易的事情,但是對於我這樣的菜鳥來說,這個實在有點難,可能是我太菜了,網上重複的陳述對於我理解這個問題一點幫助都沒有.所以這裡我寫下我對於這個問題的理解,目的是為了防止我忘記. 還是從程式碼例項開始講起

java執行物件、類、同步機制詳解

1.在java多執行緒程式設計中物件鎖、類鎖、同步機制synchronized詳解:     物件鎖:在java中每個物件都有一個唯一的鎖,物件鎖用於物件例項方法或者一個物件例項上面的。     類鎖:是用於一個類靜態方法或者class物件的,一個

Java執行-無

1 無鎖類的原理詳解 1.1 CAS CAS演算法的過程是這樣:它包含3個引數CAS(V,E,N)。V表示要更新的變數,E表示預期值,N表示新值。僅當V 值等於E值時,才會將V的值設為N,如果V值和E值不同,則說明已經有其他執行緒做了更新,則當前執行緒什麼 都不做。最後,CAS返

java執行機制二

網上看到一個題目,題目是這樣:Java多執行緒,啟動四個執行緒,兩個執行加一,另外兩個執行減一。 針對該問題寫了一個程式,測試通過,如下: class Sync { static int count = 0; public void add() {

java執行機制一

網上看了一篇關於java synchronized關鍵字使用的很好的文章,現將其簡要總結一下,加深理解。 先總結兩個規則: synchronized鎖住的是括號裡的物件,而不是程式碼。對於非static的synchronized方法,鎖的就是物件本身也就是this。 多個執行緒

java 執行 雙重檢查

雙重鎖檢查 public class User { private static User user; public static User getInstance() { if (user == null) { // 1:第一次檢查

Java執行程式設計 — 優化

作者:melonstreet 連結:www.cnblogs.com/QG-whz 閱讀目錄 一、儘量不用:儘量不要鎖住方法 二、減小粒度:縮小同步程式碼塊,只鎖資料 三、避免巢狀:鎖中儘量不要再包含鎖 四、鎖私有化:將鎖私有化,在內部管理鎖 五、適當分解:進行適當的鎖分解

java執行物件 同步機制詳解

分享一下我老師大神的人工智慧教程吧。零基礎,通俗易懂!風趣幽默!http://www.captainbed.net/ 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

java:執行(實現Runnable的原理)二種方式的區別

* 1,看Thread類的建構函式,傳遞了Runnable介面的引用  * 2,通過init()方法找到傳遞的target給成員變數的target賦值 * 3,檢視run方法,發現run方法中有判斷,如果target不為null就會呼叫Runnable介面子類物件的run方法 *

Java執行優化策略

轉載 http://www.cnblogs.com/ygj0930/p/6561264.html 編碼過程中可採取的鎖優化的思路有以下幾種: 1:減少鎖持有時間 例如:對一個方法加鎖,不如對方法中需要同步的幾行程式碼加鎖; 2:減小鎖粒度 例如:

java 執行和valitile關鍵字

死鎖 兩個或者多個執行緒都在等待對方釋放鎖,在寫多執行緒程式碼時要注意避免這種死鎖的發生 發生死鎖後可以在dos命令列輸入jps命令檢視java程序狀況 可以試用jstack -l 程序號   命令檢視當前類的問題 關閉jvm停止死鎖   以上節

java 執行synchronized同步方法,同步程式碼塊

執行緒安全問題 同步和非同步 我們知道多個執行緒共享堆記憶體,當兩個或者多個執行緒呼叫同一個物件的方法操作物件成員時,因為cpu輪流執行執行緒,執行緒A剛開始操作物件方法,修改了資料,輪到執行緒B執行,執行緒B也操作物件方法,修改資料,可能又輪到執行緒A操作物件方法,接著上次執行緒A的剩餘部

Java執行思維導圖總結

自己學習總結了一些思維導圖(持續更新中),後面附有GitHub連結 ,分享給大家。https://github.com/panjianlong13/MindMapSummary             &n

Java執行實現的方式

Java多執行緒實現的方式有四種 1.繼承Thread類,重寫run方法 2.實現Runnable介面,重寫run方法,實現Runnable介面的實現類的例項物件作為Thread建構函式的target 3.通過Callable和FutureTask建立執行緒 4.通過執行緒池建立執行

Java執行模型-順序與資源

順序鎖:當應用程式使用2把以上的鎖時,就容易出現因為多執行緒獲取鎖的順序不同而死鎖的情形,包括交叉獲取應用程式範圍內的多把已知鎖、交叉獲取應用程式與第三方方法中的多把鎖而造成的順序死鎖。絕大多數死鎖都是因為CPU排程多執行緒時,在執行時序上是交叉進行的而造成亂序獲得多把鎖,從

java執行的分類

轉載:https://blog.csdn.net/nalanmingdian/article/details/77800355 上一篇既然提到了鎖,這一篇來詳細介紹JAVA中的鎖,也為之後JUC下的鎖做一個鋪墊  其實如果按照名稱來說,鎖大概有以下名詞: 自旋鎖 ,自旋鎖的其

java執行細節問題整理總結30條

        學習,內容越多、越雜的知識,越需要進行深刻的總結,這樣才能記憶深刻,將知識變成自己的。這篇文章主要是對多執行緒的問題進行總結的,因此羅列了自己整理的多執行緒的問題,都是自己覺得比較經典和一些大企業面試會問