多线程(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包中的工具类如LocksConditions

下面的代码展示了如何使用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资源。

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

相关推荐
星星在线2 小时前
MusicFree:一个「All in One」的个人音乐服务器,让听歌回归简单
前端·后端
IT_陈寒3 小时前
Redis的SETNX并发问题让我加了三天班
前端·人工智能·后端
demo007x3 小时前
Docling 文档转换以及技术架构分析
前端·后端·程序员
袋鱼不重4 小时前
我的神奇同事,AI 用多了居然写了个 Open In Codex
前端·后端·ai编程
用户8356290780514 小时前
使用 Python 操作 Word 内容控件
后端·python
像我这样帅的人丶你还4 小时前
啥? 前端也要会干Java?🛵🛵🛵
后端
Hommy884 小时前
【剪映小助手】添加贴纸接口(Add Sticker)
后端·github·剪映小助手·视频剪辑自动化·剪映api
CaffeinePro5 小时前
FastAPI响应处理:返回值、状态码、响应头与异常标准化与案例解析
后端
HuanYu5 小时前
PageHelper分页的原理
后端
于先生吖5 小时前
SpringBoot对接大模型开发AI命理测算系统:八字排盘与AI解析接口源码全解
人工智能·spring boot·后端