天天看點

Java中的鎖synchronized和lock的用法和比較 

一、synchronized和lock的簡單使用

synchronized可以用在方法和代碼塊上,保證被包裹代碼在多線程環境下的資料安全性,synchronized是java語言内置的,lock是jdk提供的一個接口,實作類主要有ReentrantLock、ReadLock、WriteLock,lock在使用的時候通過lock()方法擷取鎖,通過unlock()方法釋放鎖,這是都是程式員手動完成。synchronized和lock都是支援可重入的。

synchronized在用法上簡單,在沒有特殊情況下,盡量使用此方法,而在擷取鎖可以被中斷,逾時擷取鎖,嘗試擷取鎖,讀多寫少用讀寫鎖等情況下,使用lock接口更好。

二、synchronized和lock的公平鎖、非公平鎖以及讀寫鎖

所謂公平鎖和非公平鎖是指在多線程下,是否可以保證先等待的線程擁有優先執行權,如果可以保證,就是公平鎖,不能保證的就是非公平鎖,從效率上來講,非公平鎖的效率更高,因為實作公平鎖,要挂起等待的線程,頻繁挂起和釋放影響了效率。synchronized就是一個非公平鎖,被等待的線程有同樣的機會擷取CPU的執行權,而ReentrantLock同過初始化可以指定使用公平鎖和非公平鎖,如果不指定,預設非公平鎖。

public ReentrantLock() {
    sync = new NonfairSync();
}

public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}
           

synchronized包裹的代碼在多線程下隻能有一個線程去執行,是以我們應該盡量減少包裹的代碼量,隻包裹資料發生變化的代碼即進行寫操作的代碼,否則十分影響效率,而ReadWriteLock接口的實作類ReentrantReadWriteLock讀寫鎖可以實作多個線程進行讀操作,當執行寫操作時,線程阻塞,ReentrantReadWriteLock内部的讀、寫鎖都實作自lock接口。

三、synchronized和lock的等待喚醒機制

synchronized中使用wait()和notify()、notifyAll()方法實作等待喚醒機制,wait()和notify()、notifyAll()都是屬于object對象的方法,在使用lock時,則借助于Condition類的await()和signal()、signalAll()方法來實作,通過lock.newCondition()方法傳回一個Condition對象,使用對象的await、signal方法實作等待喚醒。需要注意的是一個lock可以獲得多個Condition對象,對不同情況擷取不能的Condition對象,在synchronized中我們隻能有一個鎖,即等待和喚醒用的是一樣的鎖,是以在synchronized中要求使用notifyAll(),而不是notify(),否則很容易造成線程阻塞,而使用Condition時推薦使用signal()方法。

繼續閱讀