Java synchronized 可重入鎖 基本概念
Java 5以前的併發程式設計
Java的執行緒模型建立在搶佔式執行緒排程的基礎上,也就是說:
- 所有執行緒可以很容易的共享同一程式中的物件。
- 能夠引用這些物件的任何執行緒都可以修改這些物件。
- 為了保護資料,物件可以被鎖住。
Java基於執行緒和鎖的併發過於底層,而且使用鎖很多時候都是很萬惡的,因為它相當於讓所有的併發都變成了排隊等待。
在Java 5以前,可以用synchronized關鍵字來實現鎖的功能,它可以用在程式碼塊和方法上,表示在執行整個程式碼塊或方法之前執行緒必須取得合適的鎖。對於類的非靜態方法(成員方法)而言,這意味這要取得物件例項的鎖,對於類的靜態方法(類方法)而言,要取得類的Class物件的鎖,對於同步程式碼塊,程式設計師可以指定要取得的是那個物件的鎖。
不管是同步程式碼塊還是同步方法,每次只有一個執行緒可以進入,如果其他執行緒試圖進入(不管是同一同步塊還是不同的同步塊),JVM會將它們掛起(放入到等鎖池中)。這種結構在併發理論中稱為臨界區(critical section)。這裡我們可以對Java中用synchronized實現同步和鎖的功能做一個總結:
- 只能鎖定物件,不能鎖定基本資料型別
- 被鎖定的物件陣列中的單個物件不會被鎖定
- 同步方法可以視為包含整個方法的synchronized(this) { … }程式碼塊
- 靜態同步方法會鎖定它的Class物件
- 內部類的同步是獨立於外部類的
- synchronized修飾符並不是方法簽名的組成部分,所以不能出現在介面的方法宣告中
- 非同步的方法不關心鎖的狀態,它們在同步方法執行時仍然可以得以執行
- synchronized實現的鎖是可重入的鎖
在JVM內部,為了提高效率,同時執行的每個執行緒都會有它正在處理的資料的快取副本,當我們使用synchronzied進行同步的時候,真正被同步的是在不同執行緒中表示被鎖定物件的記憶體塊(副本資料會保持和主記憶體的同步,現在知道為什麼要用同步這個詞彙了吧),簡單的說就是在同步塊或同步方法執行完後,對被鎖定的物件做的任何修改要在釋放鎖之前寫回到主記憶體中;在進入同步塊得到鎖之後,被鎖定物件的資料是從主記憶體中讀出來的,持有鎖的執行緒的資料副本一定和主記憶體中的資料檢視是同步的 。
基於synchronized關鍵字的鎖機制有以下問題:
- 鎖只有一種型別,而且對所有同步操作都是一樣的作用
- 鎖只能在程式碼塊或方法開始的地方獲得,在結束的地方釋放
- 執行緒要麼得到鎖,要麼阻塞,沒有其他的可能性
Java 5的併發程式設計
Java 5對鎖機制進行了重構,提供了顯示的鎖,這樣可以在以下幾個方面提升鎖機制:
- 可以新增不同型別的鎖,例如讀取鎖和寫入鎖
- 可以在一個方法中加鎖,在另一個方法中解鎖
- 可以使用tryLock方式嘗試獲得鎖,如果得不到鎖可以等待、回退或者乾點別的事情,當然也可以在超時之後放棄操作
顯示的鎖都實現了java.util.concurrent.Lock介面,主要有兩個實現類:
- ReentrantLock – 比synchronized稍微靈活一些的重入鎖
- ReentrantReadWriteLock – 在讀操作很多寫操作很少時效能更好的一種重入鎖
可重入鎖
- 可重入鎖,也叫做遞迴鎖,指的是同一執行緒外層函式獲得鎖之後 ,內層遞迴函式仍然有獲取該鎖的程式碼,但不受影響。
- 可重入鎖(Reentrant Lock),是指允許同一個執行緒多次對該鎖進行acquire動作。對於不可重入的鎖,當一個執行緒多次呼叫acquire後將造成死鎖。
Reentrant 鎖意味著什麼呢?
簡單來說,它有一個與鎖相關的獲取計數器,如果擁有鎖的某個執行緒再次得到鎖,那麼獲取計數器就加1,然後鎖需要被釋放兩次才能獲得真正釋放。這模仿了 synchronized 的語義;如果執行緒進入由執行緒已經擁有的監控器保護的 synchronized 塊,就允許執行緒繼續進行,當執行緒退出第二個(或者後續) synchronized 塊的時候,不釋放鎖,只有執行緒退出它進入的監控器保護的第一個 synchronized 塊時,才釋放鎖。
本文節選自:關於Java併發程式設計的總結和思考
作者:jiankunking 出處:http://blog.csdn.net/jiankunking
相關文章
- synchronized鎖重入問題synchronized
- 淺談Java中的鎖:Synchronized、重入鎖、讀寫鎖Javasynchronized
- Java多執行緒/併發10、不可重入鎖/自旋鎖、可重入鎖Java執行緒
- Java中可重入鎖ReentrantLock原理剖析JavaReentrantLock
- Java併發-顯式鎖篇【可重入鎖+讀寫鎖】Java
- Java 多執行緒學習筆記(五)synchronized 鎖重入Java執行緒筆記synchronized
- redis分散式鎖-可重入鎖Redis分散式
- java中如何實現可重入的自旋鎖Java
- 可重入鎖原始碼分析原始碼
- Golang可重入鎖的實現Golang
- Java 種15種鎖的介紹:公平鎖,可重入鎖,獨享鎖,互斥鎖等等Java
- Java 種15種鎖的介紹:公平鎖,可重入鎖,獨享鎖,互斥鎖等等...Java
- 【Java面試】什麼是可重入,什麼是可重入鎖? 它用來解決什麼問題?Java面試
- java重入鎖、公平鎖和非公平鎖Java
- Redisson 分散式鎖原始碼 01:可重入鎖加鎖Redis分散式原始碼
- 從原始碼入手詳解ReentrantLock,一個比synchronized更強大的可重入鎖原始碼ReentrantLocksynchronized
- 【java併發程式設計】ReentrantLock 可重入讀寫鎖Java程式設計ReentrantLock
- 【Java】深入理解ReentrantLock可重入鎖之簡單使用JavaReentrantLock
- java 同步鎖(synchronized)Javasynchronized
- ZooKeeper 分散式鎖 Curator 原始碼 01:可重入鎖分散式原始碼
- ReentrantLock可重入鎖——原始碼詳解ReentrantLock原始碼
- Go 為什麼不支援可重入鎖?Go
- Java 重入鎖 ReentrantLock 原理分析JavaReentrantLock
- Java 中15種鎖的介紹:公平鎖,可重入鎖,獨享鎖,互斥鎖,樂觀鎖,分段鎖,自旋鎖等等Java
- ZooKeeper 分散式鎖 Curator 原始碼 03:可重入鎖併發加鎖分散式原始碼
- Java併發基礎-鎖的使用及原理(可重入鎖、讀寫鎖、內建鎖、訊號量等)Java
- ReentrantLock可重入鎖、公平鎖非公平鎖區別與實現原理ReentrantLock
- 舉例講解 Python 中的死鎖、可重入鎖和互斥鎖Python
- 重入鎖的理解
- ZooKeeper 分散式鎖 Curator 原始碼 02:可重入鎖重複加鎖和鎖釋放分散式原始碼
- Java併發包原始碼學習系列:ReentrantLock可重入獨佔鎖詳解Java原始碼ReentrantLock
- python多執行緒程式設計4: 死鎖和可重入鎖Python執行緒程式設計
- java中synchronized鎖定物件問題Javasynchronized物件
- Java併發程式設計之鎖機制之(ReentrantLock)重入鎖Java程式設計ReentrantLock
- Synchronized同步鎖synchronized
- Java 併發開發:內建鎖 SynchronizedJavasynchronized
- synchronized類鎖與物件鎖synchronized物件
- 併發程式設計系列之Lock鎖可重入性與公平性程式設計