0

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

Под Результатами класса У меня есть синхронизируются LinkedHashMap такого как:

private static Map<Integer,Result> resultsHashMap=Collections.synchronizedMap(new LinkedHashMap<Integer, Result>()); 

и метод получения:

public static Map<Integer,Result> getResultsHashMap() { 
     return resultsHashMap; 
} 

а у меня есть в моем Результата класса конструктор с этим синхронизированным кодом:

public Result(){ 
    synchronized (Lock.lock) { 
     uniqueIdResult++; 
    } 
} 

и синхронизированным методом геттерного как таковые:

public static int getUniqueIdResult() { 
    synchronized (Lock.lock) { 
     return uniqueIdResult; 
    } 

} 

в uniqueIdResult определяются следующим образом:

private static int uniqueIdResult=0; 

Также у меня есть класс Lock состоит из этого объекта:

public static final Lock lock=new Lock(); 

Теперь это важная проблема, с которой я столкнулся. В моей программе у меня есть следующие 2 строки, которые создают результат и положить его в HashMap

Result result = new Result(); 
Results.getResultsHashMap().put(Result.getUniqueIdResult(), result); 

я пытаюсь запустить мою программу с различным количеством потоков. Когда он запускается с 1 потоком, выход выглядит так, как я ожидаю, (в частности, но не обязательно важно, Results.resultsHashMap содержит 433 ключа, что должно быть, и ключи начинаются с 1).

Но когда я запускаю его с различным количеством потоков, он дает другой выход. Например, работа с 6 нитями дает различное количество ключей каждый раз, иногда 430, иногда 428, иногда 427 и т. Д., А стартовый ключ не всегда связан с общим количеством ключей (например, total_number_of_keys-start_key_number + 1, что мне казалось, в самом начале, чтобы быть какой-то рисунок, но понял, что это не так)

итерация как это:

int counterOfResults=0; 
    for (Integer key : Results.getResultsHashMap().keySet()) { 
     System.out.println(key + " " + Results.getResultsHashMap().get(key)); 
     counterOfResults++; 
    } 
    System.out.println(counterOfResults); 

Также при синхронизации метод получения для получения Hashmap, без синхронизации из Создание результата и вставка в hashMap, вывод с несколькими потоками дает неправильный вывод.
Кроме того, при синхронизации только одной из строк (создание результата и внесение в hashMap), выход не является когерентным при использовании нескольких потоков.

Однако, когда я синхронизировать как эти строки (создание результата и положить на карту), как так:

Result result; 
    synchronized (Lock.lock) { 
     result = new Result(currentLineTimeNationalityNameYearofbirth.getName(),currentLineTimeNationalityNameYearofbirth.getTime(),citycompetionwas,date,distance,stroke,gender,kindofpool); 
     Results.getResultsHashMap().put(Result.getUniqueIdResult(), result); 
    } 

выход не является идеальным, независимо от того, сколько потоков я использую.

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

Так что мой вопрос:
Насколько я знаю, перед синхронизацией 2 строки (создание результата и кладя в HashMap) все мои критических секций, например, изменение и получение uniqueIdResult, получив resultsHashMap (как я уже упоминал, я попытался синхронизировать этот метод getter) также синхронизируются на одном и том же объекте, плюс я поставил еще один безопасный подход при установке hashMap с Collections.synchronizedMap, который, насколько я знаю, должен сделать hashMap потокобезопасным.

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

+1

«начиная с 4 (по крайней мере, когда я проверил)», что это значит? Похоже, вы не знаете, с какого числа он начинался. Предоставьте воспроизводимый код. – weston

+0

Я имел в виду, что в то время, когда я запускал программу на 4 потоках (около 10 раз), это был выход. Поскольку вывод не всегда когерентный (и с 6 потоками я заметил разные выходы при разных исполнениях), я предполагаю, что он мог бы также отличаться от числа. В любом случае я удалил эту часть из моего вопроса, так как это может быть неясно. –

ответ

4

Там не исключение вокруг этих линий:

Result result = new Result(); 
Results.getResultsHashMap().put(Result.getUniqueIdResult(), result); 

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

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

Вы, вероятно, следует удалить приращение из Result конструктора класса и вместо того, чтобы сделать это в getUniqueIdResult метод:

public static int getUniqueIdResult() { 
    synchronized (Lock.lock) { 
     return ++uniqueIdResult; 
    } 
} 

(нимало что, больше нет необходимости создавать экземпляры Result вообще) ,

 Смежные вопросы

  • Нет связанных вопросов^_^