TimerTask not work as expected

S

SamuelXiao

Hi all, I am writing a simple monopoly board game, there're only 2
tokens, one is controlled by human, another by PC. I am trying to
make it turn based and move around the map step by step. Then when I
use TimerTask to trigger the step-forward movement, it's ok for the
token controlled by human, but for the PC one. It doesn't move as
expected. Below is part of the codes for Dice Roll button & Done
button.

// btnRoll() function
public void btnRoll() {
Timer timer = new Timer();
final int index = turn - 1;
boolean snakeEyes = false;
Dice1 = (int)(Math.random() * 6 + 1);
Dice2 = (int)(Math.random() * 6 + 1);

if(Dice1 == Dice2) {
snakeEyes = true;
rolled = false;
}
else
rolled = true;

if(snakeEyes == true){
tempFlagPlayer = true;
}else{
tempFlagPlayer = false;
}
timer.schedule(new TimerTask(){
private int temp = Dice1 + Dice2;
public void run(){
if (temp > 0){
SystemLogHelper.debug("btnRoll()'s players.get(index): " + index);
movePlayer(players.get(index), tempFlagPlayer); // move player one
space each time
temp --;
}else{
checkPlayerMovedStatus(players,tempFlagPlayer);
cancel();
}
repaint();
}
}, 100L,100L);
repaint();
}

// PC turn
public void AIturn(int tempNumOfPlayers){
btnRoll();
SystemLogHelper.info("players.get(turn-1): " +
players.get(turn-1).getName());
SystemLogHelper.info("players.get(turn-1).getPosition(): " +
players.get(turn-1).getPosition());
if(propertymanager.Properties[players.get(turn-1).getPosition()]
[0] == 0){
SystemLogHelper.info("enter btnBuy()");
btnBuy();
}
if(rolled) btnDone(tempNumOfPlayers);
}

// done button, next player's turn
public void btnDone(int tempNumOfPlayers){
rolled = false;
if(this.getTurn() == tempNumOfPlayers){
this.setTurn(1);
}
else{
turn += 1;
// SystemLogHelper.info("AI's this.getTurn(): " + turn);
if((AutoPlayer)players.get(turn - 1) instanceof AutoPlayer){
AIturn(tempNumOfPlayers);
}
}
repaint();
}


The main problem is, I found that
SystemLogHelper.info("players.get(turn-1): " +
players.get(turn-1).getName());
and SystemLogHelper.info("players.get(turn-1).getPosition(): " +
players.get(turn-1).getPosition());
will run before the btnRoll() function.

how could I make sure that btnRoll() is done then go to the next
code?
Any help would be appreciated.
 
T

Travers Naran

Hi all, I am writing a simple monopoly board game, there're only 2
tokens, one is controlled by human, another by PC. I am trying to
make it turn based and move around the map step by step. Then when I
use TimerTask to trigger the step-forward movement, it's ok for the
token controlled by human, but for the PC one. It doesn't move as
expected. Below is part of the codes for Dice Roll button& Done
button.

timer.schedule(new TimerTask(){
private int temp = Dice1 + Dice2;
public void run(){
if (temp> 0){
SystemLogHelper.debug("btnRoll()'s players.get(index): " + index);
movePlayer(players.get(index), tempFlagPlayer); // move player one
space each time
temp --;
}else{
checkPlayerMovedStatus(players,tempFlagPlayer);
cancel();
}
repaint();
}
}, 100L,100L);
how could I make sure that btnRoll() is done then go to the next
code?
Any help would be appreciated.

Timer runs TimerTask in a _separate_ thread. There are a few ways you
could synchronize this, but I'd recommend looking at wait()/notify().
Try to remember that you are waiting for your TimerTask to be called
Dice1+Dice2 times before you leave.
 
S

SamuelXiao

Timer runs TimerTask in a _separate_ thread.  There are a few ways you
could synchronize this, but I'd recommend looking at wait()/notify().
Try to remember that you are waiting for your TimerTask to be called
Dice1+Dice2 times before you leave.- Hide quoted text -

- Show quoted text -

Hi Travers,

Thanks for youjr suggestion, I use wait() now, but it comes to another
problem. I added wait() in the AITurn() method..Then now an exception
was caught..

public void AIturn(int tempNumOfPlayers){
long temp = (long) (Dice1 + Dice2) * 100;
btnRoll();
SystemLogHelper.info("players.get(turn-1): " +
players.get(turn-1).getName());
SystemLogHelper.info("players.get(turn-1).getPosition(): " +
players.get(turn-1).getPosition());
try {
this.wait(temp);
// notify();
// Thread.sleep(temp);
}
catch(InterruptedException e){}

if(propertymanager.Properties[players.get(turn-1).getPosition()]
[0] == 0){
SystemLogHelper.info("enter btnBuy()");
btnBuy();
}
btnDone(tempNumOfPlayers);

// }
// if(rolled) btnDone(tempNumOfPlayers);
}

