Est la synchronisation au sein d'une HttpSession faisable?

Mise à JOUR: Solution de droit après la question.

Question:

D'habitude, la synchronisation est la sérialisation des demandes parallèles à l'intérieur d'une JVM, par exemple

private static final Object LOCK = new Object();

public void doSomething() {
  ...
  synchronized(LOCK) {
    ...
  }
  ...
}

Lorsque l'on regarde les applications web, une synchronisation sur "JVM" portée globale est peut-être de devenir un goulot d'étranglement des performances et de la synchronisation uniquement dans le champ d'application de l'utilisateur HttpSession aurait plus de sens.

Est le code suivant une possibilité? Je doute que la synchronisation sur l'objet de session est une bonne idée, mais il serait intéressant d'entendre vos pensées.

HttpSession session = getHttpServletRequest().getSession();
synchronized (session) {
  ...
}

Question Clé:

Est-il garanti que l'objet session est la même instance pour tous les threads de traitement des demandes provenant de la même utilisateur?

Résumé de réponse /solution:

Il semble que l'objet de la session elle-même n'est pas toujours le même, puisqu'il dépend de la mise en œuvre du conteneur de servlet (Tomcat, Glassfish, ...) et la getSession() méthode peut retourner juste un wrapper instance.

Il est donc recommandé d'utiliser une variable personnalisée stockées dans la session pour être utilisé comme objet de verrouillage.

Voici mon code de la proposition, commentaires sont les bienvenus:

quelque part dans une Classe d'assistance, par exemple MyHelper:

private static final Object LOCK = new Object();

public static Object getSessionLock(HttpServletRequest request, String lockName) {
    if (lockName == null) lockName = "SESSION_LOCK";
    Object result = request.getSession().getAttribute(lockName);
    if (result == null) {
        //only if there is no session-lock object in the session we apply the global lock
        synchronized (LOCK) {
            //as it can be that another thread has updated the session-lock object in the meantime, we have to read it again from the session and create it only if it is not there yet!
            result = request.getSession().getAttribute(lockName);
            if (result == null) {
                result = new Object();
                request.getSession().setAttribute(lockName, result);
            }
        }
    }
    return result;
}

et puis vous pouvez l'utiliser:

Object sessionLock = MyHelper.getSessionLock(getRequest(), null);
synchronized (sessionLock) {
  ...
}

Des commentaires sur cette solution?

  • double possible de Est HttpSession thread-safe, sont set/get Attribut thread-safe opérations?
  • Il n'est pas un doublon comme lié question est au sujet de la sécurité des threads de variables de session. Je me demande si vous pouvez verrouiller la session de l'objet lui-même.
  • Je suis en désaccord, l'OP demande quel est l'objet qui est sûr pour être utilisé pour HttpSession de synchronisation/verrouillage, pas de savoir si HttpSession est thread-safe ou pas.
  • Dans le doute, vous pourriez mettre une propriété dans votre session, juste pour le verrouillage. Sachez cependant, que synchronized ne fonctionnera pas si vous utilisez un cluster avec la réplication de session et lorsque plusieurs demandes pour la même session sont traitées par des serveurs différents.
  • comme l'extrait de code dans ma question? J'ai mis à jour avec une solution possible.
  • Oui, c'est ce que j'avais à l'esprit. Avec moins de verrouillage pour ajouter la propriété, si. 🙂 En fonction de votre framework web, vous pouvez essayer de mettre le verrou de l'objet dans le contexte de session immédiatement après la création de session.
  • Oui, pensé à ça aussi, mais de cette façon, si le verrou de l'objet est disponible dans la session, le verrouillage global n'est plus utilisé, donc il ne devrait pas être que beaucoup de pertes de performances dans ce cas (mais le code est moche, je sais).
  • Le VERROUILLAGE global de l'objet est nécessaire dans votre cas (sinon deux demandes de la même utilisateur avec le même session peut créer différents SESSION_LOCK objets), et de l'omi, il va créer une certaine perte de performances puisque toutes les demandes (même à partir de différents utilisateurs) sera sérialisé.
  • La meilleure façon (omi), comme décrit dans la accepté de répondre, est à l'aide de la HttpSessionMutexListener en combinaison avec WebUtils.getSessionMutex(session) pour obtenir le verrou approprié. Dans ce cas, le seul problème pourrait être si deux demandes de session de l'utilisateur même essayer de créer une session (je ne vois pas de Printemps à l'aide d'un verrou global pour cela), ce qui devrait arriver avec une petite probabilité que votre cas.
  • J'aime votre propsed solution; il est robuste et offre des sessions multiples verrous à des fins différentes (une très bonne idée). Mais au lieu de l'ajouter à votre question, vous devez l'ajouter comme une réponse ci-dessous dans son propre droit; de cette façon, je peut voter votre réponse ainsi que votre question. 🙂

InformationsquelleAutor basZero | 2012-03-21