并发发送带有附件和"Too many open files"错误的 Html电子邮件



我怀疑我使用了错误的Apache通用电子邮件库来发送带有附件的电子邮件。有时我会出现"打开的文件太多">错误,如果我用lsof检查打开的文件,我会发现附件文件被打开了多次:

image1.pngimage2.pngimage1.png…

所以我怀疑我没有正确地发布文件(或者没有关闭一些资源(。也可能是软件工作正常,但如果外部SMTP服务器出现故障(连接异常(,我的代码不会释放一些资源。

来源:

/* Async Thread to send email */
Thread t = new Thread(){
@Override
public void run(){
try{
task(request,idNewsletter);
}
catch (Exception e){
log.error("Error " + e);
}
}
};
t.start();
[...]

任务方法:

ExecutorService executor = Executors.newFixedThreadPool(10);
[...]
List<Future<Integer>> list = new ArrayList<Future<Integer>>();
for (int i = 0; i < dests.length; i++) {        
HtmlEmail htmlEmail = getHtmlMail([...]);
ArrayList<InternetAddress> dest = new ArrayList<InternetAddress>();
InternetAddress add = new InternetAddress();
add.setAddress(dests[i]);
dest.add(add);
htmlEmail.setBcc(dest);         
htmlEmail.setMailSession(getEmailSession());            
htmlEmail.buildMimeMessage();
Callable<Integer> worker = new EmailService(htmlEmail,i);        
Future<Integer> future = executor.submit(worker);            
list.add(future);
}
try {
executor.shutdown();
executor.awaitTermination(28800, TimeUnit.SECONDS);
}
catch (InterruptedException e) {
log.error("Error=" + e);
}
finally {
if (!executor.isTerminated()) {
log.error("Task cancelled");
}
executor.shutdownNow();
}

getHtmlEmail方法

private static URL image;
static {
image= (new File("somepath").toURI().toURL());
}

private HtmlEmail getHtmlMail([...]){
HtmlEmail htmlEmail = new HtmlEmail();
htmlEmail.setCharset("UTF-8");
htmlEmail.setSubject("someSubject");
htmlEmail.setFrom(from);
htmlEmail.setSentDate(new java.util.Date());
[...]
String cidImage= htmlEmail.embed(image, "Email image");
text= text.replace("cid:image", "cid:" + cidImage);
[...] /* Other attachments */
htmlEmail.setHtmlMsg(text); 
return htmlEmail;
}

getEmailSession方法

private Session getEmailSession() throws Exception{  
if (mailSession != null)
return mailSession;
else {
InitialContext ic = new InitialContext();
mailSession = (Session) ic.lookup("someJNDI");
mailSession.getProperties().put("mail.smtp.connectiontimeout", 1000);
mailSession.getProperties().put("mail.smtp.timeout", 5000);
return mailSession;
}
}

以及发送电子邮件的方法

@Override
public Integer call() throws Exception {    
try{                                                        
htmlEmail.sendMimeMessage();    
}
catch(Exception e){  
log.error("Error=" + e);
htmlEmail=null;
return new Integer(0);
}                         
return new Integer(1);
}  

有什么提示吗?

提前感谢Andrea

我认为这就是问题所在:

static {
image= (new File("somepath").toURI().toURL());
}

它是static。这是一个并发问题。它总是在那里以下是我认为正在发生的事情。假设这在一个名为Url的类中,并且您有一个非静态的getUrl(),它返回这个。如果你这样做:

Url url1 = new Url();
Url url2 = new Url();
url1.getUrl();
url2.getUrl();

然后他们每个人都应该返回一个不同的url实例。但是,您正在将url属性初始化为static,因此实际情况是所有Url实例都只有一个Url。url属性不是由每个对象所有,而是仅由类本身所有因此,当您尝试调用它时,他们都会一次又一次地尝试访问该文件,因为它最初从未"创建"过,也从未按实例初始化过。将其视为始终存在的东西,因为类本身拥有它,而不是实例,因此会出现Too many open files错误。

所以我建议你把它从静止状态中移除。也许你可以这样做:

class Url{
private final URL url;
public Url() {
url= (new File("somepath").toURI().toURL());
}
}

然后,只要在任何需要的地方使用url属性即可。

更新:即使我将字段重写为非静态字段,问题仍然存在。我想这是这个版本的库(Apache Common Email 1.5(的问题(bug?(

最新更新