出自:https://blog.csdn.net/u011519624/article/details/61628611
synchronized妓忍、lock虏两,都可以稱呼為:對象鎖、對象監(jiān)視器世剖、同步監(jiān)視器定罢。
它們的作用應(yīng)該是相同的,差別未知旁瘫。
鎖是為多線程服務(wù)的祖凫,目的是實現(xiàn)多線程環(huán)境下同步排隊訪問某些指定代碼,最終目的是多線程下的數(shù)據(jù)安全酬凳。它們在單線程環(huán)境下沒有意義
一惠况、Synchronized
Synchronized是Java的關(guān)鍵字,當(dāng)它用來修飾一個方法或一個代碼塊時宁仔,能夠保證在同一時刻最多只有一個線程執(zhí)行該代碼稠屠。因為當(dāng)調(diào)用Synchronized修飾的代碼時,并不需要顯示的加鎖和解鎖的過程翎苫,所以稱之為隱式鎖权埠。
Sychronized的用法:
1、同步方法體煎谍,在方法聲明中使用攘蔽,如下:
public synchronized void method(){
? ? ? ? //方法體
}
2、同步代碼塊呐粘,修飾在代碼塊外層秩彤,指定加鎖對象,如下:
public void method2(){
? ? synchronized (this) {
? ? //一次只能有一個線程進入?
? ? }
}
上述synchronized(this)指定了當(dāng)前對象本身作為鎖事哭,和它持有相同對象鎖的地方將產(chǎn)生互斥性。當(dāng)一個線程訪問method2的同步代碼塊時瓜富,它就獲得了這個object的對象鎖鳍咱。其他的線程對該object所有同步代碼部分的訪問都被暫時的阻塞。
sychronized的不同寫法對程序響應(yīng)的快慢和對資源高并發(fā)的利用程度不一樣与柑,性能和執(zhí)行效率從差到優(yōu)排序如下:
差? ? ? ? ? ? ? ? ? ? ?較差? ? ? ? ? ? ? ? ? ?優(yōu)
同步方法體 < 同步代碼塊 < 小對象鎖同步代碼塊
小對象鎖同步代碼塊指鎖的對象的所占內(nèi)存小谤辜,因為鎖是對象蓄坏,加鎖和解鎖都需要釋放資源,那肯定是鎖對象越小越好丑念,實際應(yīng)用如下:
private byte[] lock = new byte[1];
public void method3(){
? ? synchronized (lock) {
? ? ? ? //一次只能有一個線程進入?
? ? }
}
二涡戳、Lock
Lock是一個接口,提供了無條件的脯倚、可輪詢的渔彰、定時的、可中斷的鎖獲取操作推正,所有的加鎖和解鎖操作方法都是顯示的恍涂,因而稱為顯示鎖。
下面針對Lock的幾個實現(xiàn)類ReentrantLock植榕、ReentrantReadWriteLock.ReadLock和ReentrantReadWriteLock.WriteLock解析再沧。
ReentrantLock(可重入鎖),是一個互斥的同步器尊残,用ReentrantLock實現(xiàn)同步機制比sychronized實現(xiàn)更具伸縮性炒瘸。使用如下:
private final ReentrantLock lock = new ReentrantLock();
? ? public void m(){
? ? ? ? lock.lock();//獲得鎖
? ? ? ? try{
? ? ? ? ? ? //方法體
? ? ? ? }finally{
? ? ? ? ? ? lock.unlock();//務(wù)必釋放鎖
? ? ? ? }
? ? }
注意:在使用ReentrantLock時,一定要有釋放鎖的操作寝衫。
三顷扩、ReadWriteLock(讀寫鎖)
是一個接口,提供了readLock和writeLock兩種鎖的操作竞端,也就是說一個資源能夠被多個讀線程訪問屎即,或者被一個寫線程訪問,但是不能同時存在讀寫線程事富。
(非原文:大概是讀鎖可以多線程異步訪問技俐。但是寫鎖必須同步。讀寫鎖也必須同步排隊訪問)
也就是說讀寫鎖應(yīng)用的場景是一個資源被大量讀取操作统台,而只有少量的寫操作雕擂。我們先看其源碼:
public interface ReadWriteLock {
? ? Lock readLock();
? ? Lock writeLock();
}
從源碼看出,ReadWriteLock借助Lock來實現(xiàn)讀寫兩個鎖并存贱勃、互斥的機制井赌。每次讀取共享數(shù)據(jù)就需要讀取鎖,需要修改共享數(shù)據(jù)就需要寫入鎖贵扰。
讀寫鎖的機制:
1仇穗、讀-讀不互斥,讀線程可以并發(fā)執(zhí)行戚绕;
2纹坐、讀-寫互斥,有寫線程時舞丛,讀線程會堵塞耘子;
3果漾、寫-寫互斥,寫線程都是互斥的谷誓。
使用方法:
//創(chuàng)建ReentrantReadWriteLock對象
private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
? ? //抽取讀寫鎖
? ? private Lock readLock = rwl.readLock();
? ? private Lock writeLock = rwl.writeLock();
? ? public int getXXX(){
? ? ? ? readLock.lock();
? ? ? ? try{
? ? ? ? ? ? //執(zhí)行操作
? ? ? ? }finally{
? ? ? ? ? ? readLock.unlock();
? ? ? ? }
? ? }
? ? public void setXXX(){
? ? ? ? writeLock.lock();
? ? ? ? try{
? ? ? ? ? ? //執(zhí)行操作
? ? ? ? }finally{
? ? ? ? ? ? writeLock.unlock();
? ? ? ? }
? ? }
ReentrantReadWriteLock和ReentrantLock的比較:
ReentrantReadWriteLock是對ReentrantLock的復(fù)雜擴展绒障,能適合更加復(fù)雜的業(yè)務(wù)場景,ReentrantReadWriteLock可以實現(xiàn)一個方法中讀寫分離的鎖的機制捍歪。而ReentrantLock只是加鎖解鎖一種機制户辱。
最后對比Synchronized、ReentrantLock和ReentrantReadWriteLock:
Synchronized是在JVM層面上實現(xiàn)的费封,無需顯示的加解鎖焕妙,而ReentrantLock和ReentrantReadWriteLock需顯示的加解鎖,一定要保證鎖資源被釋放弓摘;
Synchronized是針對一個對象的焚鹊,而ReentrantLock和ReentrantReadWriteLock是代碼塊層面的鎖定;
ReentrantReadWriteLock引入了讀寫和并發(fā)機制韧献,可以實現(xiàn)更復(fù)雜的鎖機制末患,并發(fā)性相對于ReentrantLock和Synchronized更高。
非原文:疑問
1锤窑、synchronized網(wǎng)上有多種稱呼:對象鎖璧针、對象監(jiān)視器、同步監(jiān)視器渊啰。能理解怎么用就行探橱。
無論怎么稱呼,它都是為多線程服務(wù)的绘证,目的是實現(xiàn)多線程環(huán)境下同步訪問某些方法晨缴,最終目的是多線程下數(shù)據(jù)安全寓涨。單線程下沒有意義
synchronized監(jiān)視的是整個對象铆帽,所以(Java設(shè)計規(guī)定)當(dāng)一個線程正在訪問同步方法压真、或同步代碼塊時,
其他線程不能進入該對象的任意一個同步方法魏宽、或者同步代碼塊腐泻。
(非同步方法、非同步代碼塊队询,沒有限制)
那么ReentrantLock也是這么設(shè)計的嗎派桩?
代碼測試結(jié)果:
(1)、當(dāng)lock實例化為一個成員字段時蚌斩,監(jiān)視的也是一個對象(當(dāng)前所在類的當(dāng)前對象)
和synchronized沒有差別铆惑。
(2)、如果lock實例化為局部變量,多線程訪問該方法時鸭津,不能同步訪問了
lock使用方式之一:lock對象只能作為成員字段使用。
synchronized代碼塊肠缨,分析多線程環(huán)境下怎么執(zhí)行時逆趋,可以看作是獨立的一個同步方法
2、synchronized晒奕、ReentrantLock都是重入鎖
重入鎖大概意思舉例:
public synchronized void get1(
System.out.print(1); // start
get2();? // 嵌套訪問另一個同步方法get2()
System.out.print(2); // end
){}
public synchronized void get2(){}
一個線程訪問get1()時闻书,代碼由上而下順序執(zhí)行,start? ? get2()? ? ?end,
可重入脑慧,可以理解為兩個方法魄眉,兩把鎖,先進入get1()的鎖闷袒,再進入 get2()的鎖坑律,最后重新進入? get1()的鎖。
Java這樣設(shè)計囊骤,同步方法嵌套訪問不會發(fā)生死鎖晃择?重入的概念用來理解這種設(shè)計,知道怎么用就行
3也物、public static synchronized void get3(){}
這個同步方法宫屠,監(jiān)視的是該類的class對象。例如:Test.class
那么滑蚯,監(jiān)視對象浪蹂、監(jiān)視class對象,怎么表達(dá)告材。坤次。。應(yīng)該是兩種不相干的監(jiān)視行為创葡。
代碼測試結(jié)果:是兩種不相干的監(jiān)視行為浙踢。(對象、class對象灿渴,不是同一個對象)