Java Lock Mechanism
1. Java Lock Mechanism
Before Java 5.0, synchronized是唯一的选择,Java5.0的concurrent包提供了新的Lock机制。
Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set (wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。
2.
对象的锁
所有对象都自动含有单一的锁。
JVM负责跟踪对象被加锁的次数。如果一个对象被解锁,其计数变为0。在任务(线程)第一次给对象加锁的时候,计数变为1。每当这个相同线程在此对象上获得锁时,计数会递增。
只有首先获得锁的线程才能继续获取该对象上的多个锁。
每当线程离开一个synchronized方法,计数递减,当计数为0的时候,锁被完全释放,此时别的线程就可以使用此资源。
3. synchronized
因为synchronized
锁是加在对象上的,
所以下面的代码是等效的。
public class ThreadSafe {
public synchronized void method1 () {
//access the resource protected by this lock
}
}
public class ThreadSafe {
public void method1 () {
synchronized (this) {
//access the resource protected by this lock
}
}
}
4. synchronized and Lock
4.1
同步到单一对象
public class ThreadSafe {
public void method1 () {
synchronized (this) {
//access the resource protected by this lock
}
}
public void method2 () {
synchronized (this) {
//access the resource protected by this lock
}
}
}
由于同步在同一的对象上(this),所以method1和method2是互斥的。
采用Lock也能实现同样的效果:
public class ThreadSafe {
private Lock lock = new ReentrantLock();
public void method1 () {
lock.lock();
try{
//access the resource protected by this lock
}
finally {
lock.unlock();
}
}
public void method2 () {
lock.lock();
try{
//access the resource protected by this lock
}
finally {
lock.unlock();
}
}
}
由于同步在同一个lock对象上,所以method1和method2是互斥的。
4.2
同步到多个对象
public class ThreadSafe {
private Object lock1 = new Object();
private Object lock2 = new Object();
public void method1 () {
synchronized (lock1) {
//access the resource protected by this lock
}
}
public void method2 () {
synchronized (lock2) {
//access the resource protected by this lock
}
}
}
由于同步不同的对象lock1和lock2上,所以method1和method2不是互斥的。
采用Lock也能实现同样的效果:
public class ThreadSafe {
private Lock lock1 = new ReentrantLock();
private Lock lock2 = new ReentrantLock();
public void method1 () {
lock1.lock();
try{
//access the resource protected by this lock
}
finally {
lock1.unlock();
}
}
public void method2 () {
lock2.lock();
try{
//access the resource protected by this lock
}
finally {
lock2.unlock();
}
}
}
由于同步不同的对象lock1和lock2上,所以method1和method2不是互斥的。
5. NbiLocalQueue
public void send(NbiMessage message) throws NbiException {
try {
msgReceiverLock.lock();
nbiQueue.add(message);
msgReceiverLock.signal();
} finally {
msgReceiverLock.unlock();
}
}
msgReceiverLock封装了一个ReentrantLock,所以基本上来说,这个实现和synchronized方式实现没有本质的区别。
当然Java5.0提供的Lock机制也有自身的一些优势,请参考下面的章节和JDK的帮助文档。
6. Condition
和
Object
监视器方法
6.1 Object
监视器方法实现
class ObjectBoundedBuffer {
final private Object lock = new Object();
final Object[] items = new Object[100];
int putptr, takeptr, count;
public void put(Object x){
synchronized (lock) {
while (count == items.length)
lock.wait();
items[putptr] = x;
if (++putptr == items.length) putptr = 0;
++count;
lock.notify();
}
}
public Object take() {
synchronized (lock){
while (count == 0 )
lock.wait();
Object x = items[takeptr];
if (++takeptr == items.length) takeptr = 0;
--count;
lock.notify();
return x;
}
}
}
6.2 Condition
实现
class ConditionBoundedBuffer {
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
final Object[] items = new Object[100];
int putptr, takeptr, count;
public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length)
notFull.await();
items[putptr] = x;
if (++putptr == items.length) putptr = 0;
++count;
notEmpty.signal();
} finally {
lock.unlock();
}
}
public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0)
notEmpty.await();
Object x = items[takeptr];
if (++takeptr == items.length) takeptr = 0;
--count;
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
}
7. Lock
的优势
据说Lock比synchronized
有更好的性能优势。
Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。此实现允许更灵活的结构,可以具有差别很大的属性,可以支持多个相关的 Condition 对象。
Lock 接口的实现允许锁定在不同的作用范围内获取和释放,并允许以任何顺序获取和释放多个锁定。
Lock 实现提供了使用 synchronized 方法和语句所没有的其他功能,包括提供了一个非块结构的获取锁定尝试 (tryLock())、一个获取可中断锁定的尝试 (lockInterruptibly()) 和一个获取超时失效锁定的尝试 (tryLock(long, TimeUnit))。
Lock 类还可以提供与隐式监视器锁定完全不同的行为和语义,如保证排序、非重入用法或死锁检测。如果某个实现提供了这样特殊的语义,则该实现必须对这些语义加以记录。