web服务请求线程中带有输出语句时,频繁出现线程状态变成了BLOCKED,线程被无限阻塞

alunSemiconductor 2019-01-25 05:47:00

通过Java VisualVM和jconsole等工具查看,发现带有输出语句的请求,线程状态都变成了BLOCKED,都在等待java.io.PrintStream的锁,同时发现有log日志打印到控制台的请求也出现了这个情况,即线程状态都变成了BLOCKED,都在等待java.util.logging.ConsoleHandler
的锁:



从上图可以看出,在等待的锁目前被"http-nio-80-exec-4"拥有:



这个线程一直处于RUNNABLE状态

问题很好解决,不让程序在控制台输出任何东西就好了,日志存文件。
但是究竟是什么原因造成的呢? 查到这里,没有了头绪,希望有知道的能够指点一二,不胜感激。

目前最大的疑问就是像"http-nio-80-exec-4"这种线程处于RUNNABLE状态,但是好像又永远运行不完,导致后面所有带输出的请求线程都成了BLOCKED状态。

...全文
775 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
alunSemiconductor 2019-02-19
  • 打赏
  • 举报
回复
具体问题经过写成博客了:https://blog.csdn.net/ejiao1233/article/details/86678096
alunSemiconductor 2019-01-28
  • 打赏
  • 举报
回复
原因找到了,原来一切问题都是tomcat控制台窗口的“快速编辑模式”导致的,在这个模式下,点击窗口会导致窗口打印暂停,所以涉及到输出到控制台的接口全部表现为阻塞状态,右键点击或者键盘回车键,就会释放这个状态,继续打印。。。
alunSemiconductor 2019-01-26
  • 打赏
  • 举报
回复
引用 1 楼 oldmee 的回复:
这个问题是在哪行代码引起的?


没有固定的位置,现在观察到的如帖子中所描述,输出语句、Log日志打印到控制台,这些地方都有可能发生,但是发生的时机不确定,有时候很久没有发生,有时候启动tomcat就这样了。


对了,需要说明的是,本地测试没有发生过这个情况,服务器(阿里云的轻量服务器,Windows SERVER 2012)上经常出现。
oldmee 2019-01-25
  • 打赏
  • 举报
回复
这个问题是在哪行代码引起的?
jstack生成的Thread Dump日志.docx 系统线程状态 (Native Thread Status) 系统线程有如下状态: deadlock 死锁线程,一般指多个线程调用期间进入了相互资源占用,导致一直等待无法释放的情况。 runnable 一般指该线程正在执行状态,该线程占用了资源,正在处理某个操作,如通过SQL语句查询数据库、对某个文件进行写入等。 blocked 线程正处于阻塞状态,指当前线程执行过程,所需要的资源长间等待却一直未能获取到,被容器的线程管理器标识为阻塞状态,可以理解为等待资源超线程。 waiting on condition 线程正处于等待资源或等待某个条件的发生,具体的原因需要结合下面堆栈信息进行分析。 (1)如果堆栈信息明确是应用代码,则证明该线程正在等待资源,一般是大量读取某种资源且该资源采用了资源锁的情况下,线程进入等待状态,等待资源的读取,或者正在等待其他线程的执行等。 (2)如果发现有大量的线程都正处于这种状态,并且堆栈信息得知正等待网络读写,这是因为网络阻塞导致线程无法执行,很有可能是一个网络瓶颈的征兆: 网络非常繁忙,几乎消耗了所有的带宽,仍然有大量数据等待网络读写; 网络可能是空闲的,但由于路由或防火墙等原因,导致包无法正常到达; 所以一定要结合系统的一些性能观察工具进行综合分析,比如netstat统计单位间的发送包的数量,看是否很明显超过了所在网络带宽的限制;观察CPU的利用率,看系统态的CPU间是否明显大于用户态的CPU间。这些都指向由于网络带宽所限导致的网络瓶颈。 (3)还有一种常见的情况是该线程在 sleep,等待 sleep 的间到了,将被唤醒。 waiting for monitor entry 或 in Object.wait() Moniter 是Java用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者class的锁,每个对象都有,也仅有一个 Monitor。 从上图可以看出,每个Monitor在某个刻只能被一个线程拥有,该线程就是 "Active Thread",而其他线程都是 "Waiting Thread",分别在两个队列 "Entry Set"和"Waint Set"里面等待。其在 "Entry Set" 等待的线程状态是 waiting for monitor entry,在 "Wait Set" 等待的线程状态是 in Object.wait()。 (1)"Entry Set"里面的线程。 我们称被 synchronized 保护起来的代码段为临界区,对应的代码如下: synchronized(obj){} 当一个线程申请进入临界区,它就进入了 "Entry Set" 队列,这候有两种可能性: 该Monitor不被其他线程拥有,"Entry Set"里面也没有其他等待的线程。本线程即成为相应类或者对象的Monitor的Owner,执行临界区里面的代码;此在Thread Dump显示线程处于 "Runnable" 状态。 该Monitor被其他线程拥有,本线程在 "Entry Set" 队列等待。此在Thread Dump显示线程处于 "waiting for monity entry" 状态。 临界区的设置是为了保证其内部的代码执行的原子性和完整性,但因为临界区在任何间只允许线程串行通过,这和我们使用多线程的初衷是相反的。如果在多线程程序大量使用synchronized,或者不适当的使用它,会造成大量线程在临界区的入口等待,造成系统的性能大幅下降。如果在Thread Dump发现这个情况,应该审视源码并对其进行改进。 (2)"Wait Set"里面的线程线程获得了Monitor,进入了临界区之后,如果发现线程继续运行的条件没有满足,它则调用对象(通常是被synchronized的对象)的wait()方法,放弃Monitor,进入 "Wait Set"队列。只有当别的线程在该对象上调用了 notify()或者notifyAll()方法,"Wait Set"队列线程才得到机会去竞争,但是只有一个线程获得对象的Monitor,恢复到运行态。"Wait Set"线程在Thread Dump显示的状态为 in Object.wait()。通常来说, 通常来说,当CPU很忙的候关注 Runnable 状态线程,反之则关注 waiting for monitor entry 状态线程。 JVM线程运行状态 (JVM Thread Status)

67,513

社区成员

发帖
与我相关
我的任务
社区描述
J2EE只是Java企业应用。我们需要一个跨J2SE/WEB/EJB的微容器,保护我们的业务核心组件(中间件),以延续它的生命力,而不是依赖J2SE/J2EE版本。
社区管理员
  • Java EE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