Ich erhalte diese Ausnahme auf meinem Tomcat-Server (+ liferay)
java.util.concurrent.RejectedExecutionException
Meine Klasse ist so:
public class SingleExecutor extends ThreadPoolExecutor {
public SingleExecutor(){
super(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
}
@Override
public void execute(Runnable command) {
if(command instanceof AccessLogInsert){
AccessLogInsert ali = (AccessLogInsert)command;
ali.setConn(conn);
ali.setPs(ps);
}
super.execute(command);
}
}
Ich erhalte diese Ausnahme in der Zeile. super.execute(command);
Dieser Fehler kann auftreten, wenn die Warteschlange voll ist, die LinkedBlockingQueue
Größe jedoch 2 ^ 31 beträgt, und ich bin sicher, dass nicht so viele Befehle warten.
Am Anfang ist alles stabil, aber nachdem ich einen Krieg neu eingesetzt habe, beginnt er aufzutreten. Diese Klasse ist nicht Teil des Krieges, sondern in einem Glas in Tomcat / Lib.
Haben Sie eine Idee, warum dies passiert ist und wie Sie es beheben können?
quelle
execute(java.lang.Runnable)
werden abgelehnt, wenn der Executor heruntergefahren wurde." Dies führte zu einem Fehler in meinem Code, den ich behoben habe, indem ich den Thread nach dem Herunterfahren 500 ms lang in den Ruhezustand versetzt habe (was möglicherweise nicht erforderlich ist) und dann den Scheduler aufnull
die betreffende Methode gesetzt habe, damit beim nächsten Ausführen einer Aufgabe die betreffende Methode ausgeführt werden muss prüft, ob der Scheduler istnull
. Wenn dies der Fall ist, wird eine neue erstellt. Somit entfällt die Ablehnung aus Gründen einer Abschaltung.Um die hervorragende Antwort von OrangeDog zu ergänzen, ist der Vertrag von a
Executor
tatsächlich so, dass seineexecute
Methode ausgelöst wird,RejectedExecutionException
wenn der Executor gesättigt ist (dh es ist kein Platz in der Warteschlange vorhanden).Es wäre jedoch nützlich gewesen, wenn es stattdessen blockiert worden wäre und automatisch gewartet hätte, bis in der Warteschlange Platz für die neue Aufgabe ist.
Mit dem folgenden Brauch ist
BlockingQueue
es möglich, dies zu erreichen:public final class ThreadPoolQueue extends ArrayBlockingQueue<Runnable> { public ThreadPoolQueue(int capacity) { super(capacity); } @Override public boolean offer(Runnable e) { try { put(e); } catch (InterruptedException e1) { return false; } return true; } }
Dies implementiert im Wesentlichen den Gegendruckalgorithmus und verlangsamt den Produzenten, wenn der Executor gesättigt ist.
Verwenden Sie es als:
int n = Runtime.getRuntime().availableProcessors(); ThreadPoolExecutor executor = new ThreadPoolExecutor(0, n, 1, TimeUnit.MINUTES, new ThreadPoolQueue(n)); for (Runnable task : tasks) { executor.execute(task); // will never throw, nor will queue more than n tasks } executor.shutdown(); executor.awaitTermination(1, TimeUnit.HOURS);
quelle
CallerRunsPolicy
existiert bereits, um dies zu erreichen, und bietet einen besseren Durchsatz als nur das Blockieren.InterruptedException
den Thread nicht unterbrechen. Dies ist selten wünschenswert. Sie sollten generell immer erneut unterbrechen,Thread.currentThread().interrupt();
bevor Sie dencatch
Block verlassen.