睡眠()在for循环

est_et 发布于 2019-05-15 algorithm 最后更新 2019-05-15 22:59 32 浏览

所以我写了一个兔子和狼的模拟,并且我有一个单独的线程在其循环中迭代for循环中的所有动物 - 一个用于兔子和一个用于狼群。所以:

public void run(){
    while(rabbitNumber!=0){
                for(int i=0; i<rabbitsNumber; i++){ doRabbitMove();}
                for(int i=0; i<wolvesNumber; i++){ doWofMove();}
            }
    }
现在,在每只狼和兔子移动之后,我需要暂停 - 但不是为了整个线程,而只是为了那个动物。我不能在doWolfMove / doRabbitMove之后继续睡觉,因为它会停止对所有事物的迭代。有什么办法可以让它工作吗?我不想为每只动物使用单线程。
已邀请:

qfugit

赞同来自:

你想要做的是从框架的角度思考。每帧更新一切(例如1/60秒),然后睡到下一帧(动物在更新时不需要做任何事情,只是给它机会)。 所以说一只兔子移动然后需要休息2秒才能再次移动。每只兔子都有一个restTime的实例变量,它会在移动后设置为2秒。每帧都会减少这个变量的帧时间(1/60秒)。当变量为零或更小时,它再次移动。这意味着您可以在一个线程中完成所有操作,并且动物的移动不会相互依赖(除非您希望它们当然是这样)。 如果你正在制作动画,那么最好测量一下实际的帧时间并使用它,而不是假设你真的得到了你要求的1/60秒。 一个例子可能如下

public class Rabbit {
    private double timeBetweenMoves;
    private double sleepTime=0;
    private String name;
public Rabbit(String name,double timeBetweenMoves) {
        this.name=name;
        this.timeBetweenMoves=timeBetweenMoves;
    }
public void update(double timeSlice){
        sleepTime-=timeSlice;
if (sleepTime<0){
            makeMove();
        }
    }
private void makeMove(){
        sleepTime=timeBetweenMoves;
//actually make the move
System.out.println(name + " Moved");
    }
public static void main(String[] args){
double frameTime=1/60.0;
List<Rabbit> rabbits=new ArrayList<>();
rabbits.add(new Rabbit("Floppsy",2)); //moves every 2 seconds
        rabbits.add(new Rabbit("Hopper",5)); //moves every 5 seconds
while(true){
            for(Rabbit rabbit:rabbits){
                rabbit.update(frameTime); //assumes frametime is actually what you asked for, can cause graphics to look stuttery
            }
            try {
                long milllisecondsToSleep=(long)(frameTime*1000);
                Thread.sleep(milllisecondsToSleep);
            } catch (InterruptedException ex) {
                Logger.getLogger(Rabbit.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
}
}

bea

赞同来自:

如果这是一个游戏循环,那么走向这个方向可能更有意义:

public void run() {
while (rabbitsNumber > 0) {
for (int i=0; i<rabbitsNumber; i++)
             if (shouldMoveRabbit(i)) doRabbitMove();
for (int i=0; i<wolvesNumber; i++)
             if (shouldMoveWolf(i)) doWolfMove();
renderScreen();    
    }
}
这些shouldMoveXXX方法应该在适当的时间为特定动物索引返回false。我认为这应该与“转向”数字相关联,而不是实际时间(这取决于你的渲染速度和其他因素)。

zet

赞同来自:

我同意@Groo。实现shouldMoveXXX比不必要地搞乱并发性更好。你仍然可以把这个时间(因为你的评论让你看起来像你想要的)这样:

// time between each move
final int SLEEP_TIME = 1000;
//each animal has this variable, it is the last time they moved
long lastMoveTime;
public boolean shouldMoveRabbit(){
    if(System.currentTimeMillis() >= lastMoveTime + SLEEP_TIME)
         return true;
    return false;
}
public void doMoveRabbit(){
    lastMoveTime = System.currentTimeMillis();
    // move stuff
}

eos_et

赞同来自:

这是一个不需要使用Sleep()或线程的解决方案,基本上我们将进行模拟,在视频游戏开发中使用相同的逻辑。

public class Simulation 
{
    int clock;
public static void simulate (Location r, Location w, int end_time)
    {
        clock = 0;
Rabbit rabbit = new Rabbit (r);
        Wolf wolf = new Wolf (w);
while (clock < end_time)
        {
            rabbit.update(clock, wolf.getLocation());
            wolf.update(clock, rabbit.getLocation());
if(interlace(rabbit.getLocation(), wolf.getLocation()))
            {
                System.out.println("Wolf caught the rabbit at Time="+clock);
                break;
            }
clock++;
        }
    }
public static interlace (Location a, Location b)
    {
        // return TRUE if two locations interlace
    }
}

bsequi

赞同来自:

我并不完全清楚你的需求,但你可以用几个线程来做 - 甚至可能只需要一个额外的线程。 我将处理要求(所有动物必须移动)设置为DelayQueue并在单独的线程中处理队列。

DelayQueue - An unbounded blocking queue of Delayed elements, in which an element can only be taken when its delay has expired.
将您动物的每一步移动到您想要的延迟中。从队列中有一个单独的线程take每个事件并执行它。队列将为您执行阻止和调度 - 根本不需要sleep。 每当您处理一只动物从队列中移动时,请按照所需的延迟将其重新发布回队列。