views:

459

answers:

8

Hi,

I am using a third party library to do hand evaluation of 7 card poker hands. The method evaluate in this library is declared as public static and I believe it alters some global static arrays within the class. The problem I have is that as I am doing an enumeration algorithm of about 10m enumerations I want to parallelize it, therefore I created FutureTasks which each which evaluate a fraction of the 10m evaluations. The error I am getting is:

java.util.concurrent.ExecutionException: java.lang.ArrayIndexOutOfBoundsException: -2147483648
    at java.util.concurrent.FutureTask$Sync.innerGet(Unknown Source)
    at java.util.concurrent.FutureTask.get(Unknown Source)

Which from what I gather from Google searches is caused when attempting to retrieve the result of a task that aborted by throwing an exception.

Is there some way to make this static method thread safe, like each thread making a its own copy of the global static arrays that are being edited?

Thanks

+2  A: 

If you could modify the code you could make the static variables thread local, but it doesn't sound like you can modify this part of the code. More on thread local storage (wikipedia)

Kris
what is thread-local and does it have and advantages over making the variables and method non-static. I say this as I might be able to get hold of the source code
Aly
Check the link. A thread local static variable is a static variable local to a thread (i.e. each thread has its own value for it, but otherwise it behaves as a static).
Kris
@Aly if you can get hold of the source code then you simply need to add the 'synchronized' keyword to the declaration of the evaluate method (and any other publicly accessible method that alters the affected static state).
ptomli
@ptomli while that would work, it would probably destroy all the advantages of running parallel threads (assuming that this data structure is integral to the calculations being done)
Kris
@Kris that's kind of the point. if the data needs be modified to calculate the value, you need to have synchronized access. if it's not necessary to modify the data, then you don't need to. the lib author is either trying to maintain state of the card table, or needlessly modifying date. i suggest Aly is not in a position to determine which, thus all he "needs" to do is add synchronization.
ptomli
+2  A: 

You could load the library in a separate ClassLoader for each thread, to ensure that each class has its own set of classes and therefore its own set of static variables.

If you do so, you must be careful to ensure that the parent class loader of those class loaders hasn't got access to the library, however.

Joachim Sauer
could you provide a small toy example?
Aly
See also http://java.sun.com/developer/onlineTraining/Security/Fundamentals/magercises/ClassLoader/help.html
trashgod
A: 

Are you operating on the arrays safely? Can you explain the structure of you code better? How are you dividing up the work and why does the algorithm need to modify a global array?

Regardless, maybe using ForkJoin or a CyclicBarrier/Phaser to divide up the work would make more sense?

Jeremy
I'm not operating on the arrays, I am calling a static method in a third party library which operates on arrays in a non thread-safe manor
Aly
A: 

If you have a method being accessed by multiple threads with shared state (global static arrays), you need to make sure that they are accessed in a thread-safe manner.

This means that you need to synchronize/lock both when you read from these arrays and also when they are written to.

It sounds, just from your stacktrace, that you are not.

If possible, I would suggest minimizing or eliminating the amount of state shared between threads.

matt b
A: 

You can't make it thread-safe, but you could synchronize access to the library:

static Object globalLock = new Object();

synchronize (globalLock) {
  evaluate();
}

That means, of course, that only one thread can execute this method at a time. So if your program spends a lot of time in that method, it won't help you.

Alternatively, you could make the instances run in separate processes. But establishing communication between the processes (via RMI or similar) is quite painful.

The only other option is to rewrite it, if you access to the source code. You'd have to move all static fields into a single context class, and then make sure that all code that used to access the static fields has a reference to an instance of the new context class.

The already mentioned ThreadLocal mechanism can help you with this, because it is a special kind of reference that looks different to every thread. This may save you from modifying method signatures to pass an instance to the context object. IMHO it's probably cleander to just pass the context into the methods. With the refactoring functions of modern IDEs it's not that difficult to do.

Tim Jansen
A: 

Create a singleton instance wrapper for the library with a synchronized method decoration on the evaluate method

public final class SynchronizedHandEvaluator {
    private static final SynchronizedHandEvaluator INSTANCE = new SynchronizedHandEvaluator();
    public static final getInstance() {
      return INSTANCE;
    }
    private SynchronizedHandEvaluator() { }

    public synchronized int evaluate(Card[] hand) {
        return ExternalLibrary.evaluate(hand);
    }
}


// then just use the wrapper as you would expect
int result = SynchronizedHandEvaluator.getInstance().evaluate(hand);
ptomli
A: 

Use ConcurrentLinkedQueue or Collections#synchronizedList() instead of array. Its access is internally synchronized.

BalusC
A: 

With millions of hands to evaluate, it's never too soon to look at Java Distributed Computing.

While you consider this other good suggestion, you could wrap the evaluator in a simple, single-threaded server and fire up as many JVMs as resources allow.

Finally, consider writing your own evaluator; you can test yours against the existing one, and yours may be better!

trashgod