创建后台线程发送电子邮件(Creating a background Thread for sending email)

编程入门 行业动态 更新时间:2024-10-26 16:22:32
创建后台线程发送电子邮件(Creating a background Thread for sending email)

我需要在注册过程中发送电子邮件,所以由于这个原因,我使用的是Java Mail API ,但工作正常,但观察到电子邮件进程花费了将近6秒 (这太长),所以Ajax调用让用户等待响应时间太长

因此,我决定使用后台线程发送电子邮件,以便用户不必等待Ajax调用响应(Jersey REST Web服务调用)

我的问题是,为每个请求在web应用程序中创建线程是一种很好的做法?

@Path("/insertOrUpdateUser") public class InsertOrUpdateUser { final static Logger logger = Logger.getLogger(InsertOrUpdateUser.class); @GET @Consumes("application/text") @Produces("application/json") public String getSalesUserData(@QueryParam(value = "empId") String empId ) throws JSONException, SQLException { JSONObject final_jsonobject = new JSONObject(); ExecutorService executorService = Executors.newFixedThreadPool(10); executorService.execute(new Runnable() { public void run() { try { SendEmailUtility.sendmail(emaildummy); } catch (IOException e) { logger.error("failed",e); } } }); } } catch (SQLException e) { } catch (Exception e) { } finally { } return response; } }

这是我发送电子邮件的Utility类

public class SendEmailUtility { public static String sendmail(String sendto) throws IOException { String result = "fail"; Properties props_load = getProperties(); final String username = props_load.getProperty("username"); final String password = props_load.getProperty("password"); Properties props_send = new Properties(); props_send.put("mail.smtp.auth", "true"); props_send.put("mail.smtp.starttls.enable", "true"); props_send.put("mail.smtp.host", props_load.getProperty("mail.smtp.host")); props_send.put("mail.smtp.port", props_load.getProperty("mail.smtp.port")); Session session = Session.getInstance(props_send, new javax.mail.Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(username, password); } }); try { Message message = new MimeMessage(session); message.setFrom(new InternetAddress(props_load.getProperty("setFrom"))); message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(sendto)); message.setText("Some Text to be send in mail"); Transport.send(message); result = "success"; } catch (MessagingException e) { result = "fail"; logger.error("Exception Occured - sendto: " + sendto, e); } return result; } }

您能否让我知道这是否是在Web应用程序中执行的最佳做法?

I need to send a email during registration process , so for this reason i am using Java Mail API , this is working fine , but observed that the email process is taking nearly 6 seconds (which is too long ) so Ajax call making the user wait too long for response

so for this reason i have decided to use background thread for sending email so the user need not wait for the Ajax call response (Jersey REST Web Service call)

My question is it a good practice to creating threads in a webapplication for every request ??

@Path("/insertOrUpdateUser") public class InsertOrUpdateUser { final static Logger logger = Logger.getLogger(InsertOrUpdateUser.class); @GET @Consumes("application/text") @Produces("application/json") public String getSalesUserData(@QueryParam(value = "empId") String empId ) throws JSONException, SQLException { JSONObject final_jsonobject = new JSONObject(); ExecutorService executorService = Executors.newFixedThreadPool(10); executorService.execute(new Runnable() { public void run() { try { SendEmailUtility.sendmail(emaildummy); } catch (IOException e) { logger.error("failed",e); } } }); } } catch (SQLException e) { } catch (Exception e) { } finally { } return response; } }

And this is my Utility class for sending email

public class SendEmailUtility { public static String sendmail(String sendto) throws IOException { String result = "fail"; Properties props_load = getProperties(); final String username = props_load.getProperty("username"); final String password = props_load.getProperty("password"); Properties props_send = new Properties(); props_send.put("mail.smtp.auth", "true"); props_send.put("mail.smtp.starttls.enable", "true"); props_send.put("mail.smtp.host", props_load.getProperty("mail.smtp.host")); props_send.put("mail.smtp.port", props_load.getProperty("mail.smtp.port")); Session session = Session.getInstance(props_send, new javax.mail.Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(username, password); } }); try { Message message = new MimeMessage(session); message.setFrom(new InternetAddress(props_load.getProperty("setFrom"))); message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(sendto)); message.setText("Some Text to be send in mail"); Transport.send(message); result = "success"; } catch (MessagingException e) { result = "fail"; logger.error("Exception Occured - sendto: " + sendto, e); } return result; } }

Could you please let me know if this is best practice to do in a web application ??

最满意答案

有很多方法可以处理它,所以这取决于应用程序服务器是否有足够的资源(内存,线程等)来处理您的实现,因此它使您最好决定要采用哪种方法。

因此,如果设计合理,可以产生并行线程来执行某些操作,但通常您应该使用受控线程。

请注意,无论您使用newSingleThreadExecutor()还是newFixedThreadPool(nThreads) ,都会创建一个ThreadPoolExecutor对象。

我的建议是在下面的列表中使用秒选项,即“受控的线程数”,并在那里指定最大线程数,如你所见。

每个请求一个线程

在这种方法中,将为来自GUI的每个传入请求创建一个线程,因此如果您获得10个插入/更新用户的请求,则会生成10个线程,这将发送电子邮件。

这种方法的缺点是没有线程数量的控制,所以你可以用StackOverflowException结束或者可能是内存问题。

请确保关闭您的执行程序服务,否则最终会浪费JVM资源。

