您的位置:首页 > 运维架构 > Linux

909422229_Linux执行大文件造成的线程堵塞问题

2018-03-20 10:16 435 查看
最近涉及Linux比较多,当然遇到了很多的问题,其中有一个需求是使用java调用Linux的shell文件。解压指定压缩包到指定路径。
当解压到一半的时候,停止了,百度了一下。说是操作大文件的时候造成线程堵塞。此文件大小为:100MB。所以可能是此原因造成的。
1、判断子进程是否执行结束有的时候我们用java调用shell之后,之后的操作要在Process子进程正常执行结束的情况下才可以继续,所以我们需要判断Process进程什么时候终止。Process类提供了waitFor()方法。该方法导致当前线程等待,直到Process线程终止。Process.waitFor()是有一个int类型返回值的,当返回值为0的时候表Process进程正常终止。否则一般是脚本执行出错了(我遇到的一般是这种情况)。2、Process.waitFor()导致当前线程阻塞。有的时候我们发现调用waitFor()方法后,java主线程会一直阻塞在waitFor()处,阻塞的原因是什么呢?分析一下:Java在执行Runtime.getRuntime().exec(jyName)之后,Linux会创建一个进程,该进程与JVM进程建立三个管道连接,标准输入流、标准输出流、标准错误流,假设linux进程不断向标准输出流和标准错误流写数据,而JVM却不读取,数据会暂存在linux缓存区,当缓存区存满之后导致该进程无法继续写数据,会僵死,导致java进程会卡死在waitFor()处,永远无法结束。
解决办法:java进程在waitFor()前不断读取标准输出流和标准错误流:

解决办法:java进程在waitFor()前不断读取标准输出流和标准错误流:下面是多种解决办法,本人采用的第一种,就是下面这个操作。一会贴上本人代码。本人代码,已经测试通过:     // 1.对文件授权
String command1 = "chmod 777 " + shPath;
Runtime.getRuntime().exec(command1).waitFor();

// 2.执行文件
String command2 = "/bin/sh " + shPath;

Process p0 = Runtime.getRuntime().exec(command2);
// 读取标准输出流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(p0.getInputStream()));
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
// 读取标准错误流
BufferedReader brError = new BufferedReader(new InputStreamReader(p0.getErrorStream(), "gb2312"));
String errline = null;
while ((errline = brError.readLine()) != null) {
System.out.println(errline);
}下面多个方法没有经过测试。他人使用需要测试哦。
[java] view plain copy//jyName  解压脚本路径  
String fileName=fileList.get(0).toString().substring(fileList.get(0).toString().lastIndexOf(File.separator)+1);  
String  jyName="/etc/zxvf.sh "+fileName;  
try {  
    Process p0 = Runtime.getRuntime().exec(jyName);  
    //读取标准输出流  
    BufferedReader bufferedReader =new BufferedReader(new InputStreamReader(p0.getInputStream()));  
    String line;  
    while ((line=bufferedReader.readLine()) != null) {  
        System.out.println(line);  
    }     
    //读取标准错误流  
    BufferedReader brError = new BufferedReader(new InputStreamReader(p0.getErrorStream(), "gb2312"));  
    String errline = null;  
    while ((errline = brError.readLine()) != null) {  
         System.out.println(errline);  
    }  
    //waitFor()判断Process进程是否终止,通过返回值判断是否正常终止。0代表正常终止  
    int c=p0.waitFor();  
    if(c!=0){  
        baseRes.put("desc", "软件升级失败:执行zxvf.sh异常终止");  
        baseRes.setReturnFlag(false);  
        return baseRes;  
    }  
} catch (IOException e1) {  
    baseRes.put("desc", "软件升级失败:文件解压失败");  
    baseRes.setReturnFlag(false);  
    return baseRes;  
} catch (InterruptedException e1) {  
    baseRes.put("desc", "软件升级失败:文件解压失败");  
    baseRes.setReturnFlag(false);  
    return baseRes;  
}  

也可以在执行Runtime.getRuntime().exec(jyName)之后另外再启动两个线程分别读取标准错误流和标准输出流[java] view plain copyimport java.io.BufferedReader;  
import java.io.IOException;  
import java.io.InputStream;  
import java.io.InputStreamReader;  
  
public class ExcuteThread extends Thread {  
    private String name;  
  
    public ExcuteThread(String name) {  
        this.name = name;  
    }  
    @Override  
    public void run() {  
        try {  
            Process p = Runtime.getRuntime().exec(name);  
            InputStream fis = p.getInputStream();  
            final BufferedReader brError = new BufferedReader(  
                    new InputStreamReader(p.getErrorStream(), "gb2312"));  
            InputStreamReader isr = new InputStreamReader(fis, "gb2312");  
            final BufferedReader br = new BufferedReader(isr);  
            Thread t1 = new Thread() {  
                public void run() {  
                    String line = null;  
                    try {  
                        while ((line = brError.readLine()) != null) {  
                            // System.out.println(line);  
                        }  
                    } catch (IOException e) {  
                        e.printStackTrace();  
                    } finally {  
                        try {  
                            if (brError != null)  
                                brError.close();  
                        } catch (IOException e) {  
                            e.printStackTrace();  
                        }  
                    }  
                }  
            };  
            Thread t2 = new Thread() {  
                public void run() {  
                    String line = null;  
                    try {  
                        while ((line = br.readLine()) != null) {  
                            // System.out.println(line);  
                        }  
                    } catch (IOException e) {  
                        e.printStackTrace();  
                    } finally {  
                        try {  
                            if (br != null)  
                                br.close();  
                        } catch (IOException e) {  
                            // TODO Auto-generated catch block  
                            e.printStackTrace();  
                        }  
                    }  
                }  
            };  
            t1.start();  
            t2.start();  
  
        } catch (IOException e1) {  
            // TODO Auto-generated catch block  
            e1.printStackTrace();  
        } finally {  
        }  
  
    }  
  
}  

3、shell脚本中有关联脚本,注意路径就是shell脚本中还要执行其他脚本,这时候就是注意一个路径的问题,这个问题也是我找了好长时间的一个问题。Process p=Runtime.getRuntime().exec(“/etc/a.sh”)在Test.java类调用了etc目录下的a.sh脚本, a.sh脚本中执行etc目录下的b.sh脚本,原来我在a.sh脚本中写的是./b.sh。其实这样linux是找不到b.sh的,因为我们执行是在Test.class目录下调用的/etc/a.sh  所以当a.sh中执行./b.sh的时候他会在Test.class目录下寻找,所以找不到,所以a.sh中要写成/etc/b.sh4、java连续调用多个脚本
[java] view plain copyString[] cmd = { "/bin/sh", "-c", "rm -rf /installation/upgrade/ ; mkdir /installation/upgrade/" };  
Process p = Runtime.getRuntime().exec(cmd);  
p.waitFor();  

就是这种数组的方式。
5、java执行.sh脚本文件的时候直接写目录就行,例如这样:Runtime.getRuntime().exec(“/etc/a.sh”)java 直接执行语句的时候需要加上"/bin/sh"  例如这样:[java] view plain copyString name="/bin/sh cd /installation/upgrade/ip89_install_packet";  
Process p = Runtime.getRuntime().exec(name);  

原创地址,珍惜前辈留下的秘籍:http://blog.csdn.net/hai_cheng001/article/details/22928297
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息