1. 程式人生 > >深入研究 Java Synchronize 和 Lock 的區別與用法

深入研究 Java Synchronize 和 Lock 的區別與用法

在分散式開發中,鎖是執行緒控制的重要途徑。Java為此也提供了2種鎖機制,synchronized和lock。做為Java愛好者,自然少不了對比一下這2種機制,也能從中學到些分散式開發需要注意的地方。
 
我們先從最簡單的入手,逐步分析這2種的區別。
 
一、synchronized和lock的用法區別
 
synchronized:在需要同步的物件中加入此控制,synchronized可以加在方法上,也可以加在特定程式碼塊中,括號中表示需要鎖的物件。
 
lock:需要顯示指定起始位置和終止位置。一般使用ReentrantLock類做為鎖,多個執行緒中必須要使用一個ReentrantLock類做為物件才能保證鎖的生效。且在加鎖和解鎖處需要通過lock()和unlock()顯示指出。所以一般會在finally塊中寫unlock()以防死鎖。
 
用法區別比較簡單,這裡不贅述了,如果不懂的可以看看Java基本語法。
 
二、synchronized和lock效能區別


 
synchronized是託管給JVM執行的,而lock是java寫的控制鎖的程式碼。在Java1.5中,synchronize是效能低效的。因為這是一個重量級操作,需要呼叫操作介面,導致有可能加鎖消耗的系統時間比加鎖以外的操作還多。相比之下使用Java提供的Lock物件,效能更高一些。但是到了Java1.6,發生了變化。synchronize在語義上很清晰,可以進行很多優化,有適應自旋,鎖消除,鎖粗化,輕量級鎖,偏向鎖等等。導致在Java1.6上synchronize的效能並不比Lock差。官方也表示,他們也更支援synchronize,在未來的版本中還有優化餘地。
 
說到這裡,還是想提一下這2中機制的具體區別。據我所知,synchronized原始採用的是CPU悲觀鎖機制,即執行緒獲得的是獨佔鎖。獨佔鎖意味著其他執行緒只能依靠阻塞來等待執行緒釋放鎖。而在CPU轉換執行緒阻塞時會引起執行緒上下文切換,當有很多執行緒競爭鎖的時候,會引起CPU頻繁的上下文切換導致效率很低。
 
而Lock用的是樂觀鎖方式。所謂樂觀鎖就是,每次不加鎖而是假設沒有衝突而去完成某項操作,如果因為衝突失敗就重試,直到成功為止。樂觀鎖實現的機制就是CAS操作(Compare and Swap)。我們可以進一步研究ReentrantLock的原始碼,會發現其中比較重要的獲得鎖的一個方法是compareAndSetState。這裡其實就是呼叫的CPU提供的特殊指令。
 
現代的CPU提供了指令,可以自動更新共享資料,而且能夠檢測到其他執行緒的干擾,而 compareAndSet() 就用這些代替了鎖定。這個演算法稱作非阻塞演算法,意思是一個執行緒的失敗或者掛起不應該影響其他執行緒的失敗或掛起的演算法。
 
我也只是瞭解到這一步,具體到CPU的演算法如果感興趣的讀者還可以在查閱下,如果有更好的解釋也可以給我留言,我也學習下。
 
三、synchronized和lock用途區別

 
synchronized原語和ReentrantLock在一般情況下沒有什麼區別,但是在非常複雜的同步應用中,請考慮使用ReentrantLock,特別是遇到下面2種需求的時候。
 
1.某個執行緒在等待一個鎖的控制權的這段時間需要中斷
2.需要分開處理一些wait-notify,ReentrantLock裡面的Condition應用,能夠控制notify哪個執行緒
3.具有公平鎖功能,每個到來的執行緒都將排隊等候
 
下面細細道來……
 
