Paw*_*wan 2 java multithreading
我需要在注册过程中发送一封电子邮件,因此我正在使用Java Mail API,这工作正常,但观察到电子邮件进程花了将近6秒(这太长了)所以Ajax调用让用户等待响应太久了
因此我决定使用后台线程发送电子邮件,以便用户无需等待Ajax调用响应(Jersey REST Web Service调用)
我的问题是,为每个请求在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;
}
}
Run Code Online (Sandbox Code Playgroud)
这是我发送电子邮件的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;
}
}
Run Code Online (Sandbox Code Playgroud)
如果这是Web应用程序中的最佳做法,请您告诉我?
有许多方法可以处理它,所以这一切都取决于您的应用程序服务器是否有足够的资源(内存,线程等)来处理您的实现,因此它使您最好的人决定采用哪种方法.
因此,如果通过设计证明它是合理的,那么产生并行线程的做法并不是一种坏习惯,但通常你应该使用受控线程.
请注意,无论您使用newSingleThreadExecutor()or 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.
Run Code Online (Sandbox Code Playgroud)
在这种方法中,将存在一些预定义数量的线程,这些线程将处理您的电子邮件发送要求.在下面的示例中,我正在启动一个最多10个线程的线程池,然后我正在使用一个LinkedBlockingQueue实现,所以这将确保如果有超过10个请求并且当前我的所有10个线程都忙,那么多余的请求将排队而不是失败了,这是你LinkedBlockingQueue实施的优势Queue.
您可以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);
}
}
});
Run Code Online (Sandbox Code Playgroud)
这种方法与上面类似,只是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);
}
}
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6805 次 |
| 最近记录: |