在使用 idea写代码的时候,突然发现循环中用Thread.sleep(2000)来做延迟一段时间再执行了逻辑的时候,idea会提示probably busy-waiting,

虽然并不影响代码执行,但是在循环中使用Thread.sleep(),确实有可能表现为一种类似于忙等待的形式,尤其是在不断检查某个条件是否满足的情况下。虽然调用Thread.sleep()会让线程进入休眠状态并释放CPU资源,但如果循环的间隔很短且频繁唤醒线程来检查条件,仍然可能导致以下问题:

  1. CPU利用率:即使每次睡眠都会让线程暂停执行一段时间,但过于频繁地唤醒和检查条件可能会浪费CPU资源,尤其是在条件长时间不满足的情况下。

  2. 响应延迟与性能:由于Thread.sleep()的精度依赖于操作系统的调度机制,实际的唤醒时间可能晚于预期,因此这种方法并不适用于对实时性要求较高的场景。

  3. 可读性和维护性:这种编程模式通常不太清晰,不如使用Java并发工具包中的高级同步机制(如条件变量、信号量等)易于理解和维护。

我一时上头就去找了一下怎么解决这种类似忙等待的情况(主要是闲的蛋疼,在实际开发中依然会使用Thread.sleep())

解决办法

使用Condition.awaitNanos(long nanosTimeout)可以有效的解决忙等待的问题

Condition.awaitNanos(long nanosTimeout) Thread.sleep(long millis) 是两种不同的等待机制,它们在等待条件满足时以及如何使用线程和锁方面有一些关键的区别

1. 条件等待 vs. 时间等待

Condition.awaitNanos() 通常用于等待某个条件在指定的时间内变为真,它与锁结合使用,只有在某个条件被满足或者等待超时时才会继续执行。

Thread.sleep() 用于在线程执行的过程中暂停一段时间,不关心条件的满足与否。它不需要锁。

2. 线程状态

Condition.awaitNanos()` 在等待期间会释放锁,因此其他线程可以获得锁并执行其任务。等待的线程会进入等待状态(WAITING)。

Thread.sleep() 不会释放任何锁,线程会进入休眠状态(TIMED_WAITING),但持有的锁仍然被保留,其他线程无法获得锁。

3. 等待精度

Condition.awaitNanos() 使用纳秒级别的等待时间,因此可以提供更精确的等待,但需要注意处理纳秒级别的时间戳。

Thread.sleep() 使用毫秒级别的等待时间,通常用于较粗粒度的等待。

4. 等待条件

Condition.awaitNanos() 可以用于等待某个特定的条件满足,例如等待队列非空或某个资源可用。

Thread.sleep() 通常用于静态的时间间隔等待,而不关心条件是否满足。

总结

Condition.awaitNanos() 适用于需要等待某个条件变为真的情况,并且通常与锁一起使用,以实现更复杂的线程协作。

Thread.sleep() 则适用于简单的时间间隔等待,而不考虑条件是否满足。选择哪种方式取决于您的具体需求和场景。

简单写了个例子:

public static void main(String[] args) {
    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();
    while (true) {
        try {
            lock.lock();
            // 等待2秒,以纳秒为单位
            condition.awaitNanos(2000000000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        //执行循环内的其他逻辑
        System.out.println("Loop iteration after 2 seconds.");
    }
}