1

I want to create a user defined SettableFutureObject. A user should call the get() method and has to wait until the Result-Object was set into this future object. My biggest problem is to make it threadsafe while reading and writing on a "state"-flag in this object.

My approach (corrected based on comments):

public class SettableFuture<T> implements Future<T> {

    private String status = "Wait";

    private T myObject = null;

    public synchronized T get() throws InterruptedException, ExecutionException {
        while (status.equals("Wait")) {
            wait();
        }
        return myObject;
    }

    public synchronized void set(T myObject) {
        this.myObject = myObject;
        status = "Done";
        notifyAll();
    }

    public synchronized boolean isDone() {
        if (!status.equals("Wait")) return true;
        return false;
    }

    public synchronized boolean isCancelled() {
        if (status.equals("Cancelled")) return true;
        return false;
    }

}

The Problem is, that i stuck into IllegalMontitorStateExceptions caused by the wait()-method of get(). I think some variables are not thread-safe. How can i optimize this wait/notifyAll-concept here?

Thanks

Appendix:

My TestProgram create a futureObject. Someone else (here a separate Thread) should set anytime a specific Object, get() is called and should wait until this object is set and then i want to operate on the futureObject and its content:

public class Tester {

    public static void main(String[] args) throws InterruptedException, ExecutionException {

        SettableFuture<MyObject> myFuture = new SettableFuture<MyObject>();

        new Thread( new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                    MyObject myObject = new MyObject("VALUE");
                    myFuture.set(myObject);
                } catch (Exception e) {}

            }
        }).start();

        MyObject o = myFuture.get();
        System.out.println(o);
    }

}

HelperObject:

public class MyObject {

    public String value = "none";

    public MyObject(String value) { this.value = value; }

    @Override 
    public String toString() { return value; }
}
Alex
  • 161
  • 1
  • 13
  • 1
    Your isDone and isCancelled methods are synchronized, but your get and set methods are not. This seems like a problem. – Joseph Larson Oct 31 '19 at 14:13
  • Hi, i have added an minimal example. There i did not use these two methods, but i will get a IllegalMonitorStateException anyway. But thanks for the advice. – Alex Oct 31 '19 at 14:24
  • 1
    IllegalMonitorStateException means you called `this.wait()` without being inside a `synchronized(this){...}` block. Just add `synchronized` to the method declaration to fix it. NOTE: the `wait()` call will release the lock on `this` before going to sleep, and then it will re-acquire the lock before it returns, so calls by other threads to other `synchronized` methods will not be blocked while the one thread is waiting. – Solomon Slow Oct 31 '19 at 14:30
  • I have added synchronized to set() and get(). Now it works. Thanks. – Alex Oct 31 '19 at 14:44
  • Btw, are there any other approaches to "implement" such a FutureObject? Or is "wait/NotifyAll" a good solution to be able to wait in a get()-Method until someone sets an object? – Alex Nov 02 '19 at 11:47

0 Answers0