我在tomcat上托管了两个不同的A和B Web应用程序。 B应用程序托管在具有单独tomcat的4个物理系统上。应用程序A托管在具有单独tomcat的第5个物理系统上。每当应用程序A上发生登录/注销事件时,它都需要将此通知发送到所有4个B应用程序。应用程序A为每个事件创建一个线程,该线程使用以下代码向所有4个B应用程序发出请求:
public class SendNotification implements Runnable {
private String action;
private String loginid;
private Thread thread;
StringBuilder sb = new StringBuilder();
public static SendNotification getInstance() {
return new SendNotification();
}
public void sendNotification(String action, String loginid){
this.action = action;
this.loginid = loginid;
sb.append(loginid)
.append("_")
.append(action)
.append(new Date().getTime());
thread = new Thread(this, sb.toString());
thread.start();
}
public void run(){
String methodName = "run";
int len = 4;
for(int i=0;i<len;i++){
synchronized(this){
StringBuilder url = new StringBuilder()
.append(<Server_B_i_IP:PORT>)
.append("&action=").append(action)
.append("&loginid=").append(loginid);
URL urlObj = null;
InputStream openStream = null;
try {
urlObj = new URL(url.toString());
openStream = urlObj.openStream();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
try {
if(openStream != null){
openStream.close();
}
openStream = null;
urlObj = null;
url = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
destroyObject();
}
private void destroyObject() {
thread = null;
}
}
但是一段时间后tomcat开始抛出以下异常:
Exception in thread "qe01lj_login_success1320054407929" java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:574)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:836)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1030)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1057)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1041)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:402)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:170)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:917)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:234)
at java.net.URL.openStream(URL.java:1007)
at com.test. sendNotification.run(sendNotification.java:69)
at java.lang.Thread.run(Thread.java:595)
如何解决上述问题?
这些应用程序在Tomcat 5.5.17上使用jdk1.5.0_13
运行HTTPS答案 0 :(得分:4)
如何解决上述问题?
问题的直接原因是您的内存不足以创建新线程。 (此内存不会出现在正常堆中,因此更改-Xmx
将无济于事。)
实际原因是线程的创建速度比它们退出的速度快。我怀疑这个陈述是问题的根源:
synchronized (this) {
// talk to network ...
}
问题是this
将是您用来发送通知的SendNotification
实例。如果重复使用该对象,您会发现存在严重的瓶颈,导致一次执行一个网络任务。
除了上述问题之外,您的方法存在缺陷,因为每次调用sendNotification
时,它都会覆盖SendNotification
实例的状态而不进行任何同步。简单地说,你不应该使用单例来保持多个线程的状态......
另一种可能性是您没有重用SendNotification
实例,因此同步问题不是问题的原因。在这种情况下,下一个可能的原因是您只是创建新线程而不是服务器可以处理它们。
直接的解决方案是使用有界线程池,这样你一次就不会有超过(比方说)20个线程处于活动状态。有这样的标准类。
但是,您的应用程序/平台可以执行这些任务的速率会受到限制。如果您长时间超过该限制,您的应用程序的队列将会累积,您将遇到麻烦。如果可能的话,那么您的应用程序需要某种策略来减轻负载。
嗯...
SSL堆栈似乎正在创建一个在后台执行SSL协商的线程。您似乎正在打开与远程服务器的连接,然后立即关闭它...而不读取任何内容。也许这种不寻常的使用模式会导致SSL协商线程泄漏。在关闭之前尝试从流中读取一个字节。这可能会导致当前线程到join
SSL协商线程,并且它不会处于不稳定状态。
如果这是正在发生的事情,那么它可能是您正在使用的Java SSLSocketImpl代码中的错误。您应该升级JVM和Tomcat以获取最新(并且不是最新的!)安全性,性能和错误修复。它可能无法解决这个问题......但无论如何你都应该这样做。
更新 - 谷歌搜索“SSLSocketImpl bug leak”给出了很多点击。我没有找到一个完全匹配的,但不过可以进行升级。