线程 - 为什么锁定必须遵循try和finally

时间:2011-08-05 00:13:45

标签: java locking thread-safety

一个锁总是后跟一个try / finally块,为什么?

ReentrantReadWriteLock readWriteLockBitmap = new ReentrantReadWriteLock();
Lock read = readWriteLockBitmap.readLock();
Lock write = readWriteLockBitmap.writeLock();
int shared = 0;

public void function1(){
    read.lock();
    try{
        //reading shared int
    }
    finally{
        read.unlock();
    }
}

public void function 2(){
    write.lock();
    try{
        //modify shared int
    }
    finally{
        write.unlock();
    }
}

为什么要使用此try / finally块而不是简单地编写代码如下:

ReentrantReadWriteLock readWriteLockBitmap = new ReentrantReadWriteLock();
Lock read = readWriteLockBitmap.readLock();
Lock write = readWriteLockBitmap.writeLock();
int shared = 0;

public void function1(){
    read.lock();
    //reading shared int
    read.unlock();
}

public void function 2(){
    write.lock();
    //modify shared int
    write.unlock();
}

6 个答案:

答案 0 :(得分:10)

因为try / finally块是保证一段代码在另一段完成后执行的唯一方法。

你问为什么不这样做:

public void function1(){
    read.lock();
    this.getSharedInt();
    read.unlock();
}

this.getSharedInt()抛出异常时会发生什么?然后你的read.unlock()行不会被执行,导致程序死锁。当然,它可能100%认证不会立即抛出异常 ,但是当您重构将共享int存储在文件或数据库中时会发生什么?

最后,不要忘记try / finally也会导致错误,运行时几乎可以在程序的任何一行抛出错误,即使函数保证不会抛出任何异常。

请注意,此代码也可以使用,但它会吞下异常。使用finally代替允许异常正常传播,同时在所有条件下仍然可以解锁。

public void function2(){
    read.lock();
    try {
        this.getSharedInt();
    } catch(Throwable t) {}
    read.unlock();
}

答案 1 :(得分:6)

如果出现任何问题(抛出异常等),您无需确定锁定是否已被释放。这只是标准做法,即使在这种情况下在技术上可能是不必要的。

答案 2 :(得分:5)

所以这样的事情不会发生:

private static ReentrantReadWriteLock readWriteLockBitmap = new ReentrantReadWriteLock();
private static Lock read = readWriteLockBitmap.readLock();
private static Lock write = readWriteLockBitmap.writeLock();
private static int shared = 0;

public static void function1() {
    read.lock();
    somethingThatMightThrowAnException();
    read.unlock();
}

private static void somethingThatMightThrowAnException() {
    throw new RuntimeException("I'm a bad man.");
}

public static void function2() {
    write.lock();
    //modify shared int
    write.unlock();
}

public static void main(String[] args) {
    try {
        function1();
    } catch (Exception e) {
        System.out.println("Got an exception, but so what?");
    }
    function2();
}

答案 3 :(得分:3)

问题不在于您需要try块。关键是要确保如果你的应用程序抛出了仍然调用解锁的任何类型的异常。否则,锁将保持锁定状态。

答案 4 :(得分:2)

为了确保无论发生什么,即使抛出异常,您仍然会在离开方法之前解锁锁定的流。

答案 5 :(得分:0)

http://www.google.co.uk/#sclient=psy&hl=en&q=java+Why+a+Lock+has+to+be+followed+by+try+and+finally+%3F

首先点击的是:http://download.oracle.com/javase/1,5.0/docs/api/java/util/concurrent/locks/Lock.html

引用关键部分:

  

在大多数情况下,应使用以下习语:

 Lock l = ...; 
 l.lock();
 try {
     // access the resource protected by this lock
 } finally {
     l.unlock();
 }  
     

当锁定和解锁发生在不同的范围内时,必须小心   用于确保在保持锁定时执行的所有代码   受try-finally或try-catch保护以确保锁定   必要时发布。