正常模式用的ReentrantLock和鎖()/解鎖()是這樣的:是否同步鎖定一個Reentrantlock,或只有它的對象?
lck.lock();
try {
// ...
}
finally {
lck.unlock();
}
可以這樣重構爲
synchronized(lck) {
// ...
}
?
爲什麼?
正常模式用的ReentrantLock和鎖()/解鎖()是這樣的:是否同步鎖定一個Reentrantlock,或只有它的對象?
lck.lock();
try {
// ...
}
finally {
lck.unlock();
}
可以這樣重構爲
synchronized(lck) {
// ...
}
?
爲什麼?
這些是不同的東西。內置於語言中,可用於任何對象。它所做的是鎖定其固有的鎖定。每一個物體都有一個。由於它是一種內置機制,因此不需要try-finally
塊 - 當控制器退出塊時,鎖始終處於解鎖狀態。所以只要你的代碼實際上退出該塊,鎖就會被解鎖。
ReentrantLock
是一個特殊的類。它鎖定了一些特殊的內部對象,這可能是特定於實現的。它確實不是鎖定其固有鎖定。當然,你也可以鎖定那一個,但它通常沒有任何意義。這段代碼幾乎肯定會死鎖,例如:
final ReentrantLock lock = new ReentrantLock();
new Thread(() -> {
lock.lock();
try {
System.out.println("Thread 1 locked the lock");
try { Thread.sleep(100); } catch (Exception ex) {}
synchronized (lock) {
System.out.println("Thread 1 locked lock's intrinsic lock");
}
} finally {
lock.unlock();
}
}).start();
new Thread(() -> {
synchronized (lock) {
System.out.println("Thread 2 locked lock's intrinsic lock");
try { Thread.sleep(200); } catch (Exception ex) {}
lock.lock();
try {
System.out.println("Thread 2 locked the lock");
} finally {
lock.unlock();
}
}
}).start();
它鎖死,因爲兩個線程鎖定不同的順序兩回事。
它當然感覺像ReentrantLock
幾乎與一樣。它的工作原理類似,但既方便又不太強大。所以除非你需要ReentrantLock
的任何功能,比如可中斷的鎖定嘗試或鎖定超時,你應該堅持使用來實現可重入鎖定,並且使用任何對象(簡單的new Object()
都可以)。
我假設您知道分別由Lock
和分別提供的顯式和隱式鎖定的差異。
我相信你正在尋找一個理由說什麼是錯的,使用內部實現塊Lock
接口的類的實例,如synchronized(lock)
。
它可以重構嗎? 是的。
但是你應該這樣做嗎? 不適用於實現Lock類接口的類實例
爲什麼? - 好的。
這是所有權利,如果你只是用lock
只有內但是你離開的可能性,其他開發者濫用代碼例如說如果某人明天嘗試在synchronized(lock)
之內調用Lock
方法,如下所示。
Lock lock = new ReentrantLock();
synchronized(lock){ //You write this
// lock.lock(); // I am not taking a lock here
System.out.println("See emily play");
...
...
... // after 100 lines of code
//callAnotherMethod(lock); //Someone else does this
lock.unlock(); //Someone else does this
}
上面的代碼是可怕的,但給你一個例子,在上面的例子,如果你不叫lock()
,那麼你最終IllegalMonitorStateException
。如果你打電話(取消以上註釋)lock.lock()
它沒有區別。
更不用說callAnotherMethod(lock)
您正在傳遞鎖定實例以及它可以引入哪些意外行爲。
請記住,就是這樣一個例子。底線,如果任何機會都能正確工作,那只是在浪費資源和時間,並沒有任何優勢/目的。更重要的是,它不能保證它在將來不會引入迴歸。如果有任何這樣的迴歸,由於濫用概念,最終可能會浪費大量時間。
軟件始終採用開放式原則設計。你會寫的代碼會非常清楚地違反它。
在情況下,如果你想使用細粒度鎖使用那麼你可以讓下面
Object obj1 = new Object();
Object obj2 = new Object();
public void doSomething(){
synchronised(obj1){
...
}
}
public void doSomethingMore(){
synchronised(obj2){
...
}
}
但隨後的使用再一次,我看不出有任何理由,你爲什麼不使用多個鎖實例來實現上述。
不,它不能。他們是不同的機制。 – EJP
可能重複的[synchronized和re-entrant lock之間的區別?](http://stackoverflow.com/questions/9072422/difference-between-synchronized-and-rentrant-lock) – jalopaba
不可以。鎖之後的主要思想是爲了避免粗粒度同步塊 - IOW,它是對同步塊的改進。如果你使用'synchronized(lck)',你基本上像對待任何其他對象一樣對待lck,而不是真正使用鎖定概念。 – Vasan