diff --git a/src/main/java/org/simplejavamail/mailer/internal/mailsender/MailSender.java b/src/main/java/org/simplejavamail/mailer/internal/mailsender/MailSender.java index 899c3b448..927efd3d6 100644 --- a/src/main/java/org/simplejavamail/mailer/internal/mailsender/MailSender.java +++ b/src/main/java/org/simplejavamail/mailer/internal/mailsender/MailSender.java @@ -23,8 +23,10 @@ import java.util.List; import java.util.Properties; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.Phaser; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import static java.lang.String.format; import static org.simplejavamail.converter.EmailConverter.mimeMessageToEML; @@ -192,9 +194,19 @@ the proxy bridge server (or connection pool in async mode) while a non-async ema smtpRequestsPhaser.register(); if (async) { // start up thread pool if necessary - if (executor == null || executor.isShutdown()) { - executor = Executors.newFixedThreadPool(operationalConfig.getThreadPoolSize(), - new NamedThreadFactory("Simple Java Mail async mail sender")); + if (executor == null) { + ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( + operationalConfig.getThreadPoolSize(), + operationalConfig.getThreadPoolSize(), + operationalConfig.getThreadPoolTimeout(), + TimeUnit.MILLISECONDS, + new LinkedBlockingQueue(), + new NamedThreadFactory("Simple Java Mail async mail sender") + ); + if(operationalConfig.getThreadPoolTimeout() > 0) { + threadPoolExecutor.allowCoreThreadTimeOut(true); + } + executor = threadPoolExecutor; } configureSessionWithTimeout(session, operationalConfig.getSessionTimeout()); executor.execute(new Runnable() { @@ -300,7 +312,7 @@ private void configureBounceToAddress(final Session session, final Email email) } /** - * We need to keep a count of running threads in case a proxyserver is running or a connection pool needs to be shut down. + * We need to keep a count of running threads in case a proxyserver is running */ private synchronized void checkShutDownRunningProcesses() { smtpRequestsPhaser.arriveAndDeregister(); @@ -312,11 +324,6 @@ private synchronized void checkShutDownRunningProcesses() { LOGGER.trace("stopping proxy bridge..."); proxyServer.stop(); } - // shutdown the threadpool, or else the Mailer will keep any JVM alive forever - // executor is only available in async mode - if (executor != null) { - executor.shutdown(); - } } } diff --git a/src/main/java/org/simplejavamail/mailer/internal/mailsender/OperationalConfig.java b/src/main/java/org/simplejavamail/mailer/internal/mailsender/OperationalConfig.java index a93448b25..3cad3bdc5 100644 --- a/src/main/java/org/simplejavamail/mailer/internal/mailsender/OperationalConfig.java +++ b/src/main/java/org/simplejavamail/mailer/internal/mailsender/OperationalConfig.java @@ -29,6 +29,11 @@ public class OperationalConfig { */ private final int threadPoolSize; + /** + * @see org.simplejavamail.mailer.MailerBuilder.MailerRegularBuilder#withThreadPoolTimeout(Integer) + */ + private final int threadPoolTimeout; + /** * @see org.simplejavamail.mailer.MailerBuilder.MailerRegularBuilder#withTransportModeLoggingOnly(Boolean) */ @@ -56,6 +61,7 @@ public OperationalConfig(@Nonnull Properties properties, int sessionTimeout, int this.properties = properties; this.sessionTimeout = sessionTimeout; this.threadPoolSize = threadPoolSize; + this.threadPoolTimeout = 1; // TODO wire it up to all the config files this.transportModeLoggingOnly = transportModeLoggingOnly; this.debugLogging = debugLogging; this.sslHostsToTrust = Collections.unmodifiableList(sslHostsToTrust); @@ -75,7 +81,14 @@ public int getSessionTimeout() { public int getThreadPoolSize() { return threadPoolSize; } - + + /** + * @see org.simplejavamail.mailer.MailerBuilder.MailerRegularBuilder#withThreadPoolSize(Integer) + */ + public int getThreadPoolTimeout() { + return threadPoolTimeout; + } + /** * @see org.simplejavamail.mailer.MailerBuilder.MailerRegularBuilder#withTransportModeLoggingOnly(Boolean) */