#java #multithreading #akka #concurrenthashmap
#java #многопоточность #akka #concurrenthashmap
Вопрос:
Для проекта класса я использую ConcurrentHashMap для хранения списка активных пользователей и сведений об их подключении. Несколько потоков должны иметь возможность получать список всех активных пользователей, при этом 5 потоков могут изменять хэш-карту. Когда я тестирую это, кажется, что это работает, но я не знаю, блокируются ли потоки и работает ли система достаточно быстро.
- Я хочу инкапсулировать ConcurrentHashMap, но я не знаю, остановит ли это его параллелизм?
Я также хочу, чтобы была только одна версия hashmap, поэтому я сделал класс перечисляемым, ужасным и просто получил main для его создания?- Я не хочу, чтобы другие потоки изменяли HashMap, поэтому я не передаю коллекцию / итератор. Есть ли способ передать коллекцию без удаления?
- (новое)Я вызвал два метода в CoolFeature, один блокирует, а другой нет. У обоих могут быть свои места. Есть ли какие-либо проблемы с тезисами?
Мы используем актеров Akka для создания потоков и обработки параллелизма, и мой упрощенный код приведен ниже. Это не вопрос о назначении, просто часть того, что я создаю в рамках проекта.
РЕДАКТИРОВАТЬ: я изменил код, и было бы неплохо иметь решение, которое не зависит от Akka, чтобы другие могли найти ответ полезным.
package server.management;
public class Sessions {
static final ConcurrentHashMap<Integer, Id<User>> sessions = new concurrentHashMap<>();
private Sessions() { }
}
public class SessionManager {
public static void create(int connection, Id<User> userId) {
// checks
Sessions.sessions.put(connection, userId);
}
public static Id<User> getUser(int connection) {
Id<User> userId = Sessions.sessions.get(connection);
return userId;
}
public static ArrayList<Id<User>> getActiveUsers() {
ArrayList<Id<User>> list = new ArrayList<>();
// Don't pass the sessions.values() directly because the Map can be modified.
for (Id<User> userId : Sessions.sessions.values()) {
list.add(userId);
}
return list;
}
// other methods
}
/* Another thread/akka actor class */
package server;
import server.management.SessionManager;
public class CoolFeature extends AbstractActor {
...
Id<User> client = SessionManager.getUser(1023);
// do stuff
CompletableFuture<ArrayList<Id<User>>> futureList =
CompletableFuture.supplyAsync(SessionManager::getActiveUsers);
// do stuff
ArrayList<Id<User>> list = futureList.get();
// do stuff
}
Ответ №1:
С akka actor вы можете поместить карту нормалей внутри субъекта в качестве состояния, и вам не нужно беспокоиться о параллельном доступе, потому что с actor model субъект обрабатывает только одно сообщение за раз. Вы можете сделать что-то вроде приведенного ниже. Код написан на Scala, но вы поняли мою идею.
object Manager {
case class Get(id: Int)
case object GetActive
case class Create(connId: Int, userId: Int)
}
class Manager extends Actor {
import Manager._
val sessions = mutable.Map[Int, Int].empty
override def receive = {
case Get(id) => sessions.get(id)
case GetActive => sessions.values
case Create(connId, userId) => sessions = (connId -> userId)
}
}
Дайте мне знать, если у вас возникнут какие-либо вопросы.
Комментарии:
1. Также обычно это плохая идея для кода внутри субъекта (что, я думаю, имеет в виду OP, когда они говорят «использование актеров Akka для создания потоков»), чтобы манипулировать тем же состоянием, которым манипулируют другие актеры.
2. Спасибо, создать субъекта было бы проще. Я просто подумал, что этот участник может получать много запросов и может быть бутылочным горлышком. @LeviRamsey да, ConcurrentHashMap блокирует разделы карты, когда к ней обращаются несколько потоков. Я надеялся, что это распределит нагрузку, чтобы не было большого горлышка бутылки.
3. Блокировка CHM будет надежной (она была протестирована приложениями JVM в течение многих лет, даже если я не знаю официальных доказательств корректности). Однако ничто не мешает действующему лицу вывести из-под контроля другого действующего лица. Если вас беспокоит узкое место, я бы рассмотрел возможность реализации параллельной карты с разделенными участниками (возможно, кластеризованными постоянными участниками, особенно если вы, возможно, захотите запустить несколько экземпляров для HA и т.д.)
4. @dean Как предположил Леви, можно использовать разделенных участников, например, участников кластеризации, если поступает огромное количество запросов. Всегда можно начать с простого решения для одного участника и протестировать его с приблизительной загрузкой.