2017-09-04 7 views
2

Ich muss einen globalen ThreadPoolTaskExecutor in meiner Spring-Anwendung erstellen, die für das Ausführen von Multithread-Aufgaben in meiner Anwendung verantwortlich sein wird.Controlled ThreadPoolExecutor in Java Spring

Allerdings möchte ich für jede Anfrage die Anzahl der verwendeten Threads von diesem globalen ThreadPool begrenzen. Wie soll ich sicherstellen, dass diese Beschränkung pro Anfrage durchgesetzt wird?

Für z.

Ich erstelle einen globalen Thread-Pool mit einer maximalen Poolgröße von 50 Threads. Aber ich möchte die Anzahl der Threads pro Anfrage auf 5 Threads beschränken. Diese 5 Threads konnten jedoch nur aus den 50 Threads zugewiesen werden, die im globalen Thread-Pool in der Konfigurationsdatei verfügbar sind.

Konfigurationsklasse zum Erstellen des Task Executor.

@Configuration 
public class ThreadPoolConfiguration { 

    @Value("${threadpool.corepoolsize}") 
    int corePoolSize; 

    @Value("${threadpool.maxpoolsize}") 
    int maxPoolSize; 

    @Bean 
    public ThreadPoolTaskExecutor taskExecutor() { 
     ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor(); 
     pool.setCorePoolSize(corePoolSize); 
     pool.setMaxPoolSize(maxPoolSize); 
     pool.setWaitForTasksToCompleteOnShutdown(true); 
     return pool; 
    } 
} 

Controller-Klasse

@RestController 
public class WebController { 

    @Autowired 
    ThreadPoolTaskExecutor threadPool; 

    @RequestMapping("/process") 
    public String process(){ 

     String msg = ""; 
     List<Future<String>> futureList = new ArrayList<>(); 
     for(int threadNumber = 0; threadNumber < 5; threadNumber ++){ 
      CallableWorker callableTask = new CallableWorker(String.valueOf(threadNumber)); 
      Future<String> result = threadPool.submit(callableTask); 
      futureList.add(result); 
     } 

     for(Future<String> future: futureList){ 
      try { 
       msg += future.get() + "#####"; 
      } catch (Exception e){} 
     } 

     return msg; 
    } 
} 

Haftungsausschluss: Dies ist nur Beispielcode ich von einem blog post bekam.

Wie kann ich ein solches Design implementieren? Ich sehe keinen Sub-Thread-Pool, der erstellt werden kann. Ich möchte auch keinen Thread-Pool für jede Anfrage instanziieren, da dies katastrophal wäre.

Irgendwelche Vorschläge?

+0

Was ist das Verhalten, das Sie wünschen, wenn eine Anfrage beispielsweise 6 Aufgaben hat, aber auf 5 Themen begrenzt ist? Warten Sie, bis eine der ersten 5 Aufgaben abgeschlossen ist, bevor Sie die 6. Aufgabe in die Warteschlange stellen. –

+0

Ja, genau so. Aber sagen Sie, dass eine andere Anfrage mit 5 Aufgaben kommt, geben Sie ihr 5 separate Threads vom globalen Thread-Pool. Und nachdem die zwei Anfragen eingereicht wurden, sind 10 Threads aus dem globalen Pool belegt und 1 Task wartet noch (von der ersten Anfrage) – Amriteya

Antwort

1

Eine Möglichkeit, dies zu lösen, könnte darin bestehen, Ihre aufrufbaren Methoden zu erstellen, um an einer Liste von Elementen statt an einzelnen Elementen zu arbeiten.

Wenn Sie beispielsweise x Elemente in einer Anfrage löschen möchten, können Sie Listen mit x/5 Elementen erstellen und diese Liste an Ihre aufrufbare Funktion übergeben. Auf diese Weise können Sie durch Code sicherstellen, dass höchstens 5 Threads pro Anfrage verwendet werden. Sie müssen die Ausnahmeszenarien jedoch sorgfältig behandeln. (z. B. können Sie eine Zuordnung von elementID zu result enum zurückgeben, wobei resultable excepiton oder non retryable exception sein könnte.)

Dieser Ansatz kann variieren, je nachdem, was genau Sie erreichen möchten.

+0

Dies sind die zwei Interpretationen, die ich aus Ihrer Antwort verstanden habe: Also, wenn ich 20 Aufgaben bekomme In der ersten Anfrage teile ich es in eine Liste von 4 Elementen. [1-5,6-10,11-15,16-20] und 1-5 als einen Job (Thread) einreichen. Was passiert mit den anderen 15? Oder übergebe ich alle 4 Aufgabengruppen an 4 Threads? Vor allem, wenn ich mehr als 5 * 5 Aufgaben (sagen wir 30) habe, wie gehe ich damit um? Zweitens möchte ich in meinem Anwendungsfall eine Aufgabe pro Thread haben. Wenn ich also eine Gruppe einem Thread übergebe, muss ich erneut parallelisieren, was unnötigen Overhead verursacht und außerdem meine erste Bedingung verletzt, dass eine Anfrage nur 5 Threads gleichzeitig haben kann. – Amriteya

+1

Wenn Sie 20 Anfragen haben, erstellen Sie 5 Listen mit je 4 Elementen und bearbeiten diese 4 Elemente seriell in der Methode. Wenn Sie 50 Anfragen haben, erstellen Sie 5 Listen mit jeweils 10 Elementen und bearbeiten die 10 Elemente seriell. Was Sie hier tun, ist sicherzustellen, dass Sie Ihre Aufgabe in etwas aufteilen, das auf 5 kleinere Aufgaben aufgeteilt werden kann, die parallel ausgeführt werden können. –

+0

Der Ansatz klingt gut. Das einzige Problem, das ich sehe, ist, dass ich einen Thread blockiere, um die Listeniteration zu orchestrieren. Und es wird eine schwere Aufgabe sein, denn es wird 4 Jobs einreichen, auf sie warten, bis sie fertig sind, dann wieder 4 Jobs und so weiter. Wenn ich ThreadPoolTaskExecutor verwenden konnte, kann ich alle Jobs in einer Warteschlange übergeben und diesen Thread abrufen. Ich suche nach einer Lösung, wo ich den Job in der Warteschlange einreichen könnte. – Amriteya

0

Die Art, wie ich dies tun würde wäre, eine Klasse zu erstellen, die die Aufgaben drosseln würde. Jede Anfrage würde eine Drosselklappe erzeugen und alle ihre Aufgaben an die Drosselklappe senden; Die Drossel würde die ersten 5 (sagen wir) Aufgaben an den Executor übergeben und die anderen auf eine Liste setzen. Nachdem die eingereichten Aufgaben abgeschlossen wurden, können zusätzliche Aufgaben eingereicht werden.

Um zu ermitteln, wann Aufgaben abgeschlossen wurden, konnte die Drosselung entweder periodisch die übermittelten Aufgaben abfragen, die isDone() -Methode der Futures überprüfen, um zu sehen, ob sie erledigt wurden, oder sie konnte die get() - Methode einer Zukunft blockieren Fertig und überprüfen Sie die anderen ausstehenden Futures an diesem Punkt, oder wenn Sie raffiniert werden wollten, könnte der Anfrage-Thread warten() auf den Gashebel und die Aufgaben könnten eingerichtet werden, um die Drosselung bei Beendigung zu benachrichtigen, so dass der Anfrage-Thread würde dann aufwachen und nach abgeschlossenen Aufgaben suchen.