Spring Beans verhalten sich wie ThreadLocal-Instanzen für einen ExecutorService

8

In meiner Webanwendung habe ich einen Hintergrunddienst. Dieser Dienst verwendet die Generator-Klasse, die eine Engine-Klasse und ein ExecutorService enthält, das für die Verwendung mehrerer Threads konfiguriert ist und GeneratorTasks akzeptiert.

%Vor%

Die Engine-Klasse benötigt eine lange Initialisierungsphase, daher möchte ich sie idealerweise nur einmal pro Thread initialisieren. Ich kann es nicht einfach zu einer Singleton-Instanz machen, weil die Instanz nicht über mehrere Threads hinweg geteilt werden kann (sie beruht auf sequentieller Verarbeitung). Es ist jedoch vollkommen in Ordnung, die Instanz nach dem Abschluss einer Verarbeitungsaufgabe erneut zu verwenden.

Ich habe daran gedacht, die Variable private Engine heavyEngine zu einer ThreadLocal-Variablen zu machen. Ich bin aber auch neu bei Spring, also habe ich mich gefragt, ob es vielleicht eine andere Möglichkeit gibt, ThreadLocal-Variablen mithilfe von Spring-Annotationen zu injizieren. Ich habe versucht, die Bean auf request scope zu beschränken, aber ich bin mir nicht sicher, wie ich das bei meinem Design angehen sollte.

Jede Anleitung zur Verbesserung meines Designs wäre willkommen.

    
Jensen Ching 27.09.2012, 03:00
quelle

3 Antworten

9

Als erstes: ThreadLocal - in dieser Klasse ist etwas Furchtbares. Was Sie brauchen, ist nur Objekt-Pooling. Es ist kein bekanntes Feature, aber Spring unterstützt dies auch:

%Vor%

Wenn Sie jetzt engine injizieren, erhalten Sie tatsächlich ein Proxy-Objekt ( Engine benötigt eine Schnittstelle), das alle Aufrufe an ein freies Objekt im Pool delegiert. Die Poolgröße ist konfigurierbar. Natürlich hindert Sie nichts daran, ThreadLocalTargetSource zu verwenden. , die ThreadLocal anstelle von Commons Pool verwendet. Beide Ansätze garantieren einen exklusiven, threadsicheren Zugriff auf Engine .

Schließlich können Sie das Pooling manuell verwenden (aber das Schöne an Lösung ist, dass es vollständig transparent ist) oder zu EJBs wechseln, die per Definition zusammengefasst werden.

    
Tomasz Nurkiewicz 27.09.2012, 15:58
quelle
5

Spring 3.0 und später enthalten

SimpleThreadScope .

Um es zu verwenden, müssen Sie einen benutzerdefinierten Bereich registrieren:

%Vor%

Und dann um eine threadspezifische Bean zu deklarieren:

%Vor%     
helmy 12.11.2014 21:13
quelle
1

Ich hätte eine Factory für Engine erstellt und sie in GeneratorTask umbenannt. Auf diese Weise können Sie das heavyEngine -Feld in Generator und das Generator -Konstruktor-Argument in GeneratorTask entfernen.
Wenn Sie dann die Initialisierungszeit von Engine speichern möchten, können Sie sie trotzdem als Singleton deklarieren, aber das Schlüsselwort synchronized für nicht threadfähige Methoden verwenden.

%Vor%

Es gibt wahrscheinlich einen reinen Frühlingsweg, um den Motor an das Callable zu übergeben, aber in diesem Fall ist die Fabrik meines Erachtens gut genug.

    
a.b.d 27.09.2012 04:08
quelle

Tags und Links