gpt4 book ai didi

java - 如何避免线程饿死

转载 作者:行者123 更新时间:2023-11-30 08:43:34 25 4
gpt4 key购买 nike

假设我有一家有 m 间客房的酒店。

guest (线程)一直进出。

一个房间可以有很多人,但只有一个房间会有人。例如:

  • 客人 A(想要房间 1)
  • 客人 B(想要房间 2)
  • 客人 C(想要房间 1)

    A 可以去房间 1,一旦所有房间都空了;

    B 还不能去 2 号房间,因为还有另一个房间还有人在里面;

    C可以去1号房间,因为C要的房间是唯一有人在的房间;

  • 鉴于 A 和 C 离开房间 1,B 应该可以去房间 2

  • 最后一个离开房间的客人应该阻止所有其他客人(避免他们在他出来时进来)直到它离开,这样其他人才能继续

我怎样才能以某种方式实现线程不会饿死?

为简单起见,假设 Guest 进入房间后,它会睡几秒钟然后离开。这是我的(错误的)实现:

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> {
}

最佳答案

要用线程来做到这一点——这是高度人为的,但我想这是一个练习——你需要学习如何让一个 Thread 等待一个条件,以及如何通知一个或多个 Threads,它们正在等待的条件可能已经满足。方便的是,每个对象都有用于这些目的的方法 wait()notify()notifyAll()

wait/notify 的一个重要考虑因素是您必须小心等待并通知正确的对象。通常,您希望受影响的不是Thread,而是所有涉及的线程相互同步所依赖的共享对象。在这种特殊情况下,看起来 Guest.rooms 会做得很好。

一般的想法是,在 Rooms.join() 中,当前线程测试它是否可以立即占用房间。如果是这样,它确实如此,并且像现在一样继续。但是,如果没有,它会调用 wait()(在 Rooms 实例上,此时是 this)。每当 wait() 返回时,线程必须再次检查它是否可以立即占用它想要的空间;如果没有,则必须再次等待。

另一半将在 Rooms.quit() 中。每当运行该方法的线程是最后一个离开房间的线程时,它必须重置 busy 以指示没有房间被占用,然后,重要的是,调用 notifyAll()让当时等待的所有线程都知道有机会获得房间。

您会发现您需要为此使用适当的同步。特别是,您只能在持有目标对象的监视器时调用 wait()notifyAll()(以及 notify())(它将在等待期间被释放,并在 wait() 返回之前重新获取)。您还需要确保正确同步共享对象的所有操作,但是,在本例中主要是 Rooms 及其成员,而不会阻止线程在其他情况下继续进行。特别要注意,sleep() 不会因此释放它们可能持有的任何监视器的线程。

剩下的就看你了。我给了你比我应该给的更多的提示,但学习如何正确使用 wait/notify 确实有点棘手。

关于java - 如何避免线程饿死,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34167108/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com