Java Pong - 计时器线程睡眠仍然运行功能

时间:2013-05-28 18:33:41

标签: java timer

我在java中制作乒乓球

如果球越界,pause设置为true

    if (ball.getX() <= 0) {
        score2++;   
        pause = true;       
    }
    if (ball.getX() >= this.getWidth()-ballWidth) {
        score1++;
        pause = true;
    }

应该睡觉计时器......在线程休眠1000ms后,暂停将被设置为false并且球应该继续移动(ball.autoMove()):

public void timer() {
    int initialDelay = 1000;

    timer.scheduleAtFixedRate(new TimerTask() {
        public void run() {
            if (pause) {
                try {   
                    ball.reset(width/2, height/2);
                    Thread.sleep(1000);     
                    pause = false;                      
                } 
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            ball.autoMove(velocityX, velocityY);    
            collisionCheck();           
        }
    }, initialDelay, 100);  
}

Ball Class AutoMove()函数:

public void autoMove(double velX, double velY) {
    xLoc = this.getX()+velX;    
    yLoc = this.getY()+velY;    
}

它完成了所有这些...它睡眠,暂停设置为假等等......但是当球暂停1秒钟后重置球时(在屏幕中间重置...)跳到游戏面板的远端,告诉我当线程“正在睡觉”时,ball.autoMove(velocityX, velocityY);仍在更新坐标。

为什么会这样?不应该不运行吗?

谢谢!

3 个答案:

答案 0 :(得分:6)

指令

timer.scheduleAtFixedRate(new TimerTask() {...}, initial, 100 );

在1秒的睡眠期间,将10次出现的autoMove添加到计时器队列中。

以固定费率进行的安排是正确的,但您无需代替睡觉。

将计数器设置为10并在每次调用方法时将其递减,当它达到零时,继续按正常方式行进(与“暂停”方式相反)。

timer.scheduleAtFixedRate(new TimerTask() {
   public void run() {
      if( pauseCount == 10 ) {
         ball.reset(width/2, height/2);
      }
      if( pauseCount > 0 ) {
         --pauseCount;
      }
      else {
         ball.autoMove( velocityX, velocityY );
         collisionCheck();
      }
   }
}, initialDelay, 100 );

在睡眠时按照执行日志。

首先是程序:

import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;

public class SO {

   static boolean isTrue = true;

   public static void main( String[] args ) {
      new Timer().scheduleAtFixedRate( new TimerTask() {
         @Override public void run() {
            System.out.println(
               System.currentTimeMillis() + ": " + Thread.currentThread());
            try{
               if( isTrue ) {
                  TimeUnit.SECONDS.sleep( 1 );
                  isTrue = false;
               }
            }
            catch( InterruptedException e ){
               e.printStackTrace();
            }
         }
      }, 0, 100 );
   }
}

记录日志,观察时间:

1369769673294: Thread[Timer-0,5,main]
1369769674308: Thread[Timer-0,5,main] <-- #1 at 308
1369769674308: Thread[Timer-0,5,main] <-- #2 at 308
1369769674308: Thread[Timer-0,5,main]
1369769674308: Thread[Timer-0,5,main]
1369769674308: Thread[Timer-0,5,main]
1369769674308: Thread[Timer-0,5,main]
1369769674308: Thread[Timer-0,5,main]
1369769674308: Thread[Timer-0,5,main]
1369769674308: Thread[Timer-0,5,main]
1369769674308: Thread[Timer-0,5,main] <-- #10 at 308, queued during the sleep
1369769674402: Thread[Timer-0,5,main]
1369769674496: Thread[Timer-0,5,main]
1369769674605: Thread[Timer-0,5,main]
1369769674699: Thread[Timer-0,5,main]
1369769674808: Thread[Timer-0,5,main]
1369769674901: Thread[Timer-0,5,main]
1369769674995: Thread[Timer-0,5,main]

我们观察到激活就像排队一样,但事实上,类Timer只有一个线程。 这是模拟事件队列的逻辑,java.util.Timer的文档很清楚:

  

在固定费率执行中,每次执行都是相对于   初始执​​行的预定执行时间。如果执行是   因任何原因而延迟(例如垃圾收集或其他背景   活动),两个或多个执行将快速连续发生   “跟上来。”从长远来看,执行的频率将是   恰好是指定时期的倒数(假设系统   基础Object.wait(long)的时钟是准确的)。因此   以上,如果预定的第一次是过去,那么任何   “错过”的处决将被安排立即“追赶”   执行。

答案 1 :(得分:2)

当此线程处于休眠状态时,保证不会调用autoMove。但是,在没有查看代码的情况下,我敢打赌,autoMove正在根据实时变化来移动球。一旦暂停结束,这将使球看起来跳跃,你再次调用autoMove。

您需要根据相对时间更改autoMove,否则您需要更改其使用的时间变量并减去暂停时间。

答案 2 :(得分:0)

很高兴看到改变暂停的完整代码。

你怎么知道它在睡觉时发生了什么?你可以添加带有时间戳的记录器吗?但我会采取刺。

如果在另一个线程中设置暂停,则需要对其进行同步,如果您将其声明为volatile,那么这是一个好主意。在这种方法中同步,并且正在设置暂停的地方。

private volatile Boolean pause = false;
//...
//make a setter and getter for pause
synchronized ( pause    ){
    return  pause ;    
}

synchronized ( pause    ){
    return  pause = newPauseValue;    
}