2011-11-01 97 views
2

我有两个不同的A和B Web应用程序托管在Tomcat上。 B应用程序在4个独立的tomcat物理系统上托管。并且应用程序A被托管在具有单独的tomcat的第五物理系统上。无论何时在应用程序A上发生登录/注销事件,它都需要将此通知发送给所有4 B应用程序。申请A创建每个事件的一个线程,该线程发出请求使用下面的代码全部4个B级应用:OutOfMemoryError:无法创建新的本地线程

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抛出以下异常: 异常的线程“qe01lj_login_success1320054407929”java.lang.OutOfMemoryError:无法创建新的本地线程 在java.lang.Thread.start0(本地方法) 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) 在com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1057) 在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)

如何解决上述问题? 这些应用程序正在运行HTTPS在Tomcat 5.5.17与jdk1.5.0_13

回答

4

How can I resolve above issue?

问题的直接原因是,你正在运行的内存来创建新主题。 (这个内存不是正常的堆,所以改变-Xmx不会有帮助。)

实际的原因是线程的创建速度比他们退出的速度要快。我怀疑,这种说法是问题的根源:

synchronized (this) { 
    // talk to network ... 
} 

的问题是,this将是您用来发送通知的SendNotification实例。如果您重复使用该对象,则会发现存在严重的瓶颈,导致网络任务一次执行一次。

除了上述问题,您的方法也有缺陷,因为每次调用sendNotification时,它都会覆盖SendNotification实例的状态而不进行任何同步。简单地说,你不应该使用单持有状态的线程数...


另一种可能是,你是不是重用SendNotification实例,(因此)的同步问题不问题的原因。在这种情况下,下一个可能的原因是您只需创建新线程的速度快于服务器可以处理它们的速度。

直接的解决方案是使用一个有界的线程池,这样你永远不会有超过20个线程(比如说)一次处于活动状态。有做这种事情的标准班。

但是,您的应用程序/平台可以执行这些任务的速度有限制。如果你长时间超过这个限制,你的应用程序的队列将会增加,你将遇到麻烦。如果这很可能,那么你的应用程序需要某种减轻负载的策略。


嗯...

的SSL堆栈似乎是创建一个线程在后台执行SSL协商。您似乎正在打开与远程服务器的连接,然后立即关闭它,但没有读取任何内容。也许这种不寻常的使用模式会导致SSL协商线程泄漏。尝试在关闭之前从流中读取一个字节。这很可能导致当前线程到达SSL协商线程,并且它不会被放在一边。

如果这是发生了什么,那么它可能是您正在使用的Java SSLSocketImpl代码中的一个错误。您应该升级JVM和Tomcat以获取最新(并且不是最新的!)安全性,性能和错误修复。它可能无法解决这个问题......但你应该这样做。

UPDATE - 谷歌搜索“SSLSocketImpl漏洞泄漏”提供了很多点击。我没有发现完全匹配的一个,但是升级是可取的。

+0

谢谢Stephen提供的答复。如果您查看getInstance()方法,它将创建SendNotification类的新对象。因此它不是一个单独的类。 如果我删除同步块,该怎么办?这会解决问题吗? – sushil

+0

SendNotification类的每个实例创建新的线程,并且此线程使用URL类的openStream()方法向所有4 B应用程序发出请求。 所以我的问题是,openStream()方法是否创建了与应用程序B通信的新线程? 如果我们看看Exception StackTrace,它显示 无法在java.lang.Thread.start(Thread.java:574) – sushil

+0

的java.lang.Thread.start0(Native Method)上创建新的本地线程。因此,对于每个请求有5个线程被创建? (一个由SendNotification类和4个由openStream()方法)? 如果是,那么如果应用程序A同时获得100个登录请求,则它一次将创建500个线程。 以下是tomcat连接器端口配置: sushil

相关问题