1. 程式人生 > >基礎概念:隱式鎖 Synchronized 與顯示鎖 Lock的用法和簡單對比

基礎概念:隱式鎖 Synchronized 與顯示鎖 Lock的用法和簡單對比

轉自:https://blog.csdn.net/u011519624/article/details/61628611
Synchronized

Synchronized是Java的關鍵字,當它用來修飾一個方法或一個程式碼塊時,能夠保證在同一時刻最多隻有一個執行緒執行該程式碼。因為當呼叫Synchronized修飾的程式碼時,並不需要顯示的加鎖和解鎖的過程,所以稱之為隱式鎖。

Sychronized的用法:

1、同步方法體,在方法宣告中使用,如下:

public synchronized void method(){
        //方法體
}

2、同步程式碼塊,修飾在程式碼塊外層,指定加鎖物件,如下:

public void method2(){
    synchronized (this) {
    //一次只能有一個執行緒進入   
    }
}

上述synchronized(this)指定了當前物件本身作為鎖,和它持有相同物件鎖的地方將產生互斥性。當一個執行緒訪問method2的同步程式碼塊時,它就獲得了這個object的物件鎖。其他的執行緒對該object所有同步程式碼部分的訪問都被暫時的阻塞。

sychronized的不同寫法對程式響應的快慢和對資源高併發的利用程度不一樣,效能和執行效率從差到優排序如下:

同步方法體 < 同步程式碼塊 < 小物件鎖同步程式碼塊

小物件鎖同步程式碼塊指鎖的物件的所佔記憶體小,因為鎖是物件,加鎖和解鎖都需要釋放資源,那肯定是鎖物件越小越好,實際應用如下:

private byte[] lock = new byte[1];
public void method3(){
    synchronized (lock) {
        //一次只能有一個執行緒進入   
    }
}

Lock

Lock是一個介面,提供了無條件的、可輪詢的、定時的、可中斷的鎖獲取操作,所有的加鎖和解鎖操作方法都是顯示的,因而稱為顯示鎖。
下面針對Lock的幾個實現類ReentrantLock、ReentrantReadWriteLock.ReadLock和ReentrantReadWriteLock.WriteLock解析。

ReentrantLock(可重入鎖),是一個互斥的同步器,用ReentrantLock實現同步機制比sychronized實現更具伸縮性。使用如下:

private final ReentrantLock lock = new ReentrantLock();
    public void m(){
        lock.lock();//獲得鎖
        try{
            //方法體
        }finally{
            lock.unlock();//務必釋放鎖
        }
    }

注意:在使用ReentrantLock時,一定要有釋放鎖的操作。

ReadWriteLock(讀寫鎖)是一個介面,提供了readLock和writeLock兩種鎖的操作,也就是說一個資源能夠被多個讀執行緒訪問,或者被一個寫執行緒訪問,但是不能同時存在讀寫執行緒。也就是說讀寫鎖應用的場景是一個資源被大量讀取操作,而只有少量的寫操作。我們先看其原始碼:

public interface ReadWriteLock {
    Lock readLock();
    Lock writeLock();
}

從原始碼看出,ReadWriteLock藉助Lock來實現讀寫兩個鎖並存、互斥的機制。每次讀取共享資料就需要讀取鎖,需要修改共享資料就需要寫入鎖。

讀寫鎖的機制:
1、讀-讀不互斥,讀執行緒可以併發執行;
2、讀-寫互斥,有寫執行緒時,讀執行緒會堵塞;
3、寫-寫互斥,寫執行緒都是互斥的。

使用方法:

//建立ReentrantReadWriteLock物件
    private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

    //抽取讀寫鎖
    private Lock readLock = rwl.readLock();
    private Lock writeLock = rwl.writeLock();
    public int getXXX(){
        readLock.lock();
        try{
            //執行操作
        }finally{
            readLock.unlock();
        }
    }
    public void setXXX(){
        writeLock.lock();
        try{
            //執行操作
        }finally{
            writeLock.unlock();
        }
    }

ReentrantReadWriteLock和ReentrantLock的比較:
ReentrantReadWriteLock是對ReentrantLock的複雜擴充套件,能適合更加複雜的業務場景,ReentrantReadWriteLock可以實現一個方法中讀寫分離的鎖的機制。而ReentrantLock只是加鎖解鎖一種機制。

最後對比Synchronized、ReentrantLock和ReentrantReadWriteLock:

Synchronized是在JVM層面上實現的,無需顯示的加解鎖,而ReentrantLock和ReentrantReadWriteLock需顯示的加解鎖,一定要保證鎖資源被釋放;
Synchronized是針對一個物件的,而ReentrantLock和ReentrantReadWriteLock是程式碼塊層面的鎖定;
ReentrantReadWriteLock引入了讀寫和併發機制,可以實現更復雜的鎖機制,併發性相對於ReentrantLock和Synchronized更高。