我必须使用Java信号量解决这个问题,但我不知道如何,我找不到任何相关的Java资料。这是怎么回事:
有各种各样的线索:男人和女人。两者都想使用数量为BATHROOM_SIZE的相同资源。 5条规则:
1woman,1man,5women,5men
5women1men,5men1women,2men2women,5men5women。
自从周一以来,我一直在尝试让它发挥作用,现在我已经没有想法了。
所以我的任务是编写实现 BathroomInterface 的 Bathroom.java 类:
public interface BathroomInterface {
public static final int BATHROOM_SIZE = 3; //3 is just example
void manEnter();
void manExit();
void womanEnter();
void womanExit();
}
在系统中有许多男人和女人的线程都是这样的:
for(int i = 0; i < n; i++) {
bathroom.manEnter();
//uses bathroom random amount of time
bathroom.manExit();
}
for(int i = 0; i < m; i++) {
bathroom.womanEnter();
//uses bathroom random amount of time
bathroom.womanExit();
}
我也有 Bathroom.java 类的方案,我必须扩展:
import java.util.concurrent.Semaphore;
public class Bathroom implements BathroomInterface {
private Semaphore mutex = new Semaphore(1, true);
public void womanEnter() {
mutex.acquireUninterruptibly();
}
public void womanExit() {
mutex.release();
}
public void manEnter() {
mutex.acquireUninterruptibly();
}
public void manExit() {
mutex.release();
}
}
这是我到目前为止所做的:
import java.util.concurrent.Semaphore;
public class Bathroom implements BathroomInterface {
int manW=0, manU=0, womanW=0, womanU=0; //*U-using, *W-waiting
private Semaphore mutex = new Semaphore(1, false);
public void womanEnter() {
womanW++;
StateChange();
}
public void womanExit() {
womanU--;
mutex.release();
StateChange();
}
public void manEnter(){
manW++;
StateChange();
}
public void manExit() {
manU--;
mutex.release();
StateChange();
}
void StateChange() {
if(womanU==0 && manU==0) {
if(manW>womanW) {
while(manW>0 && manU<BATHROOM_SIZE) {
manW--;
manU++;
mutex.acquireUninterruptibly();
}
}
else {
while(womanW>0 && womanU<BATHROOM_SIZE) {
womanW--;
womanU++;
mutex.acquireUninterruptibly();
}
}
}
if(womanU==0 && manU<BATHROOM_SIZE) {
while(manW>0 && manU<BATHROOM_SIZE) {
manW--;
manU++;
mutex.acquireUninterruptibly();
}
}
if(manU==0 && womanU<BATHROOM_SIZE) {
while(womanW>0 && womanU<BATHROOM_SIZE) {
womanW--;
womanU++;
mutex.acquireUninterruptibly();
}
}
}
}
答案 0 :(得分:5)
实际上,这个练习是使用监视器完成的,而不是信号量。你正在做的事情大部分都很好,你错过了条件。所以,在你的浴室课上,声明:
锁定:private Lock lock = new ReentrantLock();
锁定的2个条件或队列:
private Condition womenWaitingQueue = lock.newCondition();
private Condition menWaitingQueue = lock.newCondition();
2个计数器知道有多少人在等待,2个知道有多少人正在使用:
private int womenWaitingN = 0;
private int menWaitingN = 0;
private int womenUsingN = 0;
private int menUsingN = 0;
当然还有资源数量:
private final int BATHROOM_CAPACITY = 5;
private int free_resources = BATHROOM_CAPACITY;
所有4个函数都在这里,但由于作业标记
而被删除这里重要的是防止饥饿,如果有女人在等待和反之,不允许任何男人进入浴室。
所以,条件是,如果一个男人想进入浴室,它必须检查浴室是否至少有一个免费点(使用免费资源),如果浴室里有女性(使用womenUsingN)。如果不满足这两个条件中的任何一个,那么该男子必须等待(使用menWaitingQueue):
menWaitingQueue.await();
当一个男人离开浴室时,必须检查是否有女性在等待(女性等待N),如果有,她们会得到通知:
womanWaitingQueue.signal();
因为menUsingN柜台,女性发出信号,直到浴室里没有男人才能进入。如果没有女性在等待,那么可以发信号通知男性进入浴室。这可以防止饥饿,因为优先考虑异性(如果等待)。
最后一点是,每个功能都必须在每个进入/退出功能的开头/结尾锁定/解锁锁定。
lock.lock();
lock.unlock();
我认为通过这些新信息,您将能够自行完成这些功能。祝你好运!
答案 1 :(得分:2)
我认为你在使用整个mutex.acquire和mutex.release语义时会遇到困难,特别是对于互斥锁实际应该保护的内容。让我尝试简化一下这个问题,以便给出一个如何处理这个问题的提示。
要求您实现一个比简单信号量更复杂的并发对象,具有两个客户端类和防止饥饿。我不打算为你做那个,但是我将向你展示一个简单的信号量在Java6之前的版本中的样子:
public class Resource {
private int numClients = 0;
private final int maxClients;
public Resource(int maxClients) {
this.maxClients = maxClients;
}
public synchronized void acquire() {
while (!clientCanAcquire()) {
try {
wait();
} catch (InterruptedException e) {
}
}
++numClients;
printState();
}
public synchronized void release() {
--numClients;
printState();
notify();
}
private boolean clientCanAcquire() {
return numClients < maxClients;
}
private void printState() {
System.out.println("Resource is currently acquired by " + numClients
+ " clients");
}
}
客户可以按如下方式访问:
import java.util.Random;
public class Client implements Runnable {
private Resource resource;
private Random rnd = new Random();
public Client(Resource resource) {
this.resource = resource;
}
public void run() {
try {
Thread.sleep(rnd.nextInt(1000));
resource.acquire();
Thread.sleep(rnd.nextInt(1000));
resource.release();
} catch (InterruptedException e) {
}
}
}
并且可以驱动整个事情的最简单的应用程序将如下所示:
public class App {
public static void main(String[] arg) {
Resource r = new Resource(3);
for (int i = 0; i < 10; i++) {
Thread client = new Thread(new Client(r));
client.start();
}
}
}
资源存储确定客户端何时可以访问内部变量所需的信息。在多线程应用程序中,必须同步对这些变量的访问。这里显示的是最简单的方法,但你也可以说
private Object mutex = new Object();
然后
synchronized (mutex) { }
或任何其他类型的互斥锁。
你的问题比简单的普通信号量更复杂,但底层逻辑应该非常相似。
答案 2 :(得分:0)
@ Th0rndike好的,我按照你的提示写了这样的话:
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.*;
public class Bathroom implements BathroomInterface {
private Semaphore mutex = new Semaphore(1, false);
private Lock lock = new ReentrantLock();
private Condition womenWaitingQueue = lock.newCondition();
private Condition menWaitingQueue = lock.newCondition();
private int womenWaitingN = 0;
private int menWaitingN = 0;
private int womenUsingN = 0;
private int menUsingN = 0;
private int free_res = BATHROOM_SIZE;
public void womanEnter() {
lock.lock();
if(free_res>0 && menUsingN==0) {
womenUsingN++;
free_res--;
mutex.acquireUninterruptibly();
}
else
try {
womenWaitingQueue.await();
}
catch(Exception e) {
System.out.println("E!");
}
lock.unlock();
}
public void womanExit() {
lock.lock();
womenUsingN--;
free_res++;
mutex.release();
if(menWaitingN>0) {
try {
menWaitingQueue.signal();
}
catch(Exception e) {
System.out.println("E!");
}
}
lock.unlock();
}
public void manEnter() {
lock.lock();
menUsingN++;
free_res--;
if(free_res>0 && womenUsingN==0) {
mutex.acquireUninterruptibly();
}
else
try {
menWaitingQueue.await();
}
catch(Exception e) {
System.out.println("E!");
}
lock.unlock();
}
public void manExit() {
lock.lock();
menUsingN--;
free_res++;
mutex.release();
if(womenWaitingN>0) {
try {
womenWaitingQueue.signal();
}
catch(Exception e) {
System.out.println("E!");
}
}
lock.unlock();
}
}
但是当我将它提交给自动程序检查器时,在1man和1woman测试中一切正常,但在其余部分,它返回“实时超出”错误。如果我删除lock.lock()/ unlock(),“实时超出”错误将变为“错误答案”。
答案 3 :(得分:0)
http://se.inf.ethz.ch/courses/2013a_spring/ccc/
有一个解决方案您可以参考这些以获得一些帮助。