tomcat中的非容器线程错误是什么?

TMG*_*TMG 16 java tomcat log4j tomcat7

catalina.out我的日志中,我Tomcat7收到由第三方库引起的错误,该库以以下内容开头:

INFO: An error occurred in processing while on a non-container thread. The connection will be closed immediately
java.net.SocketException: Broken pipe
        at java.net.SocketOutputStream.socketWrite0(Native Method)
        at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:113)
Run Code Online (Sandbox Code Playgroud)

在非容器线程中发生错误的真正含义是什么?

我试图通过Thread从我的应用程序代码中生成一个新的异常来获取类似的日志消息:

new Thread(){
    @Override
    public void run() {
        Integer.parseInt("boom");
    }
}.start();
Run Code Online (Sandbox Code Playgroud)

但它导致了

Exception in thread "Thread-28" java.lang.NumberFormatException: For input string: "boom"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Integer.parseInt(Integer.java:492)
    at java.lang.Integer.parseInt(Integer.java:527)
    at ...
Run Code Online (Sandbox Code Playgroud)

所以问题是:当我看到顶部引用的日志时,它意味着什么?在非容器线程中发生错误是什么意思?我该如何重新创建呢?

Ste*_*n C 8

在非容器线程中发生错误的真正含义是什么?

当您使用JSP 3.0+异步请求处理时会发生这种情况.

在异步模式下,客户端请求由调用Servlet service()方法的"容器"线程接收.此方法(或其中一个辅助doXxxx方法)调用为请求startAsync()创建一个Runnable并将其分派给Executor.然后,此执行程序处理("非容器")工作线程上的请求.

(可以在此处找到有关异步模式的详细说明,完整的示例).

无论如何,"INFO:"消息只是说原始异常被抛出到Executor的一个工作线程的堆栈上.当Tomcat决定将失败的请求发送回容器线程时,就会生成它,以便可以执行请求清理.

在您的示例中,我怀疑原始文件SocketException是由请求处理花了很长时间以致客户端(例如用户的浏览器)超时请求并关闭套接字.一段时间后,您的服务器尝试编写响应,但由于连接已关闭而失败.

我该如何重新创建呢?

我猜,但你应该能够重现"信息:"通过在抛出异常信息Runnablerun()方法.当然,您必须使用异步模式.


Sky*_*ker 5

首要问题:

信息:在非容器线程上处理时发生错误.连接将立即关闭

答:

async.Stockticker线程坠毁由于处理ISE非.这解释了这种行为.该异常仅记录在控制台中.它未登录到Tomcat日志文件中.这是Tomcat的错误处理错误.这不是近期变化的回归.它是可重复的Tomcat 7.0.59.

它已经固定在trunk 8.0.x (for 8.0.21 onwards)7.0.x (for 7.0.60 onwards).所以你可以升级你的tomcat版本.然后将不会显示此信息消息.

资源链接:

错误57683 - 由于客户端请求中止导致的stockticket异步示例崩溃



第二期:

java.net.SocketException:管道损坏

方案1:

当我们错过关闭URLConnection等连接并关闭各种开放流时,实际上会出现此问题.我想分享一个例子

之前:

OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));
bw.write("Lorem ipsum...");
out.close();
Run Code Online (Sandbox Code Playgroud)

后:

OutputStream os = urlConnection.getOutputStream();
OutputStream out = new BufferedOutputStream(os);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));
bw.write("Lorem ipsum...");
bw.close(); //This is must. If you miss to close, then "java.net.SocketException: Broken pipe" error comes
out.close();
os.close(); 
Run Code Online (Sandbox Code Playgroud)

方案2:

当我们想在我们的应用服务器中加载测试时,有时会发生此错误.

数据需要a long time to be generated并且负载测试工具不够wait for the large amounts of data长,然后关闭连接.实际上,低内存导致应用程序关闭接收套接字或完全退出,具有相同的效果.

如果我们为JVM添加额外的内存,那么它就解决了这个问题.

解决方案3:

正如@EJP建议的那样,

这是因为当另一端已经关闭连接时写入连接.

因此,您的应用程序协议定义不明确或已实现.如果发生这种情况,您的应用程序协议规范或实现有问题,很可能是您甚至没有连接.

如果服务器端HTTP应用程序正在获取Broken Pipe异常,则仅表示客户端浏览器已退出/转到page/timed out/gone历史记录/中的另一个.忘掉它.

资源链接:

  1. 如何修复java.net.SocketException:管道坏了?
  2. 为什么会出现"java.net.SocketException:Broken pipe"?

