2016-10-27 100 views
1

正常模式用的ReentrantLock和鎖()/解鎖()是這樣的:是否同步鎖定一個Reentrantlock,或只有它的對象?

lck.lock(); 
try { 
    // ... 
} 
finally { 
    lck.unlock(); 
} 

可以這樣重構爲

synchronized(lck) { 
    // ... 
} 


爲什麼?

+0

不,它不能。他們是不同的機制。 – EJP

+0

可能重複的[synchronized和re-entrant lock之間的區別?](http://stackoverflow.com/questions/9072422/difference-between-synchronized-and-rentrant-lock) – jalopaba

+0

不可以。鎖之後的主要思想是爲了避免粗粒度同步塊 - IOW,它是對同步塊的改進。如果你使用'synchronized(lck)',你基本上像對待任何其他對象一樣對待lck,而不是真正使用鎖定概念。 – Vasan

回答

3

這些是不同的東西。​​內置於語言中,可用於任何對象。它所做的是鎖定其固有的鎖定。每一個物體都有一個。由於它是一種內置機制,因此不需要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()都可以)。

1

我假設您知道分別由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){ 
    ... 
    } 
} 

但隨後的使用再一次,我看不出有任何理由,你爲什麼不使用多個鎖實例來實現上述。

相關問題