Как правильно использовать коллекции VAVR, чтобы быть потокобезопасным?

Коллекции VAVR являются «неизменяемыми».

Итак, если у меня есть статическая переменная, например, содержащая все сеансы WebSocket, как мне использовать VAVR, чтобы коллекция была потокобезопасной?

Например:

@ServerEndpoint("/actions")
public class DeviceWebSocketServer {

    private static Set<Session> sessions = //???; // how should I initialize this?

    @OnOpen
    public void open(Session session) {
        sessions = sessions.add(session); // is this OK???
    }

    @OnClose
    public void close(Session session) {
        sessions = sessions.remove(session); // is this OK??
    }
}    

person Rafael Paulino    schedule 21.02.2018    source источник


Ответы (2)


Вы можете обернуть неизменную коллекцию vavr в атомарно обновляемый AtomicReference и используйте один из его методов обновления для атомарного обновления ссылки на неизменяемую коллекцию.

@ServerEndpoint("/actions")
public class DeviceWebSocketServer {

    private static AtomicReference<Set<Session>> sessionsRef = 
            new AtomicReference<>(HashSet.empty());

    @OnOpen
    public void open(Session session) {
        sessionsRef.updateAndGet(sessions -> sessions.add(session));
    }

    @OnClose
    public void close(Session session) {
        sessionsRef.updateAndGet(sessions -> sessions.remove(session));
    }

}

Обязательно прочтите javadoc AtomicReference< /a>, если вы собираетесь использовать их в других сценариях, так как есть некоторые требования к функциям обновления, которые необходимо соблюдать, чтобы получить правильное поведение.

person Nándor Előd Fekete    schedule 21.02.2018
comment
близко надо убрать? - person MariuszS; 22.02.2019

Для этого варианта использования вы также можете рассмотреть возможность использования параллельной карты:

@ServerEndpoint("/actions")
public class DeviceWebSocketServer {

    private static ConcurrentMap<String, Session> sessions = new ConcurrentHashMap<>();

    @OnOpen
    public void open(Session session) {
        sessions = sessions.putIfAbsent(session.getId(), session);
    }

    @OnClose
    public void close(Session session) {
        sessions = sessions.remove(session.getId());
    }

}
person Xavier Arias    schedule 22.02.2018
comment
Имейте в виду, что ConcurrentHashMap синхронизирует только метод сохранения. Методы чтения не блокируются, поэтому вы можете получить грязные значения с карты. - person eL_; 05.06.2020