Initial Anmerkung 1
Statt zu schaffen und Fäden von Hand starten, würde ich vorschlagen, einen Pool von Threads zu verwenden, die extern konfiguriert ist, so dass Sie die Anzahl der Threads verwalten, die erstellt. Wenn die Größe someList
1000 ist, ist die Erstellung so vieler Threads ineffizient. Sie sollten besser einen Executor verwenden, der von einem Thread-Pool unterstützt wird. Frühling bietet einige Implementierungen, die als Feder Bohnen mit dem task
Namespace, in etwa so konfiguriert werden, verwendet werden, können:
<task:executor id="executor" queue-capacity="10" rejection-policy="CALLER_RUNS" />
queue-capacity
die maximale Größe des Threads Pool. Wenn diese Größe überschritten wird, führt der aktuelle Thread die zusätzliche Task aus und blockiert so die Schleife, bis ein anderer Thread freigegeben wird (rejection-policy="CALLER_RUNS"
). Siehe die task:executor
Dokumentation, oder definieren Sie ThreadPoolExecutor
(Spring oder jdk-concurrent) mit Ihrer eigenen Konfiguration.
Initial Anmerkung 2
Wenn der einzige Staat, der Sie in MyClassImpl
ist das Element aus der Liste speichern wollen, dann können Sie den Rest der Erklärung unten vergessen (mit Ausnahme des Thread Sachen) und verwenden, um direkt eine Singleton-Bohne: entfernen Sie die Runnable
Schnittstelle und deren nicht argument run()
Methode, fügen Sie ein run(OtherClass obj)
Verfahren und etwas tun, wie folgt aus:
final MyInterface task = // get it from spring as a singleton
for (final OtherClass obj : someList) {
executor.execute(new Runnable() {
public void run() {task.run(obj);}
});
// jdk 8 : executor.execute(task::run);
}
Wenn Sie einige Zustand innerhalb MyClassImpl während der executi speichern möchten von run()
(außer dem verarbeiteten Objekt), lesen Sie weiter. Aber Sie werden immer noch die run(OtherClass obj)
Methode anstelle von No-Args run()
verwenden.
Die Grundidee besteht darin, für jeden laufenden Thread ein anderes Objekt zu erhalten, basierend auf einer Art von Modell oder Prototyp, die als Frühlingsbohne definiert ist. Um dies zu erreichen, definieren Sie einfach die Bean, die Sie zunächst an jeden Thread übergeben möchten, als Proxy, der an eine Instanz sendet, die an den laufenden Thread gebunden ist. Dies bedeutet, dass in jeden Thread die gleiche Task-Instanz eingefügt wird. Während der Thread-Ausführung ist die reale Task, auf die Sie Methoden anwenden, an den aktuellen Thread gebunden.
Hauptprogramm
Da Sie die Elemente der Liste sind mit Ihrem Unternehmen zu tun, werden Sie jedes Element auf seine Aufgabe zu besitzen passieren.
public class Program {
@Resource private MyInterface task; // this is a proxy
@Resource private TaskExecutor executor;
public void executeConcurrently(List<OtherClass> someList) {
for (final OtherClass obj : someList) {
executor.execute(new Runnable() {
public void run() { task.run(obj); }
});
// jdk 8 : executor.execute(task::run);
}
}
}
Wir vermuten, dass Program
eine Feder Bohne, damit die Abhängigkeiten injiziert werden kann. Wenn Program
keine Spring Bean ist, müssen Sie den Spring-Anwendungskontext von irgendwo herholen, dann autowire Program
(d. H. Abhängigkeiten in den ApplicationContext basierend auf Anmerkungen einfügen). So etwas wie dies (im Konstruktor):
public Program(ApplicationContext ctx) {
ctx.getAutowireCapableBeanFactory().autowireBean(this);
}
definieren die Aufgabe
<bean id="taskTarget" class="MyImplClass" scope="prototype" autowire-candidate="false" />
<bean id="task" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource">
<bean class="org.springframework.aop.target.ThreadLocalTargetSource">
<property name="targetBeanName" value="taskTarget"/>
<property name="targetClass" value="MyInterface"/>
</bean>
</property>
</bean>
taskTarget
, in dem Sie Ihr Unternehmen definieren. Diese Bean wird als Prototyp definiert, da jedem Thread eine neue Instanz zugewiesen wird. Dadurch können Sie sogar den Zustand speichern, der vom run()
Parameter abhängt. Diese Bohne wird niemals direkt von der Anwendung verwendet (also autowire-candidate="false"
), aber sie wird durch die task
Bean verwendet. In executeConcurrently()
oben wird die Linie task.run(obj)
tatsächlich auf einem der Prototyp taskTarget
, die von dem Proxy erstellt wurde, ausgelöst werden.
haben Sie das versucht? 'MyClass myClass = applicationContext.getBean (" myClass ");' –
werfen Sie auch einen Blick auf die Antwort dieser Frage. http://stackoverflow.com/questions/812415/why-is-springs-applicationcontext-getbean-considered-bad –
Wie ich verstehe - 'ApplicationContext.getBean' ist nicht IoC. Außerdem schlägt der von Ihnen vorgeschlagene Link eine Einzelinstanzlösung vor. dafür kann ich Inject annotaion verwenden - das ist allgemeiner (nicht federabhängig). –