Runtime.getRuntime().exec() 日志阻塞问题定位到解决

1. 发现问题

工作中使用java程序导数据,

该导数据的java程序是通过另外一个java程序通过Runtime.getRuntime().exec() 启动的。

总是会出现数据传输到一半就卡住了,不会继续传输,也不会失败

纹丝不动,不生不死

 

2. 定位问题

查看java进程pid :jps -lm

查看java进程占用资源情况: top -p pid

再查看该java进程中线程资源使用情况: top -H -p pid

发现该java程序,一点资源也不占用,0cpu 0mem

也就是该java程序并没有在运行,被挂起了,继续分析

 

查看Thread Dump

jstack 2714 查看进程2714的stack

这里省略了其它不相关的信息

可以看到两个线程处于TIME_WAITING,一个处于RUNNABLE

这里需要注意Java的线程状态和操作系统层面的线程状态有点不一样

操作系统层面一个线程有Ready和Running状态,分别表示就绪和运行状态,但是Java只有RUNNABLE状态

操作系统虽然从cpu角度认为该线程已经阻塞,不再占用cpu,

但是Java认为程序虽然不再占用cpu,但是可能还占用着IO,或网络,所以还是认定程序是RUNNABLE,和BLOCKED要区分开

 

看前面几行信息

java.lang.Thread.State: RUNNABLE

at java.io.FileOutputStream.writeBytes(Native Method)

隔了一段时间,重新打印Thread Dump,发现信息完全一样

到这里几乎可以判断是 IO 阻塞了,而且根据后面的的信息,可以推断出是LOG日志造成的IO阻塞

注释掉程序的Console日志模块配置,还是阻塞

 

上网查了半天,原来是Process p = Runtime.getRuntime().exec()方法挖的坑

该类提供三个流来处理输入输出错误,注:输入输出都是从父进程角度观察
getInputStream() 标准输入
getOutputStream() 标准输出
getErrorStream() 标准错误
不能同步处理这三个流,否则可能会出现某个流没有被及时处理,一直占用缓冲区,
等缓冲区满了,无法写入数据,导致线程阻塞,进程卡死,对外现象就是进程无法停止,也不占资源,什么反应也没有

 

3. 解决问题

不要同步处理,可以另外创建线程来处理缓冲区的流,代码

Thread t1 = new Thread(new ProcessStreamRunable(pro.getInputStream(), "INPUT"));
Thread t2 = new Thread(new ProcessStreamRunable(pro.getErrorStream(), "ERROR"));
t1.start();
t2.start();

 

完工

 

额外补充一段:

==========================补充分割线====================================

java的线程转储可能很多,不便于观察,可以重定向到文件,慢慢找,

也可以如下查找

先使用top -H -p pid 找到操作系统上的线程ID, 第一列就是

jstack 2714 | grep -A 10 a9f

-A 10  表示往后多打印10行
a9f 是操作系统线程ID,对应的16进制,就是nid,线程ID通过上面的top命令查看

这样就可以打印指定线程的转储信息了,这可以定位某个线程的状态,如可以查看占用资源很多的线程到底在干什么


顺便给出linux打印16进制的命令
printf "%x\n"  2719    十进制 -> 十六进制
printf "%d\n" 0xa9f    十六进制 -> 十进制

 

Thread Dump字段意思

prio : 表示线程优先级,就是Thread中定义的这个。Thread类
os_prio : 表示操作系统级别的优先级
tid : 表示Java内的线程ID,同样在Thread类中
nid:表示操作系统级别的线程ID的16进制形式

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值