// IllegalMonitorStateException
java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at com.xxx.applet.MonopolyBoard.AIturn(MonopolyBoard.java:822)
at com.xxx.applet.MonopolyBoard.btnDone(MonopolyBoard.java:485)
at com.xxx.applet.MonopolyEntry.actionPerformed(MonopolyEntry.java:
140)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.setPressed(Unknown Source)

seems that if I use wait(), these btnDone()/btnRoll() will be lost its
eventlistener? Is my understanding correct? I tried notify()/sleep()
and so on...but they doesn't work. wait() method can provide the token-
movement as I wanted but it is able to trigger btnDone() method
 
L

Lew

Don't use TAB characters to indent Usenet posts; use spaces (up to four per
level).

You have not synchronized access do 'Dice1' (variable names should start with
a lower-case letter) or 'Dice2'.

....
Read up on 'volatile', 'synchronized' and other concurrent-programming
constructs in Java. Buy, read and study /Java Concurrency in Practice/ by
Brian Goetz, et al.
Thanks for youjr suggestion, I use wait() now, but it comes to another
problem. I added wait() in the AITurn() method..Then now an exception
was caught..

public void AIturn(int tempNumOfPlayers){
long temp = (long) (Dice1 + Dice2) * 100;
btnRoll();
SystemLogHelper.info("players.get(turn-1): " +
players.get(turn-1).getName());
SystemLogHelper.info("players.get(turn-1).getPosition(): " +
players.get(turn-1).getPosition());
try {
this.wait(temp);

Putting 'this.' in front of method calls is useless and misleading.
// notify();
// Thread.sleep(temp);
}
catch(InterruptedException e){}

if(propertymanager.Properties[players.get(turn-1).getPosition()]
[0] == 0){
SystemLogHelper.info("enter btnBuy()");
btnBuy();
}
btnDone(tempNumOfPlayers);

// }
// if(rolled) btnDone(tempNumOfPlayers);
}
// IllegalMonitorStateException
java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at com.xxx.applet.MonopolyBoard.AIturn(MonopolyBoard.java:822)
at com.xxx.applet.MonopolyBoard.btnDone(MonopolyBoard.java:485)

That exception is thrown when you call 'wait()' without having a "monitor"
(lock) held on the 'this' object. This is clearly stated in the Javadocs for
the method. Did you read them?

http://download.oracle.com/javase/6/docs/api/java/lang/Object.html#wait(long)
"The current thread must own this object's monitor."

You have to synchronize access to data shared between threads. This is a
rather large topic.

Read up on concurrent programming. Measure twice, cut once.
 
S

SamuelXiao

Don't use TAB characters to indent Usenet posts; use spaces (up to four per
level).

You have not synchronized access do 'Dice1' (variable names should start with
a lower-case letter) or 'Dice2'.

...

Read up on 'volatile', 'synchronized' and other concurrent-programming
constructs in Java.  Buy, read and study /Java Concurrency in Practice/ by
Brian Goetz, et al.


SamuelXiao said:
Thanks for youjr suggestion, I use wait() now, but it comes to another
problem.  I added wait() in the AITurn() method..Then now an exception
was caught..
    public void AIturn(int tempNumOfPlayers){
           long temp =  (long) (Dice1 + Dice2) * 100;
           btnRoll();
           SystemLogHelper.info("players.get(turn-1): " +
players.get(turn-1).getName());
           SystemLogHelper.info("players.get(turn-1).getPosition(): " +
                           players.get(turn-1).getPosition());
           try {
                   this.wait(temp);

Putting 'this.' in front of method calls is useless and misleading.


                   // notify();
                   // Thread.sleep(temp);
           }
           catch(InterruptedException  e){}
           if(propertymanager.Properties[players.get(turn-1).getPosition()]
[0] == 0){
                   SystemLogHelper.info("enter btnBuy()");
                   btnBuy();
           }
           btnDone(tempNumOfPlayers);
           // }
           // if(rolled)   btnDone(tempNumOfPlayers);
     }
// IllegalMonitorStateException
java.lang.IllegalMonitorStateException
   at java.lang.Object.wait(Native Method)
   at com.xxx.applet.MonopolyBoard.AIturn(MonopolyBoard.java:822)
   at com.xxx.applet.MonopolyBoard.btnDone(MonopolyBoard.java:485)

That exception is thrown when you call 'wait()' without having a "monitor"
(lock) held on the 'this' object.  This is clearly stated in the Javadocs for
the method.  Did you read them?

http://download.oracle.com/javase/6/docs/api/java/lang/Object.html#wa...)
"The current thread must own this object's monitor."

You have to synchronize access to data shared between threads.  This is a
rather large topic.

Read up on concurrent programming.  Measure twice, cut once.

