我正在尝试编写一个游戏,其中我有一个Table类,每个坐在桌子上的人都是一个单独的线程。游戏涉及人们传递令牌,然后在派对铃声响起时停止。
我如何对run()方法进行编程,这样一旦我开始人员线程,他们就不会死,并且直到游戏结束时才会活着
我尝试过的一个解决方案是在run()方法中使用while(true){}循环,但这会将CPU利用率提高到60-70%左右。有更好的方法吗?
答案 0 :(得分:5)
虽然是,但你需要一个循环(while
只有一种方式,但它最简单)你还需要在循环中放置一些等待事情发生并响应它们的东西。你的目标是拥有类似伪代码的东西:
loop {
event = WaitForEvent();
RespondToEvent(event);
} until done;
好吧,这是40,000英尺的视野(一切看起来像蚂蚁!)但它仍然是你想要的核心。哦,你还需要一些东西来启动游戏的第一个事件,显然。
因此,密钥成为WaitForEvent()
的定义。经典之作是使用队列来保存事件,并从队列中进行阻塞读取,以便事情等到其他事件将事件放入队列中。这实际上是一个Concurrency-101数据结构,但是ArrayBlockingQueue
已经正确定义了,因此我在第一次实现时使用了它。您可能希望在Thread的子类中隐藏它的用法,可能是这样的:
public abstract class EventHandlingThread<Event> extends Thread {
private ArrayBlockingQueue<Event> queue = new ArrayBlockingQueue<Event>();
private boolean done;
protected abstract void respondToEvent(Event event);
public final void postEvent(Event event) throws InterruptedException {
queue.put(event);
}
protected final void done() {
done = true;
}
public final void run() {
try {
while (!done) {
respondToEvent(queue.take());
}
} catch (InterruptedException e) {
// Maybe log this, maybe not...
} catch (RuntimeException e) {
// Probably should log this!
}
}
}
对于您的每个任务,您应该能够很好地完成任务的子类。其他线程调用postEvent()
方法来发送消息,当你已经足够的时候就自己调用done()
。你还应该确保你总是得到一些可以发送的事件来终止事情,这样你就可以退出游戏......
答案 1 :(得分:3)
我会调查Locks和Conditions。这样您就可以编写等待特定条件发生的代码。这不会占用大量的CPU能力,甚至比睡眠效率更高,性能更好。
答案 2 :(得分:2)
让线程运行无限时间:
final Object obj = new Object();
try {
Thread th = new Thread(new Runnable() {
public void run() {
synchronized(obj) {
try {
System.out.println("Waiting");
obj.wait();
System.out.println("Done waiting");
}catch(Exception ex) {
ex.printStackTrace();
}
}
}
});
th.start();
System.out.println("Waiting to join.");
// Dont notify; but wait for joining. This will ensure that main thread is running always.
th.join();
System.out.println("End of the Program");
} catch(Exception ex) {
ex.printStackTrace();
}
答案 3 :(得分:1)
您可以在适当的时间添加Thread.sleep()
以最小化无用的循环迭代。
另一种解决方案是使用同步。虽然线程不需要执行任何操作,但它们使用wait()
方法在监视器上进入休眠状态,然后在转弯时,notify()
方法唤醒所需的线程。
答案 4 :(得分:1)
Actor model似乎适合这种情况。坐在桌子上的每个人和桌子本身都可以被建模为演员,并且传递令牌以及开始和停止游戏的事件可以被建模为在演员之间传递的消息。
作为奖励,通过将场景建模为actor,您可以摆脱对线程,同步和锁定的显式操作。
在JVM上,我更喜欢使用Scala来建模actor。对于Java,您可以使用像Kilim这样的库。有关Java中Actor模型相关库的比较,请参阅this post。
答案 5 :(得分:1)
一种方法是使用while循环但保持检查,即
while(true){
if(condition!=true){
Thread.sleep(time);
}else{
break;
}
}
这样一来,如果你的情况表明游戏还没有结束,它会使人线程处于睡眠状态并且内存消耗将会非常低。
答案 6 :(得分:0)
您应该测试while循环中的条件:
while (!gameOver)
{
do_intersting_stuff();
}
繁忙等待的CPU负载很重。你的循环实际上只是一遍又一遍地检查一个标志,比如
while (!gameOver)
{
if (actionNeeded)
{
do_something();
}
}
您可能会更改为另一个通知系统来睡眠和唤醒,因为这只会耗费CPU时间。