先說第一種情況,ReentrantLock的lock機制有2種,忽略中斷鎖和響應中斷鎖,這給我們帶來了很大的靈活性。比如:如果A、B2個執行緒去競爭鎖,A執行緒得到了鎖,B執行緒等待,但是A執行緒這個時候實在有太多事情要處理,就是一直不返回,B執行緒可能就會等不及了,想中斷自己,不再等待這個鎖了,轉而處理其他事情。這個時候ReentrantLock就提供了2種機制,第一,B執行緒中斷自己(或者別的執行緒中斷它),但是ReentrantLock不去響應,繼續讓B執行緒等待,你再怎麼中斷,我全當耳邊風(synchronized原語就是如此);第二,B執行緒中斷自己(或者別的執行緒中斷它),ReentrantLock處理了這個中斷,並且不再等待這個鎖的到來,完全放棄。(如果你沒有了解java的中斷機制,請參考下相關資料,再回頭看這篇文章,80%的人根本沒有真正理解什麼是java的中斷,呵呵)
 
這裡來做個試驗,首先搞一個Buffer類,它有讀操作和寫操作,為了不讀到髒資料,寫和讀都需要加鎖,我們先用synchronized原語來加鎖,如下:

檢視原始碼列印幫助
1public class Buffer {   
2
3private Object lock;   
4
5public Buffer() {
6lock = this;
7}   
8
9public void write() {
10synchronized (lock) {
11long startTime = System.currentTimeMillis();
12System.out.println("開始往這個buff寫入資料…");
13for (;;)// 模擬要處理很長時間
14{
15if (System.currentTimeMillis()
16- startTime > Integer.MAX_VALUE)
17break;
18}
19System.out.println("終於寫完了");
20}
21}   
22
23public void read() {
24synchronized (lock) {
25System.out.println("從這個buff讀資料");
26}
27}
28}

接著,我們來定義2個執行緒,一個執行緒去寫,一個執行緒去讀。

1public class Writer extends Thread {   
2

相關推薦

深入研究 Java Synchronize Lock區別用法

在分散式開發中,鎖是執行緒控制的重要途徑。Java為此也提供了2種鎖機制,synchronized和lock。做為Java愛好者,自然少不了對比一下這2種機制,也能從中學到些分散式開發需要注意的地方。 我們先從最簡單的入手,逐步分析這2種的區別。 一、synchronized和lock的用法區別 synchr

【Spark系列2】reduceByKeygroupByKey區別用法

在spark中,我們知道一切的操作都是基於RDD的。在使用中,RDD有一種非常特殊也是非常實用的format——pair RDD,即RDD的每一行是(key, value)的格式。這種格式很像Python的字典型別,便於針對key進行一些處理。 針對pair RDD這樣的

reduceByKeygroupByKey區別用法

轉自:https://blog.csdn.net/zongzhiyuan/article/details/49965021在spark中,我們知道一切的操作都是基於RDD的。在使用中,RDD有一種非常特殊也是非常實用的format——pair RDD,即RDD的每一行是(ke

Synchronize Lock區別用法

一、synchronized和lock的用法區別  (1)synchronized(隱式鎖):在需要同步的物件中加入此控制,synchronized可以加在方法上,也可以加在特定程式碼塊中,括號中表示

深入理解Java中的字段屬性的區別

ring rgs name 私有變量 pub tail 博文 們的 方式 轉載出處 http://blog.csdn.net/chenchunlin526/article/details/69939337 1、Java中的屬性和字段有什麽區別? 答:Java中的屬性(p

深入理解Java中的欄位屬性的區別

1、Java中的屬性和欄位有什麼區別?  答:Java中的屬性(property),通常可以理解為get和set方法。 而欄位(field),通常叫做“類成員”,或 "類成員變數”,有時也叫“域”,理解為“資料成員”,用來承載資料的。 這兩個概念是完全不同的。 2、屬性

多執行緒:synchronize、volatile、Lock區別用法

Java多執行緒之記憶體可見性和原子性:Synchronized和Volatile的比較       在說明Java多執行緒記憶體可見性之前,先來簡單瞭解一下Java記憶體模型。     

java之RunnableThread區別實現方法

1、多執行緒中start()和run()方法的區別 1) start: 用start方法來啟動執行緒,真正實現了多執行緒執行,這時無需等待run方法體程式碼執行完畢而直接繼續執行下面的程式碼。通過呼叫Thread類的 start()方法來啟動一個執行緒,這時

