2009-12-21 7 views
7

ich dieses Problem habe, ich habeJava: SingleThreadScheduledExecutor & java.util.concurrent.RejectedExecutionException

private ScheduledExecutorService executor = 
    Executors.newSingleThreadScheduledExecutor(); 

und Aufgabe, die alle 50 millliseconds erstellt:

executor.scheduleAtFixedRate(myTask, 0, 50, TimeUnit.MILLISECONDS); 

myTask manchmal eine Weile dauern, zu vervollständigen (etwa 2-3 Sekunden), aber newSingleThreadScheduledExecutor garantiert, dass die nächste geplante myTask warten wird, bis die aktuelle abgeschlossen ist.

Allerdings bekomme ich diesen Fehler von Zeit zu Zeit:

ausführen: java.util.concurrent.RejectedExecutionException

Was soll ich tun? Dank

+0

Bitte Genauer gesagt über das, was yyou bedeuten durch "von Zeit zu Zeit". Diese Ausnahme sollte nur zum Zeitpunkt des Aufrufs von execute() auf dem ExecutorService ausgelöst werden. –

+0

Eigentlich ist RejectedExecutionException throwable von executor.scheduleAtFixedRate() –

+0

@Andrey, müssen Sie uns wesentlich mehr Informationen geben, mit einem Stack-Trace starten die Ausnahme darstellt. –

Antwort

11

Überlegen Sie, was der Ausführende tut. Es führt gemäß Ihren Anweisungen alle 50 Millisekunden eine einzelne Aufgabe aus. Wenn diese Aufgabe weniger als 50 Millisekunden dauert, ist alles in Ordnung. Es dauert jedoch immer 2-3 Sekunden, um zu laufen. Wenn dies geschieht, versucht der Executor weiterhin, alle 50 Millisekunden auszuführen, aber da er nur einen einzigen Thread hat, kann er dies nicht tun und weist diese Ausführungen zurück, die ausgelöst werden, während Ihre lang andauernde Aufgabe noch läuft. Dies verursacht die Ausnahme, die Sie sehen.

Sie haben zwei Möglichkeiten diese (vorausgesetzt, Sie mit einem einzigen Thread halten wollen) zu beheben:

  1. Verwenden scheduleWithFixedDelay statt scheduleAtFixedRate. Wenn Sie das Javadoc sorgfältig lesen, sehen Sie, dass scheduleWithFixedDelay 50 Millisekunden zwischen dem Ende einer Aufgabe und dem Beginn der nächsten wartet, so dass es sich niemals "überschneidet", selbst wenn eine davon lange dauert. Im Gegensatz dazu wird scheduleAtFixedRate versuchen, alle 50 Millisekunden auszuführen, unabhängig davon, wie lange jeder einzelne dauert.

  2. Ändern Sie die Art und Weise, wie der Executor die auszuführenden Fehler behandelt.Standardmäßig wird eine Ausnahme protokolliert, Sie können jedoch angeben, dass sie ignoriert werden soll. Werfen Sie einen Blick auf die Unterklassen von java.util.concurrent.RejectedExecutionHandler zum Beispiel DiscardPolicy, die nur leise die Aufgabe fällt, die nicht ausgeführt werden können. Sie können diese verwenden, indem Sie direkt ScheduledThreadPoolExecutor und vorbei in den Handler an den Konstruktor, anstatt die Executors Factory-Klasse zu bauen.

Ich vermute, Option (1) ist das, was Sie wollen.

+0

Danke! Es funktioniert – Andrey

+3

@skaffman: tatsächlich ist es genau das Gegenteil von dem, was Sie sagten in 1 :) javadoc: scheduleAtFixedRate: Wenn eine Ausführung dieser Aufgabe länger als seine Zeit dauert, dann nachfolgenden Ausführungen spät beginnen kann, wird aber nicht gleichzeitig ausgeführt werden – radio

4

Diese Ausnahme wird ausgelöst, wenn entweder:

  1. Sie Herunterfahren haben den Executor
  2. Die Grenzen des Executor für seine Arbeitswarteschlange oder maximale Threads überschritten wurden.

Ich nehme an, letzteres passiert. Wenn Sie Ihre Aufgabe ausführen und es lange dauert, können nachfolgende geplante Aufgaben nicht ausgeführt werden, da nicht genügend Threads im Pool verfügbar sind.

Entweder:

  1. Verwenden Sie eine größere Poolgröße verwenden oder verwenden cachedThreadPool
  2. Ändern der Zurückweisungsrichtlinie zum Beispiel verwenden ThreadPoolExecutor.CallerRunsPolicy
  3. eine separate Executor Erstellen Sie die lange Sicht Aufgaben für das Laufen und laufen diese von Ihrer geplanten Aufgabe. Tatsächlich können Sie dies mit derselben Executor-Instanz tun, vorausgesetzt, Sie erhöhen die Poolgröße.

Siehe auch ThreadPoolExecutor javadoc

+0

Wie benutze ich cachedThreadPool in meiner Situation? executor.scheduleAtFixedRate (myTask, 0, 50, TimeUnit.MILLISECONDS); Wie ist es möglich, die ThreadPoolExecutor-Zurückweisungsrichtlinie zu ändern? Danke – Andrey

Verwandte Themen