Threads - Почему после блокировки следует попытаться и наконец - PullRequest
6 голосов
/ 05 августа 2011

За блокировкой всегда следует блок 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 ]

10 голосов
/ 05 августа 2011

Поскольку блок 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();
}
6 голосов
/ 05 августа 2011

В случае, если что-то пойдет не так (исключение будет брошено и т. Д.), Вы хотите убедиться, что замок снят, несмотря ни на что. Это просто стандартная практика, хотя в этом случае технически это может оказаться ненужным.

5 голосов
/ 05 августа 2011

Так что такого не бывает:

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 голосов
/ 05 августа 2011

Проблема не в том, что вам нужен блок try.Смысл в том, чтобы убедиться, что если ваше приложение генерирует исключение любого рода, которое все еще называется разблокировкой.В противном случае замок останется заблокированным.

2 голосов
/ 05 августа 2011

Чтобы быть уверенным, что что бы ни случилось, даже если выдается исключение, вы все равно разблокируете заблокированный поток перед выходом из метода.

0 голосов
/ 05 августа 2011

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, чтобы гарантировать, что блокировкаосвобождается при необходимости.

...