(Ответ обновлен для измененного вопроса.)
Как правило, вы должны профилировать код, прежде чем пытаться оптимизировать его, особенно если он довольно сложный.
Для многопоточности необходимо определить, какое изменяемое состояние разделяется между потоками.В идеале, насколько это возможно, прежде чем прибегать к блокировкам и параллельным структурам данных.Изменяемое состояние, которое содержится в одном потоке, не является проблемой как таковой.Неизменные значения - это здорово.
Я полагаю, что ничего, переданное вашей задаче, не будет изменено.Это сложно сказать.final
на полях - хорошая идея.Коллекции могут быть помещены в неизменяемые обертки, хотя это не останавливает их изменение с помощью других ссылок и теперь показывает себя в статических типах.
Предполагая, что вы не разбиваете внутренний цикл, единственная общая изменяемая переменнаясостояние выглядит как similarities
и содержащиеся в нем значения.
Вы можете или не можете обнаружить, что по-прежнему выполняете слишком много последовательных операций и вам нужно изменить similarities
, чтобы стать параллельным
ConcurrentMap<String, Set<String>> similarities = new ConcurrentHashMap<>();
get
и put
из similarities
должны быть поточно-ориентированными.Я предлагаю всегда создавать Set
.
Set<String> similarityWords = similarities.getOrDefault(seed, new HashSet<>());
или
Set<String> similarityWords = similarities.computeIfAbsent(seed, key -> new HashSet<>());
. Вы можете использовать потокобезопасный Set
(например, с Collections.synchronizedSet
), но я предлагаюудерживая соответствующую блокировку для всего внутреннего цикла.
synchronized (similarityWords) {
...
}
Если вы хотите создать similarityWords
лениво, то это будет «веселее».