【问题标题】:Threads - Why a Lock has to be followed by try and finally线程 - 为什么锁必须跟在 try 和 finally
【发布时间】:2011-10-20 11:23:26
【问题描述】:

一个 Lock 后面总是跟着一个 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();
}

【问题讨论】:

标签: java locking thread-safety


【解决方案1】:

万一出现任何问题(抛出异常等),您要确保无论如何都会释放锁。这只是标准做法,尽管在这种情况下可能在技术上是不必要的。

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

        因为 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();
        }
        

        【讨论】:

          【解决方案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();
          }
          

          【讨论】:

            【解决方案6】:

            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 保护,以确保锁是 必要时发布。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2015-12-06
              • 2010-11-12
              • 2013-11-09
              • 1970-01-01
              • 2020-12-15
              • 1970-01-01
              相关资源
              最近更新 更多