在我的catalina.out
的{{1}}日志中,我收到的错误是由第三方库引起的:
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)
中抛出异常来获取类似的日志消息:
Thread
但结果是
new Thread(){
@Override
public void run() {
Integer.parseInt("boom");
}
}.start();
所以问题是:当我看到顶部引用的日志时,它意味着什么?在非容器线程中发生错误是什么意思?我该如何重新创建呢?
答案 0 :(得分:8)
在非容器线程中发生错误的真正含义是什么?
当您使用JSP 3.0+异步请求处理时会发生这种情况。
在异步模式下,客户端请求由调用Servlet的service()
方法的“容器”线程接收。此方法(或其中一个辅助doXxxx
方法)调用startAsync()
,为请求创建Runnable
并将其分派给Executor。然后,此执行程序处理(“非容器”)工作线程上的请求。
(可以在here找到有关异步模式的详细说明,并附上一个示例。)
无论如何,“INFO:”消息只是说原始异常被抛出到Executor的一个工作线程的堆栈上。当Tomcat决定将失败的请求发送回容器线程时,就会生成它,以便可以执行请求清理。
在您的示例中,我怀疑原始SocketException
是由请求处理花了很长时间以致客户端(例如用户的浏览器)超时请求并关闭套接字引起的。一段时间后,您的服务器尝试编写响应,但由于连接已关闭而失败。
如何重新创建?
我猜,但你应该能够通过在Runnable
的{{1}}方法中抛出异常来重现那条“INFO:”消息。当然,你必须使用异步模式。
答案 1 :(得分: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版本。然后将不会显示此信息消息。
Bug 57683 - Crash of stockticket async example caused by an aborted client request
java.net.SocketException:Broken pipe
当我们错过关闭URLConnection等连接并关闭各种开放流时,实际上会出现此问题。我想分享一个例子
<强>之前:强>
OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));
bw.write("Lorem ipsum...");
out.close();
<强>后:强>
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();
当我们想在我们的应用服务器中加载测试时,有时会发生此错误。
数据需要long time to be generated
且负载测试工具不会wait for the large amounts of data
足够长,然后关闭连接。实际上,低内存导致应用程序关闭接收套接字或完全退出,具有相同的效果。
如果我们为JVM添加额外的内存,那么就解决了这个问题。
如@EJP所示,
这是因为当另一端已经关闭连接时写入连接。
因此,您的应用程序协议定义不明确。如果发生这种情况,您的应用程序协议规范或实现会出现问题,很可能是您甚至没有连接。
如果服务器端HTTP应用程序正在获取Broken Pipe异常,则意味着客户端浏览器已退出/转到历史记录中的另一个page/timed out/gone
。别忘了。
如果您想重现此错误,那么此tutorial可能会对您有所帮助。
线程中的异常&#34;线程-28&#34; java.lang.NumberFormatException:For 输入字符串:&#34;繁荣&#34;
您尝试将字母字符串转换/解析为整数时会发生此错误。这是正常的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
。这些发生在每个插槽中,需要容器进一步处理。通常这些事件由套接字实现触发,但它们也可能由容器触发。
非容器线程发生错误,处理需要返回容器进行必要的清理。使用它的示例包括:
这是信息消息的代码快照。
/**
* 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);
}
}
当请求使用多个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
*
*/
通过在非容器线程中定义读取和/或写入侦听器来启动非阻塞IO时,将调用此方法。一旦非容器线程完成,就会调用它,以便容器第一次调用onWritePossible()
和/或onDataAvailable()
。
处理调度需要(for APR/native at least)
已将套接字添加到waitingRequests队列。在非容器线程完成触发对此方法的调用时,可能不会发生这种情况。 因此,SocketWrapper上的编码同步作为启动此非容器线程的容器线程,可以锁定SocketWrapper 。容器线程将在释放socketWrapper上的锁之前将套接字添加到waitingRequests队列。因此,通过在处理调度之前获取socketWrapper上的锁定,我们可以确保已将套接字添加到waitingRequests queue
。