多线程(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资源。

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

相关推荐
画个大饼37 分钟前
Go语言实战:快速搭建完整的用户认证系统
开发语言·后端·golang
iuyou️6 小时前
Spring Boot知识点详解
java·spring boot·后端
一弓虽6 小时前
SpringBoot 学习
java·spring boot·后端·学习
姑苏洛言6 小时前
扫码小程序实现仓库进销存管理中遇到的问题 setStorageSync 存储大小限制错误解决方案
前端·后端
光而不耀@lgy7 小时前
C++初登门槛
linux·开发语言·网络·c++·后端
方圆想当图灵7 小时前
由 Mybatis 源码畅谈软件设计(七):SQL “染色” 拦截器实战
后端·mybatis·代码规范
毅航7 小时前
MyBatis 事务管理:一文掌握Mybatis事务管理核心逻辑
java·后端·mybatis
我的golang之路果然有问题8 小时前
速成GO访问sql,个人笔记
经验分享·笔记·后端·sql·golang·go·database
柏油8 小时前
MySql InnoDB 事务实现之 undo log 日志
数据库·后端·mysql
写bug写bug9 小时前
Java Streams 中的7个常见错误
java·后端