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 af668e508..a0069b984 100644 --- a/src/main/java/org/simplejavamail/mailer/internal/mailsender/MailSender.java +++ b/src/main/java/org/simplejavamail/mailer/internal/mailsender/MailSender.java @@ -25,8 +25,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Phaser; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.atomic.AtomicInteger; import static java.lang.String.format; import static org.simplejavamail.converter.EmailConverter.mimeMessageToEML; @@ -72,7 +70,7 @@ public class MailSender { * Only set when {@link ProxyConfig} is provided with authentication details. */ @Nullable - private AnonymousSocks5Server proxyServer = null; + private AnonymousSocks5Server proxyServer; /** * Allows us to manage how many thread we run at the same time using a thread pool. @@ -194,21 +192,9 @@ 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 = Executors.newFixedThreadPool(operationalConfig.getThreadPoolSize(), new ThreadFactory() { - final AtomicInteger threadCounter = new AtomicInteger(0); - @Override - public Thread newThread(Runnable r) { - Thread thread = new Thread(r, "Simple Java Mail async mail sender #" + threadCounter.getAndIncrement()); - if (!thread.isDaemon()) { - thread.setDaemon(true); - } - if (thread.getPriority() != Thread.NORM_PRIORITY) { - thread.setPriority(Thread.NORM_PRIORITY); - } - return thread; - } - }); + if (executor == null || executor.isShutdown()) { + executor = Executors.newFixedThreadPool(operationalConfig.getThreadPoolSize(), + new NamedThreadFactory("Simple Java Mail async mail sender")); } configureSessionWithTimeout(session, operationalConfig.getSessionTimeout()); executor.execute(new Runnable() { @@ -269,7 +255,6 @@ private void sendMailClosure(@Nonnull final Session session, @Nonnull final Emai try { synchronized (this) { - //noinspection ConstantConditions if (needsAuthenticatedProxy() && !proxyServer.isRunning()) { LOGGER.trace("starting proxy bridge"); proxyServer.start(); @@ -319,7 +304,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 + * We need to keep a count of running threads in case a proxyserver is running or a connection pool needs to be shut down. */ private synchronized void checkShutDownRunningProcesses() { smtpRequestsPhaser.arriveAndDeregister(); @@ -327,11 +312,15 @@ private synchronized void checkShutDownRunningProcesses() { // if this thread is the last one finishing if (smtpRequestsPhaser.getUnarrivedParties() == 0) { LOGGER.trace("all threads have finished processing"); - //noinspection ConstantConditions if (needsAuthenticatedProxy() && proxyServer.isRunning() && !proxyServer.isStopping()) { 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(); + } } } @@ -389,7 +378,6 @@ public synchronized void testConnection() { logSession(session, "connection test"); try (Transport transport = session.getTransport()) { - //noinspection ConstantConditions if (needsAuthenticatedProxy() && !proxyServer.isRunning()) { LOGGER.trace("starting proxy bridge for testing connection"); proxyServer.start(); diff --git a/src/main/java/org/simplejavamail/mailer/internal/mailsender/NamedThreadFactory.java b/src/main/java/org/simplejavamail/mailer/internal/mailsender/NamedThreadFactory.java new file mode 100644 index 000000000..70940ebf1 --- /dev/null +++ b/src/main/java/org/simplejavamail/mailer/internal/mailsender/NamedThreadFactory.java @@ -0,0 +1,30 @@ +package org.simplejavamail.mailer.internal.mailsender; + +import javax.annotation.Nonnull; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +import static java.lang.String.format; +import static java.lang.Thread.currentThread; + +class NamedThreadFactory implements ThreadFactory { + private final AtomicInteger threadNumber = new AtomicInteger(1); + private final ThreadGroup group; + private final String threadName; + + NamedThreadFactory(@Nonnull final String threadName) { + SecurityManager s = System.getSecurityManager(); + group = (s != null) ? s.getThreadGroup() : currentThread().getThreadGroup(); + this.threadName = threadName; + } + + @Nonnull + public Thread newThread(@Nonnull Runnable r) { + Thread t = new Thread(group, r, format("%s %d", threadName, threadNumber.getAndIncrement())); + if (t.isDaemon()) + t.setDaemon(false); + if (t.getPriority() != Thread.NORM_PRIORITY) + t.setPriority(Thread.NORM_PRIORITY); + return t; + } +}