多线程(51)忙等待

忙等待(Busy-waiting)是一种同步机制,其中一个进程或线程重复检查某个条件是否满足以便继续执行,而不是进入休眠或阻塞状态。这个条件通常与某种资源或锁的可用性有关。忙等待常常与自旋锁相关联,因为自旋锁就是通过忙等待来检查锁的状态。

为什么要避免忙等待?

  1. CPU资源浪费:忙等待会占用处理器资源进行无意义的循环检查,而不释放处理器去执行其他可能的任务。
  2. 效率低下:特别是在单处理器系统中,忙等待的线程会阻塞其他线程的执行,使得整体系统效率降低。
  3. 响应时间延迟:忙等待会导致线程响应其他任务的延迟,因为它们被固定在检查条件上。

忙等待示例

下面是一个忙等待的简单示例,我们模拟一个场景,某个线程需要等待一个信号(变量signal)被另一个线程设置为true。

java 复制代码
public class BusyWaitExample {

    private static volatile boolean signal = false;

    public static void main(String[] args) throws InterruptedException {
        Thread waitingThread = new Thread(() -> {
            // 忙等待直到 signal 变为 true
            while (!signal) {
                // 忙等待循环体通常为空或者执行非阻塞操作
            }
            System.out.println("Signal received. Waiting thread is proceeding.");
        });

        Thread signallingThread = new Thread(() -> {
            try {
                Thread.sleep(2000); // 模拟计算或其他操作
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            signal = true; // 发送信号
            System.out.println("Signal sent.");
        });

        waitingThread.start();
        signallingThread.start();

        waitingThread.join();
        signallingThread.join();
    }
}

在这个例子中,waitingThread就是在进行忙等待。在signal变量被设置为true之前,它不停地检查signal的值而不做任何实际工作。

如何避免忙等待?

通常,我们可以通过使用某种阻塞机制(如等待/通知机制、信号量、互斥锁等)来避免忙等待。在Java中,可以使用wait()和notify()或notifyAll()方法,或者使用java.util.concurrent包中的工具类如Locks和Conditions。

下面的代码展示了如何使用wait()和notify()来避免忙等待:

java 复制代码
public class WaitNotifyExample {

    private static final Object lock = new Object();
    private static boolean signal = false;

    public static void main(String[] args) throws InterruptedException {
        Thread waitingThread = new Thread(() -> {
            synchronized (lock) {
                while (!signal) {
                    try {
                        lock.wait(); // 阻塞而不是忙等待
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
                System.out.println("Signal received. Waiting thread is proceeding.");
            }
        });

        Thread signallingThread = new Thread(() -> {
            synchronized (lock) {
                try {
                    Thread.sleep(2000); // 模拟计算或其他操作
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                signal = true; // 发送信号
                lock.notify(); // 通知等待的线程
                System.out.println("Signal sent.");
            }
        });

        waitingThread.start();
        signallingThread.start();

        waitingThread.join();
        signallingThread.join();
    }
}

在修改后的例子中,waitingThread将不再忙等待,而是在signal没有被设置之前阻塞在wait()方法上。这样就避免了忙等待,线程在等待信号的时候不会消耗CPU资源。

总之,忙等待虽然在某些低延迟和高性能的场景下适用,但在大多数情况下,它是应该被避免的。通过使用适当的同步工具和方法可以有效提高程序效率,节省系统资源。

相关推荐
噢,我明白了3 小时前
java中唯一键和幂等键的应用
java·后端
GreenTea3 小时前
我把 Agent 的 while 循环拆掉了:一种你可能没想到的 Agent 架构
前端·后端·架构
考虑考虑3 小时前
synchronized字符串常量
java·后端·java ee
颜进强4 小时前
16 · NestJS LifecycleEvents 生命周期事件:五个钩子、三条边界,和 rag-server 的优雅停机
前端·后端·ai编程
GetcharZp5 小时前
定位不再一个个吐坐标:英伟达 LocateAnything 上手全攻略
后端
郑州光合科技余经理6 小时前
同城电商系统:库存变更怎么同步到订单
java·开发语言·前端·后端·uni-app·php·ai编程
我叫黑大帅6 小时前
Go日志库工程选型与逃逸分析评测报告
后端·面试·go
IT_陈寒8 小时前
JavaScript闭包的这个坑,我居然今天才爬出来
前端·人工智能·后端
Thneonl8 小时前
消息队列选型决策树:RabbitMQ vs Kafka vs Redis Streams
后端·架构