Я запустить программу, которая содержит следующие классы (не только, но эти значимых из них на вопрос)синхронизируются на объекте кажется, что это не синхронизированы
Под Результатами класса У меня есть синхронизируются 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 потокобезопасным.
Почему тогда выход не такой, какой я ожидаю? Где проблема безопасности?
«начиная с 4 (по крайней мере, когда я проверил)», что это значит? Похоже, вы не знаете, с какого числа он начинался. Предоставьте воспроизводимый код. – weston
Я имел в виду, что в то время, когда я запускал программу на 4 потоках (около 10 раз), это был выход. Поскольку вывод не всегда когерентный (и с 6 потоками я заметил разные выходы при разных исполнениях), я предполагаю, что он мог бы также отличаться от числа. В любом случае я удалил эту часть из моего вопроса, так как это может быть неясно. –