fbe*_*oit 4 java java.util.concurrent
具有ReentrantLock和lock()/ unlock()的普通模式如下所示:
lck.lock();
try {
// ...
}
finally {
lck.unlock();
}
Run Code Online (Sandbox Code Playgroud)
可以重构为
synchronized(lck) {
// ...
}
Run Code Online (Sandbox Code Playgroud)
?
又为什么呢
这些是不同的东西。synchronized内置于语言中,可与任何对象一起使用。它所做的就是锁定其固有的锁定。每个对象都有一个。由于它是一种内置机制,因此您不需要try-finally块-当控件退出该synchronized块时,锁总是解锁的。因此,只要您的代码实际退出该块,锁就会被解锁。
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();
Run Code Online (Sandbox Code Playgroud)
它死锁是因为两个线程以不同的顺序锁定了两个不同的事物。
当然感觉就像在ReentrantLock做一样的事情synchronized。它的工作原理类似,但synchronized更方便,功能也更差。因此,除非您需要的任何功能(ReentrantLock例如可中断的锁定尝试或锁定超时),否则应坚持使用synchronized以重入锁定为目的,并为此使用任何对象。简单private final Object lock = new Object()就可以了。请注意,这final将防止在您暂时更改该对象时可能造成的混淆。如果您省略某些IDE,则会发出警告final。