我正在尝试理解这个旧考试任务的答案,其中学生应该使用javas reentrantlock实现公平的二进制信号量.我不明白这些柜台的意义:
int next = 0;
int nextToGo = 0;
int myNumber;
它在任务描述中说“你可以假设程序中最多有20个线程使用信号量.此外,在一次运行程序期间最多只能进行1000万次信号量操作.”
在任务的解决方案中,它说:“每个尝试获取信号量的线程必须在队列中注册,并且只有在之前的线程离开之后才离开队列.每个线程都记住它在队列中的位置使用32-计数器将不会回转,因为在信号量上将执行大多数1000万次操作,但即使计数器可以包围,代码也能正常运行.
对我而言,老师似乎忽略了解决方案中1000万个线程的限制,但我的主要问题是为什么在将线程放入lock()和await()语句的队列中时需要计数器,并且正在检查的*变量.并且ReentrantLock(真实)不会照顾公平吗?
解:
public class FairSemaphore {
ReentrantLock l = new ReentrantLock(true);
Condition c = l.newCondition();
int next = 0;
int nextToGo = 0;
boolean free = true;
public void aqcuire() throws InterruptedException {
l.lock();
int myNumber = next++;
while(!(free && myNumber == nextToGo)) {
c.await();
}
free = false;
nextToGo++;
l.unlock();
}
public void release() {
l.lock();
free = true;
c.signalAll();
l.unlock();
}
}
解决方法:
虽然您可能会认为ReentrantLock上的线程阻塞
排队,不能保证队列作为FIFO公平行事
队列.文档明确告诉您:
…this lock does not guarantee any particular access
order.
… Note however, that fairness of locks does not guarantee fairness of thread scheduling. …
阅读整个docs,即使您创建了一个公平的ReentrantLock,它也不能保证它是公平的.
但是,显示的代码确实表现得很公平,因为计数器使线程以FIFO顺序获取锁定.
代码是一个Ticket Lock,所以也请查看https://en.wikipedia.org/wiki/Ticket_lock