Nehmen wir an, ich habe 1000 Dateien zu lesen, und wegen einiger Einschränkungen möchte ich maximal 5 Dateien parallel lesen. Und sobald einer von ihnen fertig ist, möchte ich einen neuen starten.
Ich habe eine Hauptfunktion, die die Liste der Dateien haben, und ich versuche, einen Zähler zu ändern, wenn ein Thread beendet ist. aber es funktioniert nicht!
Irgendwelche Vorschläge?
Das Folgende ist die Hauptfunktionsschleife
%Vor% Solche Fäden zu erzeugen, ist nicht der richtige Weg. Verwenden Sie ExecutorService
und geben Sie an, dass der Pool 5 sein soll. Legen Sie alle Dateien in eine BlockingQueue
oder eine andere threadsichere Sammlung, und alle ausführbaren Dateien können nur poll()
nach Belieben.
Der Ansatz in Kylars Antwort ist der richtige. Verwenden Sie die von den Java-Klassenbibliotheken bereitgestellten Executor-Klassen, anstatt das Thread-Pooling selbst von Grund auf neu zu implementieren (schlecht).
Aber ich dachte, es könnte nützlich sein, den Code in Ihrer Frage zu diskutieren und warum es nicht funktioniert. (Ich habe einige der Teile, die du weggelassen hast, so gut wie möglich ausgefüllt ...)
%Vor%OK, was ist daran falsch? Warum funktioniert es nicht?
Nun, das erste Problem ist, dass Sie in main
counter
lesen und schreiben, ohne eine Synchronisation durchzuführen. Ich gehe davon aus, dass es auch von den Worker-Threads aktualisiert wird - ansonsten macht der Code keinen Sinn. Das bedeutet, dass die Wahrscheinlichkeit besteht, dass die Hauptthreads das Ergebnis der von den untergeordneten Threads vorgenommenen Aktualisierungen nicht sehen. Mit anderen Worten, while (counter > 5);
könnte eine Endlosschleife sein. (Tatsächlich ist das ziemlich wahrscheinlich. Der JIT-Compiler kann Code erzeugen, in dem counter > 5
einfach den Wert von counter
, der in einem Register nach der vorherigen counter++;
-Anweisung übrig geblieben ist, testet.
Das zweite Problem ist, dass Ihre while (counter > 5);
-Schleife eine unglaubliche Verschwendung von Ressourcen darstellt. Sie sagen der JVM, dass sie eine Variable abfragen soll ... und sie wird dies MILLIARDEN Mal pro Sekunde tun ... einen Prozessor (Kern) ausführen. Du solltest das nicht tun. Wenn Sie solche Dinge mit Low-Level-Primitiven implementieren möchten, sollten Sie die Methoden Object.wait()
und Object.notify()
von Java verwenden; z.B. Der Haupt-Thread wartet und jeder Worker-Thread benachrichtigt.
Sie können einen ExecutorService als Thread-Pool UND eine Warteschlange verwenden.
%Vor%Welche Methode Sie auch verwenden, um einen neuen Thread zu erstellen, einen globalen Zähler zu erhöhen, eine bedingte Anweisung um die Thread-Erstellung hinzuzufügen. Wenn das Limit erreicht wurde, dann erstellen Sie keinen neuen Thread, sondern schieben Sie die Dateien in eine Warteschlange (eine Liste?) und dann können Sie eine weitere bedingte Anweisung hinzufügen, nachdem ein Thread erstellt wurde, wenn es Elemente in der Warteschlange gibt, um diese Elemente zuerst zu verarbeiten.
Tags und Links java multithreading limit