Sleep()in for循环

时间:2014-05-11 21:21:49

标签: java multithreading algorithm sleep

所以我写了一个兔子和狼的模拟,我有一个单独的线程,在它的运行迭代所有动物的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之后暂停睡眠,因为它会停止对所有内容的迭代。有什么方法可以让它发挥作用吗?我不想为每只动物使用单线程。

5 个答案:

答案 0 :(得分:5)

我同意@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
}

答案 1 :(得分:3)

我并不完全清楚你的需求,但你可以用几个线程来做 - 甚至可能只需要一个额外的线程。

我会将处理要求(所有动物必须移动)设置为DelayQueue并在单独的线程中处理队列。

  

DelayQueue - Delayed元素的无界阻塞队列,其中只有在延迟过期时才能获取元素。

将您的动物的每次移动都延迟到您想要的延迟时间。从队列中有一个单独的线程take每个事件并执行它。队列将为您执行阻止和调度 - 根本不需要sleep

每当您处理一只动物从队列移动时,请按照所需的延迟将其重新发布回队列。

答案 2 :(得分:2)

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

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。我认为这应该与“转向”数字相关联,而不是实际时间(这取决于你的渲染速度和其他因素)。

答案 3 :(得分:1)

你想要做的是从框架的角度思考。每一帧更新一切(例如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);
            }
        }

    }

}

答案 4 :(得分:0)

这是一个不需要使用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
    }
}