如果您想重现此错误,那么本教程可能会对您有所帮助.



第三期:

线程"Thread-28"中的异常java.lang.NumberFormatException:对于输入字符串:"boom"

您尝试将字母字符串转换/解析为整数时,会发生此错误.这是正常的java错误NumberFormatException.



更新:

正如您所知,在捕获应用程序抛出的异常时,Tomcat决定在哪些情况下记录该附加消息.所以我简要分享一下.

为了明确概念"INFO: An error occurred in processing while on a non-container thread. The connection will be closed immediately java.net.SocketException: Broken pipe",首先,我想与您分享这是与插座相关的问题.tomcat中6个SocketEvent.他们是OPEN_READ, OPEN_WRITE, STOP, TIMEOUT, DISCONNECT and ERROR.这些发生在每个插槽中,需要容器进一步处理.通常这些事件由套接字实现触发,但它们也可能由容器触发.

套接字事件"ERROR":

非容器线程发生错误,处理需要返回容器进行任何必要的清理.使用它的示例包括:

  • 由NIO2表示完成处理程序的失败
  • 由容器在Servlet 3.0异步处理期间发出非容器线程上的I/O错误信号.

发生此错误并在TOMCAT中显示INFO消息?

这是信息消息的代码快照.

  /**
     * Update the current error state to the new error state if the new error
     * state is more severe than the current error state.
     * @param errorState The error status details
     * @param t The error which occurred
     */
    protected void setErrorState(ErrorState errorState, Throwable t) {
        boolean blockIo = this.errorState.isIoAllowed() && !errorState.isIoAllowed();
        this.errorState = this.errorState.getMostSevere(errorState);
        if (blockIo && !ContainerThreadMarker.isContainerThread() && isAsync()) {
            // The error occurred on a non-container thread during async
            // processing which means not all of the necessary clean-up will
            // have been completed. Dispatch to a container thread to do the
            // clean-up. Need to do it this way to ensure that all the necessary
            // clean-up is performed.
            if (response.getStatus() < 400) {
                response.setStatus(500);
            }
            getLog().info(sm.getString("abstractProcessor.nonContainerThreadError"), t);  // This section gives the INFO message "INFO: An error occurred in processing while on a non-container thread. The connection will be closed immediately"
            socketWrapper.processSocket(SocketEvent.ERROR, true);
        }
    }
Run Code Online (Sandbox Code Playgroud)

DEADLOCK怎么可能发生?

当请求使用多个start()序列时; dispatch()对于非容器线程,前者可能dispatch()会干扰后续操作start().这个锁可以防止这种情况发生.它是一个专用对象,因为用户代码可能会锁定AsyncContext,因此如果容器代码也锁定该对象,则可能发生死锁.

非容器线程如何定义当前错误状态并给出响应?

随着异步处理的引入non-container threads calling sendError() tracking the current error state以及确保调用正确错误页面的可能性变得更加复杂.此状态属性有助于跟踪当前错误状态并通知调用者如果更改成功或另一个线程首先到达,则尝试更改状态.

   /** 
     * The state machine is very simple:
     *
     * 0 - NONE
     * 1 - NOT_REPORTED
     * 2 - REPORTED
     *
     *
     *   -->---->-- >NONE
     *   |   |        |
     *   |   |        | setError()
     *   ^   ^        |
     *   |   |       \|/
     *   |   |-<-NOT_REPORTED
     *   |            |
     *   ^            | report()
     *   |            |
     *   |           \|/
     *   |----<----REPORTED
     * 
     */
Run Code Online (Sandbox Code Playgroud)

当在非容器线程中调用executeNonBlockingDispatches(...)方法以及它如何与SocketWrapper交互时?

通过在非容器线程中定义读取和/或写入侦听器来启动非阻塞IO时,将调用此方法.一旦非容器线程完成就调用它,以便第一次调用onWritePossible()和/或onDataAvailable()适当地由容器进行调用.

处理调度需要(for APR/native at least)将套接字添加到waitingRequests队列.在非容器线程完成触发对此方法的调用时,可能不会发生这种情况.因此,SocketWrapper上的编码同步作为启动此非容器线程的容器线程保持对SocketWrapper的锁定.容器线程将在释放socketWrapper上的锁之前将套接字添加到waitingRequests队列.因此,通过在处理调度之前获取socketWrapper上的锁定,我们可以确定已将套接字添加到waitingRequests queue.

  • 说真的,这个答案真的需要这么长吗?那里有很多东西似乎与所问的问题无关。 (2认同)