Java基于Semaphore实现呼叫中心出现呼叫丢失问题求解
问题核心错误
你的现有实现存在两个核心逻辑问题:
- 仅使用单个信号量,完全没有限制消费者的取操作时机:队列无数据时消费者仍会执行
poll()返回null,相当于空占了应答名额,后续入队的呼叫自然没有对应的消费者处理,就出现了呼叫丢失的情况。 - 使用的
LinkedList是非线程安全队列,多线程并发调用add()和poll()时会出现队列结构损坏,导致部分呼叫没有正确入队或出队。
修正后实现(完全符合约束要求)
仅修改服务类即可,所有逻辑均基于Semaphore实现,仅调用acquire()和release()方法,未使用其他锁结构:
import java.util.Queue; import java.util.concurrent.Semaphore; import java.util.LinkedList; public final class BoundedCallCenterSemaphore implements BoundedCallCenter { private final Queue<Call> pendingCalls = new LinkedList<Call>(); // 空缓冲区信号量:初始值为队列最大容量,控制生产者最多放入的呼叫数 private final Semaphore empty = new Semaphore(MAX_NUMBER_OF_PENDING_CALLS, true); // 满缓冲区信号量:初始值为0,控制消费者仅在队列有呼叫时才能取 private final Semaphore full = new Semaphore(0, true); // 互斥信号量:初始值为1,保证队列操作的原子性 private final Semaphore mutex = new Semaphore(1, true); public void receive(Call call) throws Exception { // 先获取空缓冲区许可,队列满时阻塞 empty.acquire(); // 获取队列操作权限 mutex.acquire(); try { pendingCalls.add(call); } finally { // 释放队列操作权限 mutex.release(); } // 通知消费者有新的呼叫可处理 full.release(); } public Call answer() throws InterruptedException { // 先获取满缓冲区许可,队列空时阻塞,不会执行后续poll逻辑 full.acquire(); // 获取队列操作权限 mutex.acquire(); Call call; try { call = pendingCalls.poll(); } finally { // 释放队列操作权限 mutex.release(); } // 通知生产者有空位可以放入新呼叫 empty.release(); return call; } }
实现说明
- 两个计数信号量分别控制生产者和消费者的执行时机:生产者必须等有空位才能放呼叫,消费者必须等有呼叫才能取,完全避免了消费者取到null的情况,也不会出现队列溢出。
- 互斥信号量保证同一时间只有一个线程操作队列,完全解决了非线程安全队列的竞态问题,不会出现呼叫丢失或重复应答的情况。
- 所有阻塞都是通过
Semaphore的acquire()实现,没有忙等,完全符合作业要求。
内容的提问来源于stack exchange,提问作者Requieem
相关产品推荐
相关产品推荐