Java cookiesession介紹區別

  一、cookie機制和session機制的區別   具體來說cookie機制採用的是在客戶端保持狀態的方案,而session機制採用的是在伺服器端保持狀態的方案。   同時我們也看到,由於才伺服器端保持狀態的方案在客戶端也需要儲存一個標識,所以session   機制可能

Java容器深入研究(jdk 1.8)--- ArrayList總結原始碼分析

結構:public class ArrayList<E> extends AbstractList<E>   implements List<E>, RandomAccess, Cloneable, java.io.Serializabl

synchronizeLock鎖的區別

為什麼java已經通過synchronized關鍵字實現同步訪問了,還需要提供Lock? synchronized的缺陷 前面部落格有提到過釋放物件的鎖有兩種情況: 程式執行完同步程式碼塊會釋放程式碼塊。 程式在執行同步程式碼塊是出現異常,JVM會自動

深入研究java.lang.Object類

下一個 line 版本號 gin bool 獲得 不同 ava 表達 前言:Java的類庫日益龐大。所包括的類和接口也不計其數。但當中有一些非常重要的類和接口,是Java類庫中的核心部分。常見的有String、Object、Class、Collection、Class

SynchronizeReentrantLock區別

目錄介紹 1.Synchronize和ReentrantLock區別 1.1 相似點 1.2 區別 1.3 什麼是執行緒安全問題?如何理解 1.4 執行緒安全需要保證幾個基本特性 2.Synchronize在編譯時如何實現鎖機制 3.Reent

Java中 = += 的區別

1)+:在編譯器將右邊的表示式結果計算出來後,和左邊的變數型別比較精度,如果左邊的變數精度低於右邊的結果的精度,編譯器會顯式的報錯,告訴程式設計師去強制轉型。(所以s1 = s1 + 1出錯)最後將表示式的結果複製到變數所在的記憶體區。 2)+=:編譯器自動隱式直接將+=運算子後面的運算元強制裝

Mybatis中的mapper.xml裡面${} #{}區別用法

Mybatis 的Mapper.xml語句中parameterType向SQL語句傳參有兩種方式:#{}和${} #{}方式能夠很大程度防止sql注入。 $方式無法防止Sql注入。 $方式一般用於傳入資料庫物件,例如傳入表名. 一般能用#的就別用$. #{}表示一個佔

深入研究Java String

開始寫 Java 一年來,一直都是遇到什麼問題再去解決,還沒有主動的深入的去學習過 Java 語言的特性和深入閱讀 JDK 的原始碼。既然決定今後靠 Java吃飯,還是得花些心思在上面,放棄一些打遊戲的時間,系統深入的去學習。 Java String 是 Java

深入研究java.lang.ThreadLocal類

ThreadLocal是什麼呢?其實ThreadLocal並非是一個執行緒的本地實現版本,它並不是一個Thread,而是threadlocalvariable(執行緒區域性變數)。也許把它命名為ThreadLocalVar更加合適。執行緒區域性變數(Threa

深入理解Java型別資訊(Class物件)反射機制

關聯文章: 本篇主要是深入對Java中的Class物件進行分析,這對後續深入理解反射技術非常重要,主要內容如下: 深入理解Class物件 RRTI的概念以及Class物件作用 認識Class物件之前,先來了解一個概念,RTTI(Run-Time

MyBatis中#$的區別PageHelper配置詳解

一.PageHelper配置詳解 二.MyBatis中#和$的區別 #將傳入的資料都當成一個字串,會對自動傳入

NSMutableDictionary NSDictionary的區別用法大全

NSDictionary 初始化新字典,新字典包含otherDic NSDictionary *dic = [NSDictionary dictionaryWithDictionary:otherDic]; 以檔案內容初始化字典 NSDictionary *dic