假设我有一间带m房的酒店。
嘉宾(主题)一直进出。
一个房间里面可以有很多人,但只有一个房间会有人。例如:
嘉宾C(想要房间1)
一旦所有房间都空了,A可以去1号房间;
B还不能去2号房间,因为还有另一个房间还有人在里面;
C可以去1号房间,因为C室想要的是唯一有人在里面的房间;
鉴于A和C离开1号房间,B应该可以去2号房间
退出房间的最后一位客人应该阻止其他客人(避免他们在外出时进来),直到它离开,以便其他人可以继续
我怎么能以某种方式实现这个线程不会饿死?
为简单起见,假设一旦宾客进入一个房间,它会睡几秒钟然后离开。这是我的(错误的)实现:
import java.util.ArrayList;
import java.util.Random;
public class Guest extends Thread {
static Rooms rooms = new Rooms(5);
int id;
Guest(int id) {
this.id = id;
}
public void run() {
rooms.join(this);
nap();
rooms.quit(this);
}
public void nap() {
try {
sleep((new Random().nextInt(4000) + 1000));
} catch (InterruptedException e) {
}
}
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 20; i++) {
Thread t = new Guest(i);
t.start();
Thread.sleep((long) new Random().nextInt(1500) + 1000);
}
}
}
class Rooms {
Room[] rooms;
int busy;
Rooms(int m) {
busy = -1;
rooms = new Room[m + 1];
for (int i = 0; i < m + 1; i++)
rooms[i] = new Room();
}
void join(Guest h) {
if (busy == -1) {
busy = (new Random().nextInt(rooms.length));
}
rooms[busy].add(h);
System.out.println("Guest " + h.id + " came inside room " + busy + " with " + rooms[busy].size() + " people");
}
void quit(Guest h) {
if (rooms[busy].size() == 1) {
setHandler(busy, h);
} else {
rooms[busy].remove(h);
System.out
.println("Guest " + h.id + " came out of room " + busy + " with " + rooms[busy].size() + " people");
}
}
synchronized void setHandler(int numQuarto, Guest ultimo) {
System.out.println("(Last) Guest " + ultimo.id + " came out of room " + busy + " with "
+ rooms[numQuarto].size() + " people");
rooms[numQuarto].remove(ultimo);
busy = -1;
}
}
class Room extends ArrayList<Guest> {
}
答案 0 :(得分:1)
使用线程执行此操作 - 这是非常人为的,但我认为这是一个练习 - 您需要学习如何在某个条件下进行Thread
等待,以及如何通知一个或多个{ {1}}他们等待的条件可能已经满足。方便的是,每个对象都有用于这些目的的方法Threads
,wait()
和notify()
。
wait / notify的一个重要考虑因素是您必须小心等待并通知正确的对象。通常,不您想要受影响的notifyAll()
,而是所有相关线程所依赖的共享对象,以实现相互同步。在这种特殊情况下,看起来Thread
会很好。
一般的想法是在Guest.rooms
中,当前线程测试它是否可以立即占用一个房间。如果是这样,它确实如此,现在继续。但是,如果没有,则调用Rooms.join()
(在wait()
实例上,此时为Rooms
)。每当this
返回时,线程必须再次检查它是否可以立即占用它想要的房间;如果没有,它必须再次等待。
另一半将在wait()
。每当运行该方法的线程是房间外的最后一个线程时,它必须重置Rooms.quit()
以指示没有占用空间,然后,重要的是,调用busy
让所有线程在那时等待知道有机会得到一个房间。
您会发现需要对此进行适当的同步。特别是,您只能在持有目标对象的监视器时调用notifyAll()
和wait()
(以及notifyAll()
)(它将在等待期间释放,并在等待之前重新获取()返回)。您还需要确保正确同步共享对象的所有操作,但是,在这种情况下主要是notify()
及其成员,而不会阻止线程继续执行。特别要注意的是,Rooms
不的线程会释放他们可能持有的任何监视器。
剩下的由你决定。我给你的提示比我应该提供的更多,但是学习如何正确使用wait / notify确实有点棘手。
答案 1 :(得分:1)
你做不到。根据您的要求,需要实施其他机制,以确保不会发生饥饿。例如,
嘉宾(主题)一直进出。
因此, n 线程有可能在整个时间内进入Room m 。也有可能在那段时间里有更多的线程需要另一个房间。但是,在Room m 首次清空(可能永远不会发生)之前,他们无法进入房间。这可以继续任意数量的房间和线程。即使......就是这种情况。
为简单起见,假设一旦宾客进入房间,就会发生这种情况 睡了几秒然后就出去了。
那是因为......
C可以去1号房间,因为C室想要的是唯一的房间 里面的人;
这意味着另一个线程可能会进入一个已经占用的房间,其中有一个或多个线程,其中 t 时间要休眠。新线程进入休眠状态,直到上一个线程之后才会唤醒。在睡觉 n 时,更多线程可能进入房间,可能导致其他线程等待其他房间饿死。