Im Allgemeinen ist die Geschwindigkeit der Produktionsaufgaben größer als die Geschwindigkeit des Verbrauchs. Eine Detailfrage ist die Warteschlangenlänge und die Erfüllung der Produktions- und Verbrauchsgeschwindigkeit.
Ein typisches Hersteller-Verbrauchermodell lautet wie folgt:
Für die allgemeine Produktion ist schneller als der Verbrauch. Wenn die Warteschlange voll ist, möchten wir nicht, dass eine Aufgabe ignoriert oder nicht ausgeführt wird. . Blockieren sind auch einfach.
Wenn die Warteschlange leer ist, können die Verbraucher die Aufgabe nicht erhalten, bevor sie sie erhalten. . Auf diese Weise werden die Verbraucher, wenn der Produzent tatsächlich die Produktion gestoppt hat, nicht unendlich warten.
Daher wird ein effizientes Produktions- und Verbrauchsmodell, das die Blockierung unterstützt, implementiert.
Warten Sie, da JUC uns geholfen hat, Threadpools zu implementieren, müssen wir diese Dinge noch verwenden? Ist es nicht bequemer, Executorservice direkt zu verwenden?
Schauen wir uns die Grundstruktur von ThreadPoolexecutor an:
Das Problem ist jedoch, dass selbst wenn Sie eine Blockierungsqueue-Implementierung manuell angeben, wenn Sie ThreadPoolexecutor konstruieren, tatsächlich blockiert die Ausführungsmethode, wenn die Warteschlange voll ist.
Die Codekopie lautet wie folgt:
public void execute (runnable command) {
if (command == null)
neue nullpointerexception () werfen;
if (poolsize> = corepoolsize ||! addifundercorepoolSize (Befehl)) {
if (runState == running && arbeitsqueue.offer (Befehl)) {
if (runState! = running || poolsize == 0)
sicherstellen, dass die Taskehandeled (Befehl);
}
sonst wenn (! addifundermaximumpoolsize (Befehl)))
Ablehnung (Befehl); // wird geschaltet oder gesättigt.
}
}
Zu diesem Zeitpunkt muss etwas getan werden, um ein Ergebnis zu erzielen: Wenn der Produzent eine Aufgabe einreicht und die Warteschlange voll ist, kann der Produzent sie blockieren und darauf warten, dass die Aufgabe konsumiert wird.
Der Schlüssel ist, dass in einer gleichzeitigen Umgebung die Warteschlange nicht vom Produzenten beurteilt werden kann, und ThreadPoolexecutor.getQueue (). Size () kann nicht aufgerufen werden, um festzustellen, ob die Warteschlange voll ist.
Bei der Implementierung des Thread -Pools wird die während des Baus übergebene Ablehnung der Aufgabe aufgerufen, die während der Konstruktion verabschiedete Ablehnung der Aufgabe abzulehnen. Die Standardimplementierung ist abortpolicy, die direkt eine AblehnungsexecutionException wirft.
Ich werde hier nicht mehr über mehrere Ablehnungsstrategien eingehen. Der Verbrauch.
Die Codekopie lautet wie folgt:
öffentliche statische Klassen Callerrunspolicy -Geräte AblehnungsexecutionHandler {
/**
* Erstellt eine <tt> callerrunspolicy </tt>.
*/
public Callerrunspolicy () {}
/**
* Führt Aufgabe R im Thread des Anrufers aus, es sei denn, der Testamentsvollstrecker
* wurde geschlossen, in diesem Fall wird die Aufgabe verworfen.
* @param r Die für die Ausführung von Ausführungen angeforderte Aufgabe
* @param e Der Testamentsvollstrecker versucht, diese Aufgabe auszuführen
*/
public void rejectedExecution (runnable r, threadpoolexecutor e) {
if (! e.isshutdown ()) {
r.run ();
}
}
}
Diese Strategie hat jedoch auch versteckte Gefahren. Produzieren Sie weiterhin die Aufgaben.
In Bezug auf ähnliche Ideen, die einfachste Art und Weise, können wir eine Ablehnung von Ablehnung direkt definieren und sie so ändern, dass die Warteschlange blockiert wird.
Die Codekopie lautet wie folgt:
Neue AblehnungsexecutionHandler () {
@Override
public void rejectedExecution (runnable r, threadpoolexecutor) {
if (! Executor.isshutdown ()) {
versuchen {
Executor.getQueue (). Put (R);
} catch (InterruptedException e) {
// sollte nicht unterbrochen werden
}
}
}
};
Auf diese Weise müssen wir uns nicht mehr um die Logik der Warteschlange und Verbraucher kümmern.
Im Vergleich zum ursprünglichen Design kann diese Methode die Codemenge reduzieren und viele Probleme in gleichzeitigen Umgebungen vermeiden. Natürlich können Sie auch andere Mittel verwenden, z. B. bei der Verwendung von Semaphoren als Einstiegsbegrenzungen beim Senden. Wenn Sie jedoch nur den Produzenten blockieren möchten, erscheint dies kompliziert.