CodeQL 文档

持有锁时休眠

ID: java/sleep-with-lock-held
Kind: problem
Security severity: 
Severity: error
Precision: medium
Tags:
   - reliability
   - correctness
   - concurrency
   - external/cwe/cwe-833
Query suites:
   - java-security-and-quality.qls

单击查看 CodeQL 代码库中的查询

调用 Thread.sleep 时持有锁可能会导致性能极差甚至死锁。这是因为 Thread.sleep 不会导致线程释放其锁。

建议

应仅在 synchronized 块之外调用 Thread.sleep。但是,线程让出执行时间给其他线程的更好方法可能是使用以下两种解决方案中的任何一种:

  • java.util.concurrent

  • waitnotifyAll 方法

示例

在以下问题示例中,启动了两个线程 StorageThreadOtherThread。这两个线程都输出一条消息以显示它们已启动,但随后 StorageThread 锁定 counter 并进入休眠状态。该锁阻止 OtherThread 锁定 counter,因此它必须等到 StorageThread 唤醒并解锁 counter 才能继续。

class StorageThread implements Runnable{
    public static Integer counter = 0;
    private static final Object LOCK = new Object();

    public void run() {
        System.out.println("StorageThread started.");
        synchronized(LOCK) {  // "LOCK" is locked just before the thread goes to sleep
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) { ... }
        }
        System.out.println("StorageThread exited.");
    }
}

class OtherThread implements Runnable{
    public void run() {
        System.out.println("OtherThread started.");
        synchronized(StorageThread.LOCK) {
            StorageThread.counter++;
        }
        System.out.println("OtherThread exited.");
    }
}

public class SleepWithLock {
    public static void main(String[] args) {
        new Thread(new StorageThread()).start();
        new Thread(new OtherThread()).start();
    }
}

为了避免这个问题,StorageThread 应该在 synchronized 块之外调用 Thread.sleep,以便释放 counter 锁。

参考文献

  • ©GitHub, Inc.
  • 条款
  • 隐私