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.
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.
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:
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.
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% 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.
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.
Tags und Links java multithreading spring