java concurrency 线程_Java Concurrency - 使用信号量实现监视器 - 所有线程都陷入等待状态,我的理解有问题...

该博客探讨了一个并发编程中的问题,即线程在使用信号量进行同步时可能出现的错误情况。作者展示了如何在缓冲区满或空时,通过调整许可的释放方式来避免线程等待死锁。博客内容包括了对原始代码的分析,指出问题所在,并提出了修改后的解决方案,确保了线程在适当的时候获取信号量,从而保证了缓冲区操作的正确性和线程间的公平性。
摘要由CSDN通过智能技术生成

问题是你无法控制notifyCalled.acquire()中哪个线程成功 .

例如,考虑这种情况:

线程A等待获取

线程B执行put两次并填充缓冲区 . 只有一个线程在等待,所以它调用notifyCalled.release()

线程C执行put并且由于缓冲区已满,它进入等待块 .

3中的notifyCalled.release()导致notifyCalled.aquire()在线程C而不是线程A中成功

由于缓冲区仍然是完整的,因此线程C(以及所有其他put操作)进入重新进入while循环并再次等待,并且线程B将永远不会收到它正在等待的释放 .

SOLUTION

当由于缓冲区已满(或与get操作相反)而未使用在放置操作块中获得的许可时,会出现问题 . 为避免这种情况,可以使用标志释放许可证,以便具有相反操作的另一个等待线程可以尝试获取它 .

此外,正如Daniel Pryden所述 inc() 也应该在monitorSemaphore锁内移动以避免竞争条件 .

请注意,这使得用于修改 blocksWaitingCount 的同步块变得不必要(尽管由于它们是无竞争的,因此它们对性能的影响很小) .

这是修改后的代码

public class BufferNonSync {

private int[] buffer = new int[] { 0};

private int start = 0;

private int last = 0;

private final int size = 1;

private int numberInBuffer = 0;

// Monitor variables

private Semaphore monitorSemaphore = new Semaphore(1);

private Semaphore notifyCalled = new Semaphore(0);

private int blocksWaitingCount = 0;

public void put(int input, int id) throws InterruptedException {

monitorSemaphore.acquire();

boolean acquired = false;

while (numberInBuffer == size) {

// Equivalent of wait()

if (acquired) {

dec();

notifyCalled.release();

}

inc();

monitorSemaphore.release();

notifyCalled.acquire();

monitorSemaphore.acquire();

acquired = true;

}

// Critical section

buffer[last] = input;

last = (last + 1) % size;

numberInBuffer++;

// Equivalent of notifyAll()

for (int i = val(); i > 0; i--) {

dec();

notifyCalled.release();

}

monitorSemaphore.release();

}

public int get(int id) throws InterruptedException {

monitorSemaphore.acquire();

boolean acquired = false;

while (numberInBuffer == 0) {

// Equivalent of wait()

if (acquired) {

dec();

notifyCalled.release();

}

inc();

monitorSemaphore.release();

notifyCalled.acquire();

monitorSemaphore.acquire();

acquired = true;

}

// Critical section

int temp = buffer[start];

start = (start + 1) % size;

numberInBuffer--;

// Equivalent of notifyAll()

for (int i = val(); i > 0; i--) {

dec();

notifyCalled.release();

}

monitorSemaphore.release();

return temp;

}

private void inc() {

blocksWaitingCount++;

}

private void dec() {

blocksWaitingCount--;

}

private int val() {

return blocksWaitingCount;

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值