web-dev-qa-db-fra.com

Le thread HttpSession est-il sûr, les opérations set-get Attribute-thread sont-elles sécurisées?

De plus, l'objet qui est défini doit-il être thread-safe afin de garantir que nous savons quel est l'état de l'objet stocké dans la session.

De plus, je lisais sur le Web que certains suggèrent d'utiliser:

synchronized(session) {
  session.setAttribute("abc", "abc");
}

Est-ce une suggestion valable?

52
Berlin Brown

Non, ils ne sont pas sûrs pour les threads, selon IBM - Théorie et pratique Java: toutes les applications Web avec état sont-elles cassées? . Vous devez synchroniser.

Comment HttpSession n'est pas sûr pour les threads from Java Ranch pourrait également être utile.

36
duffymo

Spécification Servlet 2.5:

Plusieurs servlets exécutant des threads de demande peuvent avoir un accès actif au même objet de session en même temps. Le conteneur doit garantir que la manipulation des structures de données internes représentant les attributs de session est effectuée de manière sécurisée pour les threads. Le développeur est responsable de l'accès threadsafe aux objets d'attribut eux-mêmes. Cela protégera la collection d'attributs à l'intérieur de l'objet HttpSession d'un accès simultané, éliminant ainsi la possibilité pour une application de corrompre cette collection.

C'est sûr:

// guaranteed by the spec to be safe
request.getSession().setAttribute("foo", 1);

Ce n'est pas sûr:

HttpSession session = request.getSession();
Integer n = (Integer) session.getAttribute("foo");
// not thread safe
// another thread might be have got stale value between get and set
session.setAttribute("foo", (n == null) ? 1 : n + 1);

Ce n'est pas garanti pour être sûr:

// no guarantee that same instance will be returned,
// nor that session will lock on "this"
HttpSession session = request.getSession();
synchronized (session) {
  Integer n = (Integer) session.getAttribute("foo");
  session.setAttribute("foo", (n == null) ? 1 : n + 1);
}

J'ai vu cette dernière approche préconisée (y compris dans les livres J2EE), mais elle n'est pas garantie de fonctionner par la spécification Servlet. Vous pourriez tiliser l'ID de session pour créer un mutex , mais il doit y avoir une meilleure approche.

63
McDowell

Et comme vous ne voulez pas que le même client (avec session) effectue des requêtes simultanées, vous devez sérialiser ces requêtes comme le fait AbstractController dans Spring MVC.

4
cherouvim

À certains égards, cela dépend de la conception de votre client.

Avez-vous la possibilité, dans votre conception Web, qu'un seul client ait plusieurs demandes simultanées en suspens en utilisant la même session HTTP? Cela semble difficile à faire sauf si vous liez une seule session HTTP à plusieurs sockets. (aka, AJAX) À défaut de cela, l'accès HTTP d'un client donné sera monothread en ce qui concerne le serveur, ce qui signifie qu'une seule session est effectivement Thread safe.

La synchronisation de vos objets de session rendra l'application plus sûre contre les changements futurs qui rendront votre application Web capable d'avoir plusieurs demandes simultanées, donc ce n'est pas une mauvaise idée. Dans les implémentations modernes Java Java, la synchronisation n'a pas le coût élevé qui lui était précédemment associé, en particulier lorsque la synchronisation n'est généralement pas souhaitée. Si votre application utilise AJAX, ce qui implique que vous vous attendez à plusieurs envoyez des requêtes simultanées à votre serveur Web, puis la synchronisation est un must.

3
Eddie

Ce n'est pas le cas, mais la plupart du temps, vos clients n'y accèdent qu'avec un seul thread.

Différents clients auront des threads différents et chacun aura sa propre session.

Comme le souligne Eddie, une situation où vous pouvez rencontrer deux threads accédant à la même session est que deux appels ajax tentent de modifier le même attribut de session. Sinon, vous n'aurez aucun problème.

2
OscarRyz

La session n'est pas sécurisée pour les threads et les méthodes get not the set ne sont pas garanties pour les threads. En général, dans un conteneur de servlet, vous devez supposer être dans un environnement multi-thread et aucun outillage fourni n'est sûr.

Cela vaut également pour les objets que vous stockez dans la session. La session elle-même ne manipulera pas l'objet stocké mais vous pouvez récupérer l'objet dans un thread différent et tenter de le manipuler. C'est à vous d'examiner votre propre code pour voir si les conditions de course sont possibles.

L'exemple de code que vous avez publié est valide, mais le problème peut exister au-delà de la portée limitée de votre exemple. Il garantit qu'il n'y a aucune condition lors de la définition de la session, mais rien n'empêche un autre thread de remplacer l'ensemble. Si le code dans votre demande dépend de la valeur restée inchangée, vous pourriez toujours avoir des problèmes.

1
DefLog