shardulc
shardulc

Reputation: 301

Java Optimization with Threads

I'm using a custom class Foo in Java as the key type in a HashMap. All the fields of Foo instances are immutable (they are declared final and private and are assigned values only in the constructor). Thus, the hashCode() of a given Foo object is also fixed, and for optimization purposes, I am calculating it in the constructor and simply returning that value in the hashCode() method.

Instances of Foo also have a value() method which returns a similar fixed value once the object has been instantiated. Currently I am also calculating it in the constructor and returning it in the method, but there is a difference between hashCode() and value(): hashCode() is called for the first time almost instantly after the object is created, but value() is called much later. I understand that having a separate Thread to calculate the hash-code would simply increase the run-time because of synchronization issues, but:

Note: this may seem like I'm optimizing the wrong parts of my program, but I've already worked on the 'correct' parts and brought the average run-time down from ~17 seconds to ~2 seconds. Edit: there will be upwards of 5000 Foo objects, and that's a conservative estimate.

Upvotes: 4

Views: 517

Answers (2)

Zim-Zam O'Pootertoot
Zim-Zam O'Pootertoot

Reputation: 18148

I recommend creating a Future for value - create a static fixedTheadPool and submit the value calculations on it. This way there's no risk that value will be accessed before it's available - the worst case is that whatever is accessing value will block on a Future.get call (or use the version with a timeout if e.g. deadlock is a concern)

Because Future.get throws checked exceptions which can be a nuisance, you can wrap the get call in your class's getter method and wrap the checked exceptions in a RuntimeException

class MyClass {
    private static final ExecutorService executor = Executors.newFixedThreadPool(/* some value that makes sense */);

    private final Future<Value> future;

    public MyClass() {
        future = executor.submit(/* Callable */);
    }

    public boolean isValueDone() {
        return future.isDone();
    }

    public Value value() {
        try {
            return future.get();
        } catch(InterruptedException|ExecutionException e) {
            throw new RuntimeException(e);
        }
    }
}

Upvotes: 1

Oak
Oak

Reputation: 26868

It definitely sounds like deferred calculation is a good approach here - and yes, if you create a lot of these objects, a thread pool is the way to go.

As for value()'s return value until it's ready, I would stay away from returning invalid values, and instead either make it blocking (and add some isValueReady() helper) or make it instantly return a "future" - some object that offers those same isReady and a blocking get methods.

Also, never rely on "much later" - always make sure the value there is ready before using it.

Upvotes: 2

Related Questions