taner armanc
taner armanc

Reputation: 3

Java monitoring an object with another object

I would like to say that I tried to find some answers on this site but I couldn't manage, also this is my first question so I am sorry if i wrote it off format etc...

I am trying to learn java and now trying to understand thread section. So far I understood some basics and I wanted to try this: a lieutenant class shares the monitor-lock with a soldier class but I am failing at somewhere.

Edit: I want to Lieutenant waits until the Soldier says his first line, then he gives an order. But when soldier tries to release lock I get an monitor error because of notify method. "Exception in thread "Thread-1" java.lang.IllegalMonitorStateException."

P.S: I know there are easier ways but I am trying to utilize wait&notify.

public class Lieutenant {
private boolean waitForCommand = true;
public void setWaitForCommand(boolean waitForCommand) {
    this.waitForCommand = waitForCommand;
}
public synchronized void giveOrder() {
    while (waitForCommand) {
        try {
            wait();
        } catch (InterruptedException e) {
            e.getStackTrace();
        }
        System.out.println("I said run soldier! RUN!");
    }}}




public class Soldier {
private final Lieutenant lieutenant;

public Soldier(Lieutenant lieutenant) {
    this.lieutenant = lieutenant;
}
public void getOrder() {
    synchronized (this.lieutenant) {
        System.out.println("Sir! Yes, sir!");
        lieutenant.setWaitForCommand(false);
        notifyAll();
    }}}


class Main {

public static void main(String[] args) {

    Lieutenant lieutenant = new Lieutenant();
    Soldier soldier = new Soldier(lieutenant);
    new Thread(new Runnable() {
        @Override
        public void run() {
            lieutenant.giveOrder();
        }}).start();

    new Thread(new Runnable() {
        @Override
        public void run() {
            soldier.getOrder();
        }}).start();
}}

Upvotes: 0

Views: 66

Answers (1)

Evan Jones
Evan Jones

Reputation: 886

The immediate problem here is with this method:

synchronized (this.lieutenant) {
        System.out.println("Sir! Yes, sir!");
        lieutenant.setWaitForCommand(false);
        notifyAll();
    }}

The synchronized block is holding a lock on this.lieutenant but you are attempting to call notifyAll() on this, which you aren't holding the lock on.

If make this change

synchronized (this.lieutenant) {
        System.out.println("Sir! Yes, sir!");
        lieutenant.setWaitForCommand(false);
        this.lieutenant.notifyAll();
    }}

It should work better. But as mentioned in the comments you can't guarantee that giveOrder will be called before getOrder.

Upvotes: 3

Related Questions