// inside your getSalesUserData() method ExecutorService emailExecutor = Executors.newSingleThreadExecutor(); emailExecutor.execute(new Runnable() { @Override public void run() { try { SendEmailUtility.sendmail(emaildummy); } catch (IOException e) { logger.error("failed", e); } } }); emailExecutor.shutdown(); // it is very important to shutdown your non-singleton ExecutorService.

受控的线程数

在这种方法中,将存在一些预定义的线程数量,这些线程将处理您的电子邮件发送要求。 在下面的例子中,我启动了一个最多有10个线程的线程池,然后我使用了LinkedBlockingQueue实现,这样可以确保如果有超过10个请求,并且当前我所有10个线程都处于忙碌状态,那么过多的请求将会排队,不会丢失,这是您使用Queue LinkedBlockingQueue实现获得的优势。

您可以在应用程序服务器启动时初始化您的单例ThreadPoolExecutor ,如果没有请求,则不会有线程存在,因此可以安全地执行此操作。 实际上,我为我的prod应用程序使用了类似的配置。

我使用时间将秒数作为1秒,所以如果一个线程在JVM中理想的时间超过1秒,那么它将会死亡。

请注意,由于同一个线程池用于处理所有请求,所以它应该是单例,并且不会关闭此线程池,否则您的任务将永远不会执行。

// creating a thread pool with 10 threads, max alive time is 1 seconds, and linked blocking queue for unlimited queuing of requests. // if you want to process with 100 threads then replace both instances of 10 with 100, rest can remain same... // this should be a singleton ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()); // inside your getSalesUserData() method executor.execute(new Runnable() { @Override public void run() { try { SendEmailUtility.sendmail(emaildummy); } catch (IOException e) { logger.error("failed", e); } } });

Java的默认缓存线程池

这种方法与上述非常类似,只是Java会将ThreadPoolExecutor初始化为ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());

这里最大线程数将是Integer.MAX_VALUE ,所以线程将根据需要创建,生存时间将为60秒。

如果你想用这种方式,那么下面就是这样。

// this should be a singleton ExecutorService emailExecutor = Executors.newCachedThreadPool(); // from you getSalesUserData() method emailExecutor.execute(new Runnable() { @Override public void run() { try { SendEmailUtility.sendmail(emaildummy); } catch (IOException e) { logger.error("failed", e); } } });

There are host of ways you can handle it, so it all depends on whether your application server has that much resources (memory, threads etc.) to handle your implementation, so it makes you best person to decide on which approach to go.

As such it is not bad practice to spawn parallel threads for doing something if it is justified by design, but typically you should go with controlled threads.

Please note that whether you use newSingleThreadExecutor() or newFixedThreadPool(nThreads), under-the-hoods there will always be a ThreadPoolExecutor object created.

My recommendation will be to use seconds option in below list i.e. "Controlled number of threads", and in that specify max thread count as you see fir.

One thread for each request

In this approach one thread will be created for each incoming request from GUI, so if you are getting 10 requests for inserting/updating user then 10 threads will be spawned which will send emails.

Downside of this approach is that there is no control on number of threads so you can end with StackOverflowException or may be memory issue.

Please make sure to shutdown your executor service else you will end up wasting JVM resources.

// inside your getSalesUserData() method ExecutorService emailExecutor = Executors.newSingleThreadExecutor(); emailExecutor.execute(new Runnable() { @Override public void run() { try { SendEmailUtility.sendmail(emaildummy); } catch (IOException e) { logger.error("failed", e); } } }); emailExecutor.shutdown(); // it is very important to shutdown your non-singleton ExecutorService.

Controlled number of threads

In this approach, some pre-defined number of threads will be present and those will process your email sending requirement. In below example I am starting a thread pool with max of 10 threads, then I am using a LinkedBlockingQueue implementation so this will ensure that if there are more than 10 requests and currently all my 10 threads are busy then excess of requests will be queued and not lost, this is the advantage you get with LinkedBlockingQueue implementation of Queue.

You can initialize you singleton ThreadPoolExecutor upon application server start, if there are no requests then no threads will be present so it is safe to do so. In fact I use similar configuration for my prod application.

I am using time to live seconds as 1 seconds so if a thread is ideal in JVM for more than 1 seconds then it will die.

Please note that since same thread pool is used for processing all you requests, so it should be singleton and do not shutdown this thread pool else your tasks will never be executed.

// creating a thread pool with 10 threads, max alive time is 1 seconds, and linked blocking queue for unlimited queuing of requests. // if you want to process with 100 threads then replace both instances of 10 with 100, rest can remain same... // this should be a singleton ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()); // inside your getSalesUserData() method executor.execute(new Runnable() { @Override public void run() { try { SendEmailUtility.sendmail(emaildummy); } catch (IOException e) { logger.error("failed", e); } } });

Java's default cached thread pool

This approach is much like above, only that Java will initialize the ThreadPoolExecutor for you as ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());

Here max number of threads will be Integer.MAX_VALUE, so threads will be created as needed and time to live will be 60 seconds.

If you want to use this way then below is the way.

// this should be a singleton ExecutorService emailExecutor = Executors.newCachedThreadPool(); // from you getSalesUserData() method emailExecutor.execute(new Runnable() { @Override public void run() { try { SendEmailUtility.sendmail(emaildummy); } catch (IOException e) { logger.error("failed", e); } } });

更多推荐

本文发布于:2023-07-24 01:45:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1240075.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:线程   后台   发送电子邮件   Creating   email

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!