Frage

Ich habe einige Java-Code, der eine Sitzung Attribut erhält und setzt:

Object obj = session.getAttribute(TEST_ATTR);
if (obj==null) {
  obj = new MyObject();
  session.setAttribute(obj);
}

Um diesen Code Thread-sicher zu machen, würde ich es gerne in einem synchronisierten Block wickeln. Aber was ich als das Verriegelungsobjekt verwenden? Ist es sinnvoll, die Sitzung zu benutzen?

synchronized (session) {
  Object obj = session.getAttribute(TEST_ATTR);
  if (obj==null) {
    obj = new MyObject();
    session.setAttribute(obj);
  }
}
War es hilfreich?

Lösung

Es ist allgemein verpönt, eine Sperre zu verwenden, die Sie keine Kontrolle haben. Eine Sperre soll möglichst dicht scoped werden und da die Sitzung mehr oder weniger ein globales Objekt ist, ist es nicht das Richtige. Versuchen Sie, ein separates Schloss aus dem

Andere Tipps

Im Rahmen von Servlets? Servlets kann auf mehrere Prozesse verteilt werden, deshalb kann man nicht immer die gleiche Session-Objekt haben. Eine logische Folge davon ist, dass ein Servlet-Container entscheiden können Sie im gleichen Prozess einen anderen Sitzungsobjekt geben.

IIRC, schrieb Brian Goetz einen interessanten Artikel über die Schwierigkeit, die Dinge richtig mit Sitzungen zu tun.

Mein Rat: Bleiben Sie von Sitzungen so viel wie möglich klar und sperrt nicht zufällige Objekte (ein Sperrobjekt verwenden, die keinen anderen Zweck hat)

.

Die Spezifikation garantiert nicht, dass dies überhaupt helfen:

synchronized (session) {
  Object obj = session.getAttribute(TEST_ATTR);
  if (obj==null) {
    obj = new MyObject();
    session.setAttribute(obj);
  }
}

(Es könnte für bestimmte Implementierungen arbeiten, aber es gibt keine Garantie, dass es in allen Containern arbeiten.)

Servlet 2.5 MR6 sagt:

  kann den aktiven Zugriff auf die gleiche Session-Objekt zur gleichen Zeit

Mehrere Servlets Anfrage Threads ausgeführt wird. Der Behälter muss, dass die Manipulation von internen Datenstrukturen sorgen für die Sitzung repräsentieren Attribute in einem THREAD Weise durchgeführt. Der Entwickler hat die Verantwortung für THREAD Zugriff auf das Attribut selbst Objekte. Dies wird die Attributsammlung innerhalb des Http Objekts aus dem gleichzeitigen Zugriff, wodurch die Möglichkeit für eine Anwendung zu schützen, dass die Sammlung korrumpiert werden.

Im Grunde macht die Spezifikation es Ihr Problem. Ihre Lösung muss auf Ihr Anwendungsdesign und Einsatzplan angepasst werden. Ich bin nicht sicher, dass es eine globale Lösung für das Problem ist, dass in allen Fällen funktionieren wird; Sie können jedoch eine bessere Antwort, wenn man präziser über die Architektur der Anwendung und Konfiguration des Anwendungsservers ist.

Ihr Code wird nicht für mindestens zwei Gründe arbeiten.

1) Wenn die Sitzung nicht existiert, dann könnte man es einfach erstellen zweimal für den gleichen Benutzer und hast eine hässliche Race-Bedingung.

2) Wenn die Sitzung nicht das gleiche Objekt über Threads ist, dann wird es sowieso nicht funktionieren. Die Sitzung wird wahrscheinlich auf die gleiche Sitzung in einem anderen Thread equals() werden, aber das wird nicht funktionieren.

Sie brauchen nicht zu sperren, da session.setAttribute() ist Thread-sicher (Servlet-Spezifikation Kommentar von @McDowell siehe oben).

Lassen Sie sich jedoch ein anderes Beispiel. wenn <= 100. In diesem Fall müssten Sie syncronize den Codeblock für die getAttribute() das Vergleichen von <= 100 und die setAttribute() Angenommen, Sie den Wert des Attributs, dann aktualisieren, es Chek wollte.

Nun, was sollten Sie für die Sperre zu verwenden? Denken Sie daran, es gibt keine syncronization wenn verschiedene Objekte für die Sperre verwendet werden. So unterschiedliche Codeblöcke müssen das gleiche Objekt verwenden. Ihre Wahl des session Objekt kann nur in Ordnung sein. Bedenken Sie auch, dass unterschiedliche Codeblöcke die Sitzung zugreifen kann (beide lesen / schreiben), auch wenn Sie eine Sperre genommen haben, es sei denn, dass andere Code auch auf dem Session-Objekt sperrt. Ein pitfall hier ist, dass zu viele Stellen im Code eine Sperre auf dem Session-Objekt übernehmen und damit zu warten. Zum Beispiel, wenn Ihr Code-Block-Session Attribut A verwendet und ein weiteres großes Stück Code verwendet Session B-Attribut, es wäre schön, wenn sie aufeinander warten müssen nicht durch beide eine Sperre auf dem Session-Objekt nehmen. Die Verwendung von statischen Objekten namens LockForA und LockForB könnte eine bessere Wahl für Ihren Code verwenden - zum Beispiel synchronized (LockForA) { }.

Ich hatte das gleiche Problem und wollte es nicht zu meiner Klasse Umfang, weil die Schaffung meiner Aufgabe könnte eine Sekunde dauern und Threads anderer Sitzungen Stall, wo das Objekt wurde bereits erstellt. Ich wollte nicht das Sitzungsobjekt der Anforderung verwenden, um auf zu synchronisieren, da die Implementierung der Anwendungsserver eine differen Sitzung Fassade in verschiedenen Anfragen zurückkehren könnte und einfach auf verschiedene Objekte zu synchronisieren funktioniert nicht. So wähle ich auf der Sitzung ein Objekt zu setzen als Sperre zu verwenden und das doppelte Kontrolle Idiom verwendet die Sperre, um sicherzustellen, wird nur einmal erstellt. Synchronisieren im Rahmen von MyObject ist kein Problem mehr, weil die Schaffung eines Objekts ist recht schnell.

Object lock = session.getAttribute("SessionLock");
if (lock == null) {
  synchronized (MyObject.class) {
    lock = session.getAttribute("SessionLock");
    if(lock == null) {
      lock = new Object();
      session.setAttribute("SessionLock", lock);
    }
  }
}
synchronized (lock) {
  Object obj = session.getAttribute(TEST_ATTR);
  if (obj==null) {
    obj = new MyObject();
    session.setAttribute(obj);
  }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top