for dice1 & dice2 both are primitive type. And only AITurn() method
need to wait. May I ask how can I wait until another thread finish?
From my search, it just tells 1 thread call another thread to wait
instead of one thread wait for another thread to finish...
 
S

SamuelXiao

theThreadYouWantFinished.join();

SOrry, I think my explanation is not clear. Because I use TimerTask
instead of thread, and for btnRoll()/btnDone() methods, these are in
fact the actionPerformed methods attached to those Roll/Done buttons,
I just wanna within the AITurn(), the btnRoll() will be finished
first(a timerTask is within it).
 
T

Travers Naran

long temp = (long) (Dice1 + Dice2) * 100;
btnRoll();
SystemLogHelper.info("players.get(turn-1): " +
players.get(turn-1).getName());
SystemLogHelper.info("players.get(turn-1).getPosition(): " +
players.get(turn-1).getPosition());
try {
this.wait(temp);
// notify();
// Thread.sleep(temp);
}
catch(InterruptedException e){}

// IllegalMonitorStateException
java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at com.xxx.applet.MonopolyBoard.AIturn(MonopolyBoard.java:822)
at com.xxx.applet.MonopolyBoard.btnDone(MonopolyBoard.java:485)
at com.xxx.applet.MonopolyEntry.actionPerformed(MonopolyEntry.java:
140)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.setPressed(Unknown Source)

seems that if I use wait(), these btnDone()/btnRoll() will be lost its
eventlistener? Is my understanding correct? I tried notify()/sleep()
and so on...but they doesn't work. wait() method can provide the token-
movement as I wanted but it is able to trigger btnDone() method

That's not how you use wait/notify. You've got it completely wrong,
Sam. Wait() is not some sort of sleep() command. It is part of a
synchronization system.

Please read:
http://download.oracle.com/javase/tutorial/essential/concurrency/index.html

Again, in your btnRoll() method, TimerTask is running in a SEPARATE
THREAD. I imagined you would figure out to do the synchronization in
btnRoll().

Your TimerTask needs to let your main thread know when it is done. So
think about two processes running beside each other with one process
waiting for the first process to finish.
 
L

Lew

SOrry, I think my explanation is not clear. Because I use TimerTask
instead of thread, and for btnRoll()/btnDone() methods, these are in
fact the actionPerformed methods attached to those Roll/Done buttons,
I just wanna within the AITurn(), the btnRoll() will be finished
first(a timerTask is within it).

There is no successful "just wanna" in concurrent programming. It is
not cookie-cutter programming. Again, take the time to study the
matter before you jump in. You haven't even read the Javadocs for the
methods you're using, much less the Java tutorials on concurrent
programming, much less any serious study. The answers that you have
already received give you study points. Go thou and study them!

You are not going to get a successful solution with a brief Usenet
answer. Answers here are signposts to further research. Don't ask us
to write your program for you. Do the work. Study the materials.
There is no shortcut.

None.
 
R

Roedy Green

Hi all, I am writing a simple monopoly board game, there're only 2
tokens, one is controlled by human, another by PC

The usual problem is the background task is not allowed to touch the
GUI. Only the Swing thread is. When the background thread wants to
modify the GUI, it must use invokeAndWait or invokeLater.

See http://mindprod.com/jgloss/thread.html and chase links.
--
Roedy Green Canadian Mind Products
http://mindprod.com
To err is human, but to really foul things up requires a computer.
~ Farmer's Almanac
It is breathtaking how a misplaced comma in a computer program can
shred megabytes of data in seconds.
 
M

markspace

The usual problem is the background task is not allowed to touch the
GUI. Only the Swing thread is. When the background thread wants to
modify the GUI, it must use invokeAndWait or invokeLater.

See http://mindprod.com/jgloss/thread.html and chase links.


Roedy has a point. javax.swing.Timer executes its tasks on the EDT, but
java.util.Timer does not. There's an unfortunate conicidence of class
names there; I think perhaps they should have named the former
javax.swing.SwingTimer or something.

Originally I thought that the OP was using javax.swing.Timer, but I no
longer think that is the case. Something else for him to fix up.
 
A

Arne Vajhøj

Timer runs TimerTask in a _separate_ thread. There are a few ways you
could synchronize this, but I'd recommend looking at wait()/notify().
Try to remember that you are waiting for your TimerTask to be called
Dice1+Dice2 times before you leave.

wait()/notify() is not exactly the easiest way to synchronize
in Java.

It is more like the most difficult.

synchronized keyword or or some of the stuff in java.util.concurrent
would be a lot easier to get right.

Arne
 
M

markspace

wait()/notify() is not exactly the easiest way to synchronize
in Java. ....
some of the stuff in java.util.concurrent
would be a lot easier to get right.


Specifically a CountDownLatch would be the way to go I think.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top