0

I'm making a platformer in which I make the player jump by, every 30ms, adding a small amount of force upwards. I thought I'd use multi-threading, as I've done a little bit of it before and it seemed simple enough. Anyway, I tried this:

public void jump() {
    new Runnable() {
        public void run() {
            for (int i = 0; i <= jumpForce; i++) {
                velocity.y++;
                System.out.println("Adding force");
                try {
                    wait(30);
                } catch (InterruptedException e) {}
            }
        }
    }.run();
}

Now, what I thought this would do is every loop from 0 to jumpForce (in this case 50), it adds 1 onto the y velocity variable then waits 30ms, but what actually happens is I get an error called:

java.lang.IllegalMonitorStateException

and I have no idea what this means so can someone tell me what I'm doing wrong?

Zac G
  • 125
  • 2
  • 17
  • you need to `implement Runnable` in the class deceleration. Did you do that? – Ashwin Gupta Feb 15 '16 at 22:23
  • on which class? The Runnable or the class which contains `jump()`? – Zac G Feb 15 '16 at 22:24
  • 1
    Calling `Runnable#run()` alone isn't enough to create a new thread. You need to create a `Thread` from your runnable, then `start()` it. – FThompson Feb 15 '16 at 22:25
  • Why not a `ScheduledExecutorService`? And you are not actually "multithreading", since the thread is the same that started the runnable. – Enrichman Feb 15 '16 at 22:25
  • 2
    Possible duplicate of [Java Wait and Notify: IllegalMonitorStateException](http://stackoverflow.com/questions/7126550/java-wait-and-notify-illegalmonitorstateexception) – nkukhar Feb 15 '16 at 22:25

3 Answers3

1

The javadoc says for wait :

This method should only be called by a thread that is the owner of this object's monitor. See the notify method for a description of the ways in which a thread can become the owner of a monitor.

you own a monitor with a synchronized block, change your code to :

synchronized (this) {
  wait(30);
}
Jérémie B
  • 10,611
  • 1
  • 26
  • 43
  • I have answered to the IllegalMonitorStateException - your question. but see the other answer : your code is not multithreaded, creating a Runnable is not enough – Jérémie B Feb 15 '16 at 22:31
1

If you want to execute this code in a different thread, than you should NOT invoke the run() method of the Runnable. What you should do is create an instance of a thread and put your Runnable implementation in its constructor. Then invoke .start().

 public void jump() {
        new Thread(new Runnable() {
            public void run() {
                for (int i = 0; i <= jumpForce; i++) {
                    velocity.y++;
                    System.out.println("Adding force");
                    try {
                        Thread.sleep(30);
                    } catch (InterruptedException e) {}
                }
            }
        }).start();
    }

Also you should sleep() the thread in this case rather than wait(), because you have not taken the object lock. In order to implement what you need using wait(), the method jump() must be synchronized and another thread must invoke it.

Krasimir Stoev
  • 1,734
  • 11
  • 9
0

You are not multithreading, because you are not creating any threads.
The Runnable is running in the same thread that is going to run it. If you want to create a new Thread you have to explicitly do so with new Thread(new Runnable()) and use Thread#start().

Anyway, you probably just want to schedule a task so better to use a ScheduledExecutorService:

ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();
ex.scheduleAtFixedRate(new Runnable() {
    @Override
    public void run() {
        // do something
    }
}, 0, 30, TimeUnit.SECONDS);
Enrichman
  • 11,157
  • 11
  • 67
  • 101
  • It's used to run the Runnable every 30s. So you don't have to wait and loop. It will just run again the Runnable. – Enrichman Feb 15 '16 at 22:34