Статический метод для доступа к нескольким потокам, Java - PullRequest
2 голосов
/ 05 марта 2010

Я использую стороннюю библиотеку для оценки рук в 7-карточном покере. Метод evaluate в этой библиотеке объявлен как public static, и я считаю, что он изменяет некоторые глобальные статические массивы в классе. Проблема, с которой я столкнулся, заключается в том, что, поскольку я делаю алгоритм перечисления из примерно 10-ти метровых перечислений, я хочу его распараллелить, поэтому я создал FutureTasks, каждая из которых оценивает часть 10-ти метровых оценок. Я получаю ошибку:

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)

Что из того, что я собираю из поисков Google, вызвано при попытке получить результат задачи, которая была прервана с помощью исключения.

Есть ли какой-нибудь способ сделать поток статического метода безопасным, например, чтобы каждый поток создавал свою собственную копию глобальных статических массивов, которые редактируются?

Спасибо

Ответы [ 8 ]

3 голосов
/ 05 марта 2010

Вы можете загрузить библиотеку в отдельном ClassLoader для каждого потока, чтобы каждый класс имел свой собственный набор классов и, следовательно, свой собственный набор статических переменных.

Если вы это сделаете, вы должны быть осторожны, чтобы гарантировать, что загрузчик родительских классов этих загрузчиков классов не имеет доступа к библиотеке.

2 голосов
/ 05 марта 2010

Если бы вы могли изменить код, вы могли бы сделать статические переменные поток локальными , но это не похоже на то, что вы можете изменить эту часть кода. Подробнее о нить локального хранилища (википедия)

1 голос
/ 05 марта 2010

Создание оболочки-экземпляра одиночного экземпляра для библиотеки с синхронизированным украшением метода в методе оценки

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);
0 голосов
/ 05 марта 2010

Имея миллионы рук для оценки, никогда не рано взглянуть на Распределенные вычисления Java .

Пока вы рассматриваете это другое хорошее предложение , вы можете заключить оценщик в простой однопоточный сервер и запустить столько JVM, сколько позволяют ресурсы.

Наконец, подумайте над написанием собственного оценщика;Вы можете проверить свои против существующего, и ваш может быть лучше!

0 голосов
/ 05 марта 2010

Используйте ConcurrentLinkedQueue или Collections#synchronizedList() вместо массива. Его доступ внутренне синхронизирован.

0 голосов
/ 05 марта 2010

Вы не можете сделать это поточно-ориентированным, но вы можете синхронизировать доступ к библиотеке:

static Object globalLock = new Object();

synchronize (globalLock) {
  evaluate();
}

Это означает, конечно, что только один поток может выполнять этот метод одновременно. Так что если ваша программа тратит много времени на этот метод, это вам не поможет.

Кроме того, вы можете запустить экземпляры в отдельных процессах. Но установление связи между процессами (через RMI или подобное) довольно болезненно.

Единственный другой вариант - переписать его, если вы обращаетесь к исходному коду. Вам нужно переместить все статические поля в один класс контекста, а затем убедиться, что весь код, который использовался для доступа к статическим полям, имеет ссылку на экземпляр нового класса контекста.

Уже упомянутый механизм ThreadLocal может помочь вам в этом, потому что это особый вид ссылок, который выглядит по-разному для каждого потока. Это может избавить вас от изменения сигнатур методов для передачи экземпляра объекту контекста. ИМХО, наверное, понятнее просто передать контекст в методы. С функциями рефакторинга современных IDE это не так сложно сделать.

0 голосов
/ 05 марта 2010

Если у вас есть метод, к которому обращаются несколько потоков с общим состоянием (глобальные статические массивы), вам необходимо убедиться, что к ним обращаются потокобезопасным способом.

Это означает, что вам нужно синхронизировать / блокировать как при чтении из этих массивов, так и при их записи.

По вашей трассировке стека звучит, что вы не являетесь *.1005 *

Если возможно, я бы посоветовал минимизировать или устранить количество состояний, разделяемых между потоками.

0 голосов
/ 05 марта 2010

Вы безопасно работаете с массивами? Можете ли вы объяснить структуру вашего кода лучше? Как вы распределяете работу и почему алгоритм должен модифицировать глобальный массив?

Независимо от того, возможно, было бы более разумным использовать ForkJoin или CyclicBarrier / Phaser для разделения работы?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...