惊群效应是什么?如何避免惊群效应?

Java juc 面试 大约 1680 字

线程惊群

惊群效应(thundering herd)是指多进程(多线程)在同时阻塞等待同一个事件的时候(休眠状态),如果等待的这个事件发生,那么他就会唤醒等待的所有进程(或者线程),但是最终却只能有一个进程(线程)获得这个时间的“控制权”,对该事件进行处理,而其他进程(线程)获取“控制权”失败,只能重新进入休眠状态,这种现象和性能浪费就叫做惊群效应。

性能影响

Linux内核对用户进程(线程)频繁地做无效的调度、上下文切换等使系统性能大打折扣。上下文切换(context switch)过高会导致CPU像个搬运工,频繁地在寄存器和运行队列之间奔波,更多的时间花在了进程(线程)切换,而不是在真正工作的进程(线程)上面。

代码示例

在一段无缓存则请求数据库的代码中,当高并发时只有一个线程能获取到锁,其他线程都休眠1秒,1秒后可能有成千上百个线程从休眠中被唤醒来争夺锁,但也只有一个线程能获取到锁,其他线程又继续休眠等待。

public String getData2(String keywords) throws InterruptedException {
    String data = getDataFromCache(keywords);
    if (data == null) {
        while (!lock.tryLock()) {
            TimeUnit.SECONDS.sleep(1);
        }
        try {
            data = getDataFromCache(keywords);
            if (data == null) {
                data = getDataFromDB(keywords);
                saveToCache(keywords, data);
            }
        } finally {
            lock.unlock();
        }
    }
    return data;
}

退避策略

增加随机策略,每次休眠的时间为一个随机数,避免多个线程同一时间被唤醒。

public String getData3(String keywords) throws InterruptedException {
    String data = getDataFromCache(keywords);
    if (data == null) {
        while (!lock.tryLock()) {
            // 使用随机数,免出现惊群效应,防止相同时间执行大量操作
            long randomSleepTs = ThreadLocalRandom.current().nextLong(1000);
            TimeUnit.MILLISECONDS.sleep(randomSleepTs);
        }
        try {
            data = getDataFromCache(keywords);
            if (data == null) {
                data = getDataFromDB(keywords);
                saveToCache(keywords, data);
            }
        } finally {
            lock.unlock();
        }
    }
    return data;
}

缓存惊群

缓存惊群换个名词就是缓存击穿、缓存踩踏。当缓存过期时,大量并发请求直接到数据库请求。

参考

知乎:什么是惊群,如何有效避免惊群?

维基百科:惊群问题

阅读 1126 · 发布于 2021-03-24

————        END        ————

扫描下方二维码关注公众号和小程序↓↓↓

扫描二维码关注我
昵称:
随便看看 换一批