I'm working on a little game (bomberman), using javafx. Basically, I have players which can plant bomb. The bomb has a duration (1500ms before explosion, for example).
So, when my player plant a bomb, I start a thread in the bomb, using a Thread.sleep(ms), and right after I notify the player that the bomb has exploded.
Thing is, my player can drop his bomb then move... But when the bomb explodes, it notify the instance of the player with the coordinate when the bomb was planted...
For example, if my player is in [2;2], plant a bomb, then move to [2;4], then the bomb explodes, my player goes back to [2;2]...
Anyone knows how could I actualize the instance of player my bomb is pointing to ... ?
Here's a sample of code :
public class Player{
public void putBomb(){
listBomb.add(new Bomb(this));
}
public void refresh(){
System.out.println(xCoordinate+" "+yCoordinate);
}
}
public class Bomb{
public Bomb(Player p){
observer=p;
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(1500);
notify();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
public void sendNotification(){
observer.refresh();
}
}
As your question is JavaFX specific, the recommendations on how to do this vary from a non-GUI Java program (because JavaFX has in-built concurrency assistance and a single-threaded application programming model).
You don't need another thread, you can use a PauseTransition.
public class Bomb{
public Bomb(final Player player){
PauseTransition pause = new PauseTransition(Duration.seconds(1.5));
pause.setOnFinished(event -> player.refresh());
pause.play();
}
);
If for some reason you didn't wish to use a transition and you want to use your own threading, then you should look use JavaFX concurrency utilities such as Task.
If you didn't want to use a Task, then you can still create your own thread or runnable, but ensure that any callbacks are made using Platform.runLater(). For example:
public class Bomb{
public Bomb(final Player player){
new Thread(() -> {
try {
Thread.sleep(1500);
Platform.runLater(() -> player.refresh());
} catch (InterruptedException e) {}
}
}).start();
}
}
Of the different approaches, I recommend the PauseTransition over the others as then you don't need to deal with concurrency details such as threading, which are easy to get wrong.
Your run method calls [this.]notify() without being synchronized on this. I would expect it to always throw an IllegalMonitorStateException.
Also, it's almost always a mistake to call notify() without also setting some variable that other threads can examine. The problem with notify() is that it does not do anything at all unless some other thread happens to be in a wait() call for the same object. Without proper synchronization, you have no way to guarantee that that will be true.
There's only one right way to use wait() and notify(), and that's in a design pattern that Oracle calls a guarded block. https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
Related
When I click the stop button on my GUI which invokes the code below through an event listener, the GUI stops responding. I know wait() has to be synchronized, but what is the correct way to invoke it? Thanks in advance!
public void actionPerformed(ActionEvent actionEvent) {
if(actionEvent.getSource().equals(ui.stop)) {
if(clickerThread != null) {
/*terminate() stops the while loop
running in the thread's run(); */
autoClicker.terminate();
synchronized(clickerThread) {
try {
clickerThread.wait();
ui.updateLabel("Idle", ui.state);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
This is how the thread was created in case it helps:
else if(actionEvent.getSource().equals(ui.play)) {
if(clickerThread == null) {
autoClicker= new AutoClicker();
clickerThread = new Thread(autoClicker);
clickerThread.start();
ui.updateLabel("playing", ui.state);
}
}
As you're finding out, calling wait() does not freeze the thread that it's called on (in fact it can be called on any "monitor" object -- thread or not), but rather the thread that its called in. Per the Object API (and do make it a habit to read the API before asking):
Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object.
Much better to give your clickerThread class a public method that the GUI can call that pauses and resumes execution. So perhaps you wish to give your clickerThread class a volitile boolean field that it checks when deciding whether to continue running or not, and then give the class a public method to set this field's value.
I'm doing a Snake game in Java. I have the basic functionability, but I want pause the game when I click on a button. But the problem I have is when I clic on this button, the game is paused, but when I click again the game doesn't recognize the controls. I have a method called Init, on this I initialize the thread "Hilo". I tried to make a second thread in which I put an actionPerformed for the button, but the problem continued, now I am more confused. Here is my code:
Thread hilo; //I declared the thread
String state=""; //It is for control de state (paused or no)
Runnable hiloFor = new Runnable()
{
public void run()
{
Thread actual = Thread.currentThread();
synchronized(actual)
{
do
{
//Game instructions (there are a lot of them)
if(state.equals("paused"))
{
actual.wait();
}
}while(!option.equals("Exit"));
}
}
};
//This is my action performed where I control if it is paused
public void actionPerformed(ActionEvent e)
{
if ( e.getSource() == btnPause )
{
if(state.equals("paused"))
{
cont(); //method for reactive the thread
state="";
}else if(state.equals(""))
{
state="paused";
}
}
}
If somebody can help me, I will be very glad, It has turned difficult to me.
To reactivate the Thread in wait() you must call notify() (or better notifyAll()) on the same object.
Your code looks like you expect to pause the Thread you call wait() on. This is not the case. wait() will always pause the thread making the call, not the object that is the target. You can use any object for the wait() / notifyAll() signaling, it just has to be the same object for both sides of the communication.
This pages has some good explanations: http://javamex.com/tutorials/synchronization_wait_notify.shtml
if(state.equals("paused"))
{
actual.wait();
}
This part actually pauses the thread, until it's told to start it's work again. I suppose what you wanted in this case is something like continue; in loop, which, although, is not a very elegant way to do this. More suitable way to do this would be using notify().
I'm hoping someone can help me with this. I've been searching for about a week for an answer to this issue, with no avail.
I currently have a custom thread class that implements Runnable, which I'd like to pause upon a key press. Based on my research, I've learned that the best way to go about this is by using wait() and notify(), triggered by a key that's using a key binding.
My question is, how can I get this to work? I can't seem to set up a key binding without something going wrong, and how I might implement wait() and notify() without running into a deadlock is beyond me.
wait and notify are meant to be used for synchronization. It seems to me that you wanted to use methods like Thread.suspend(), Thread.stop() and Thread.resume(), but those have been deprecated for the risk of problems with lock that they cause.
The solution is to use a helper variable that the thread will check periodically to see if it should be running, otherwise, yield(or sleep)
Why not to use suspend, stop or resume: http://docs.oracle.com/javase/6/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html
Simple solutions:
How to Pause and Resume a Thread in Java from another Thread
http://www.tutorialspoint.com/java/java_thread_control.htm
Here is a simple snapshot that might get you started :
class PausableThread extends Thread {
private volatile boolean isPaused;
#Override
public void run() {
while (true /* or some other termination condition */) {
try {
waitUntilResumed();
doSomePeriodicAction();
} catch (InterruptedException e) {
// we've been interrupted. Stop
System.out.println("interrupted. Stop the work");
break;
}
}
}
public void pauseAction() {
System.out.println("paused");
isPaused = true;
}
public synchronized void resumeAction() {
System.out.println("resumed");
isPaused = false;
notifyAll();
}
// blocks current thread until it is resumed
private synchronized void waitUntilResumed() throws InterruptedException {
while (isPaused) {
wait();
}
}
private void doSomePeriodicAction() throws InterruptedException {
System.out.println("doing something");
thread.sleep(1000);
}
}
So, you start your thread somewhere new PausableThread().start();
And then in your button/keypress listeners on UI thread you call
in OnPauseKeyPress listener mPausableThread.pauseAction();,
and for OnResumeKeyPress you call mPausableThread.resumeAction();
To stop the tread altogether, just interrupt it : mPausableThread.interrupt();
Hope that helps.
i have just attempted to add something to my game where if one player is hit by a bullet his health goes down. problem is when i am checking for this, CPU is at 100% and everything sooo laggy. This is a problem. here is the thread i am using:
package Graphics;
import java.util.logging.Level;
import java.util.logging.Logger;
public class BulletCollision implements Runnable {
Player1 player1 = new Player1();
Player2 player2 = new Player2();
public Thread checkBulletCollision = new Thread(this);
public void checkPlayerBulletCollide() {
if (player2.getBulletX() > player1.getX() &&
player2.getBulletX() < player1.getX() - 50) {
player2.decHealth(50);
}
}
#Override
public void run() {
while(true) {
checkPlayerBulletCollide();
try {
checkBulletCollision.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(BulletCollision.class.getName()).log(
Level.SEVERE, null, ex);
}
}
}
}
i am pretty sure this is where the problem is. there are no errors when compiled or ran. if anyone could help that would be amazing! and i just make this class so the code is not perfect. i have tried a lot to fix this, the Threads start() method is being called in my Display class which only displays the JFrame. i previously had the start method in one of my player classed.
The problem is not in this code. There are one or two flaws, but nothing in this code that would result in laggyness ... as far as I can tell.
FWIW, the flaws are as follows:
1) This is bad style:
checkBulletCollision.sleep(100);
The Thread.sleep method is static, so you should invoke it as:
Thread.sleep(100);
2) Your thread run() method should return if it receives an interrupt. You have coded it to keep going ... which would defeat the purpose of interrupting it.
In my opinion, using this block free running in a separate thread is not correct in this case.
while(true) {
checkPlayerBulletCollide();
try {
checkBulletCollision.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(BulletCollision.class.getName()).log(Level.SEVERE, null, ex);
}
}
I'd only do this once each frame, I'd call the checkPlayerBulletCollide() from the drawing logic.
Also note that Thread.sleep() is a static function, so you can't make a specific Thread instance sleep from another Thread, a Threac can just put itself to sleep...
EDIT If you would like to code nice and clean (which is very good), I'd advise using the locking mechanisms we have from Java 1.5 on.
Even though this is (in the current context of 2 users with 1 bullet each) not lightweight ebough, I'd use a BlockingQueue. The checking thread would have to issue a queue.take(), but the actual Integer value wouldn't matter (later on e.g. with more bullets or players, you could put objects in the queue that specify which bullets and which users to check...). The drawing logic - or the logic controlling the drawing would do queue.offer(0). The checking Thread would look like this:
public class BulletCollision implements Runnable{
Player1 player1 = new Player1();
Player2 player2 = new Player2();
public BlockingQueue<Integer> checkQueue = new LinkedBlockingQueue<Integer>();
public void checkPlayerBulletCollide() {
if(player2.getBulletX() > player1.getX() && player2.getBulletX() < player1.getX() -50) {
player2.decHealth(50);
}
}
#Override
public void run() {
while(true) {
try {
queue.take();
checkPlayerBulletCollide();
} catch (InterruptedException ex) {
Logger.getLogger(BulletCollision.class.getName()).log(Level.SEVERE, null, ex);
break; //I'd put this here. If we were interrupted, the hread should stop gracefully.
}
}
}
}
Also, when you're done with drawing a frame, you should issue a queue.offer(0);
I'm having some issues with java multithreading, best explained on an example:
class Thread1 extends Thread
{
boolean val=false;
public void set()
{
val=true;
}
public void run()
{
while (true)
{
if(val==true)
{
System.out.println("true");
val=false;
}
try
{
sleep(1);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
So this is a simple class which is ran in a separate thread.
Now consider this case:
1) I start the thread in the class above
2) from some other thread I call the Thread1.set() function
3) the condition on the Thread1.run() function evaluates to true
Now, the thing is that if I remove the sleep(1) from the above code, this condition is never set to true.
So my question is: is there any other way I can interrupt the run() function so that
other functions may set the variables that would be used inside the run()function?
(I'm making a game on Android, so the openGL renderer runs in one thread and my game logic thread would run in another thread and I would like to sync them every frame or two),
If only a single thread (i.e. one other than the thread reading it) is modifying val, then make it volatile.
Your boolean variable is not volatile which means there is no guarantee that two different threads are seeing the same value. By sleeping it the virtual machine might cause the value set from a different thread to become visible to the thread (this is a guess - nothing more), but this behavior should not be relied upon in any way. You should either use a volatile boolean variable or an AtomicBoolean class depending on your needs.