Sonar问题:不会在所有路径上释放锁定

问题描述

我有类似下面提到的代码。我在finally块中释放了锁定,但sonarqube仍显示“不在所有路径上释放锁定”消息。 我尝试将lock.isHeldByCurrentThread()更改为lock.isLocked(),但还是没有运气。而且我没有在任何其他方法中使用锁。没有线索如何解决这个声纳问题。

class Sample{
    reentrantlock lock = new reentrantlock();

    public Response<T> method(Inputs input){

        try{
            // some logic
            lock.lock();

        }catch(Exceptions e){
            // handle exception
        }finally{
            if(lock.isHeldByCurrentThread()){
                lock.unlock();
            }
        }
    }
}

解决方法

Sonar在这里看到的是您无条件地获取了一个锁,然后仅在某些条件下才释放它。 Sonarqube不能说选择未释放锁的路径的可能性有多大,只是看到它可能会发生。

还请注意,看来您用于检查锁定的这些方法并不适合这种用法。例如ReentrantLock#isHeldByCurrentThread的文档说:

此方法通常用于调试和测试。

这似乎是在警告您应该在此处重新使用它。

该代码似乎正在使用此方法,以便区分在获取锁之前引发异常的情况与已经获取锁的情况之间的区别,因此它可以知道是否需要释放锁。

答案不是要使用哪种方法来测试锁以查看是否已获得锁,而是要修复代码以免出现测试需求。添加另一个try-block,如下所示:

class Sample{
    ReentrantLock lock = new ReentrantLock();

    public Response<T> method(Inputs input){

        try{
            // do whatever needs doing prior to acquiring lock
            lock.lock();
            try {
                // do whatever needs doing with lock held
            } finally {
                // release lock on the way out of inner try block
                lock.unlock();
            }
        } catch (Exception e){
            // handle exception thrown from anywhere within outer or inner try block
        }
    }
}

这样,如果执行进展到获取锁的程度,它将在释放时释放。如果在任何地方抛出异常,它将被捕获,并且锁将被解锁。

TLDR:如果无条件获得锁,则应无条件释放它。