Sie können absolut. Durch den Aufruf von setCorePoolSize(int)
wird die Kerngröße des Pools geändert. Aufrufe dieser Methode sind Thread-sicher und überschreiben Einstellungen für den Konstruktor ThreadPoolExecutor
. Wenn Sie die Poolgröße reduzieren, werden die verbleibenden Threads nach Abschluss der aktuellen Jobwarteschlange heruntergefahren (wenn sie inaktiv sind, werden sie sofort heruntergefahren). Wenn Sie die Poolgröße erhöhen, werden neue Threads so schnell wie möglich zugewiesen. Der Zeitrahmen für die Zuweisung neuer Threads ist nicht dokumentiert. In der Implementierung wird jedoch bei jedem Aufruf der Methode execute
die Zuweisung neuer Threads ausgeführt.
diese Job-Farm mit einer Laufzeit-abstimmbaren So koppeln, können Sie diese Eigenschaft aussetzen können (entweder durch Wrapper oder einen dynamischen MBean Exporteur unter Verwendung) als Lese-Schreib-JMX-Attribut eine ziemlich nett zu erstellen, on-the-fly abstimmbarer Stapelprozessor.
Um die Poolgröße zwangsweise zur Laufzeit zu reduzieren (was Ihre Anforderung ist), müssen Sie die ThreadPoolExecutor
Unterklasse bilden und der Methode beforeExecute(Thread,Runnable)
eine Unterbrechung hinzufügen. Das Unterbrechen des Threads ist keine ausreichende Unterbrechung, da diese nur mit Wartezuständen interagiert und während der Verarbeitung die Task-Threads ThreadPoolExecutor
nicht in einen unterbrechbaren Zustand gehen.
Ich hatte vor kurzem das gleiche Problem zu versuchen, einen Thread-Pool zwangsweise zu beenden, bevor alle übergebenen Aufgaben ausgeführt werden. Um dies zu erreichen, unterbrach ich den Thread, indem ich eine Laufzeitausnahme erst nach dem Ersetzen der UncaughtExceptionHandler
des Threads mit einer, die meine spezifische Ausnahme erwartet und löscht.
/**
* A runtime exception used to prematurely terminate threads in this pool.
*/
static class ShutdownException
extends RuntimeException {
ShutdownException (String message) {
super(message);
}
}
/**
* This uncaught exception handler is used only as threads are entered into
* their shutdown state.
*/
static class ShutdownHandler
implements UncaughtExceptionHandler {
private UncaughtExceptionHandler handler;
/**
* Create a new shutdown handler.
*
* @param handler The original handler to deligate non-shutdown
* exceptions to.
*/
ShutdownHandler (UncaughtExceptionHandler handler) {
this.handler = handler;
}
/**
* Quietly ignore {@link ShutdownException}.
* <p>
* Do nothing if this is a ShutdownException, this is just to prevent
* logging an uncaught exception which is expected. Otherwise forward
* it to the thread group handler (which may hand it off to the default
* uncaught exception handler).
* </p>
*/
public void uncaughtException (Thread thread, Throwable throwable) {
if (!(throwable instanceof ShutdownException)) {
/* Use the original exception handler if one is available,
* otherwise use the group exception handler.
*/
if (handler != null) {
handler.uncaughtException(thread, throwable);
}
}
}
}
/**
* Configure the given job as a spring bean.
*
* <p>Given a runnable task, configure it as a prototype spring bean,
* injecting any necessary dependencices.</p>
*
* @param thread The thread the task will be executed in.
* @param job The job to configure.
*
* @throws IllegalStateException if any error occurs.
*/
protected void beforeExecute (final Thread thread, final Runnable job) {
/* If we're in shutdown, it's because spring is in singleton shutdown
* mode. This means we must not attempt to configure the bean, but
* rather we must exit immediately (prematurely, even).
*/
if (!this.isShutdown()) {
if (factory == null) {
throw new IllegalStateException(
"This class must be instantiated by spring"
);
}
factory.configureBean(job, job.getClass().getName());
}
else {
/* If we are in shutdown mode, replace the job on the queue so the
* next process will see it and it won't get dropped. Further,
* interrupt this thread so it will no longer process jobs. This
* deviates from the existing behavior of shutdown().
*/
workQueue.add(job);
thread.setUncaughtExceptionHandler(
new ShutdownHandler(thread.getUncaughtExceptionHandler())
);
/* Throwing a runtime exception is the only way to prematurely
* cause a worker thread from the TheadPoolExecutor to exit.
*/
throw new ShutdownException("Terminating thread");
}
}
In Ihrem Fall sollten Sie eine Semaphore erstellen (nur für die Verwendung als THREAD Zähler), die keine Genehmigungen haben, und wenn Fäden lösen Abschalten eine Anzahl von Genehmigungen, um es, die das Delta entspricht der die vorherige Core-Pool-Größe und die neue Pool-Größe (Sie müssen die setCorePoolSize(int)
-Methode überschreiben). Dadurch können Sie Ihre Threads beenden, nachdem ihre aktuelle Aufgabe abgeschlossen ist. angefordert -
private Semaphore terminations = new Semaphore(0);
protected void beforeExecute (final Thread thread, final Runnable job) {
if (terminations.tryAcquire()) {
/* Replace this item in the queue so it may be executed by another
* thread
*/
queue.add(job);
thread.setUncaughtExceptionHandler(
new ShutdownHandler(thread.getUncaughtExceptionHandler())
);
/* Throwing a runtime exception is the only way to prematurely
* cause a worker thread from the TheadPoolExecutor to exit.
*/
throw new ShutdownException("Terminating thread");
}
}
public void setCorePoolSize (final int size) {
int delta = getActiveCount() - size;
super.setCorePoolSize(size);
if (delta > 0) {
terminations.release(delta);
}
}
Dies sollte n Gewinde für f (n) = aktiv unterbrechen. Wenn es irgendein Problem gibt, ist die Zuteilungsstrategie ThreadPoolExecutor
ziemlich dauerhaft. Es Buch-hält vor vorzeitiger Beendigung mit einem finally
Block, der die Ausführung garantiert. Aus diesem Grund werden sie, selbst wenn Sie zu viele Threads beenden, erneut gefüllt.
Um die Wähler unten. Wenn Sie die Frage des OP lesen, antwortete die hochgeschätzte zweite Antwort ursprünglich nicht. Das OP sagt so viel. Nachfolgende Änderungen implementieren die Vorschläge in dieser Antwort. –