2016-10-27 91 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){ 
    ... 
    } 
} 

但随后的使用再一次,我看不出有任何理由,你为什么不使用多个锁实例来实现上述。

相关问题