问题描述
功能描述,开启多个线程,每个线程都通过Process来调用cmd对网络进行ping,当线程执行完成后回显结果,现在的问题是,只有等全部线程中的process调用的cmd命令完成后才能进行输出,给我的感觉是当一个线程内的Process执行时,其他的线程是挂起状态。为说明这一点,我特意做了下修改,如果是ping百度的话,我要求ping5次,ping谷歌只ping1次,预想的结果是谷歌的结果很快就先显示出来,然后过一下再显示百度的结果(百度ping5次,一般需要5秒钟的时间),但现在的效果是谷歌不显示,等到百度也ping完成后同时显示,顺序不定,这时候体现出了线程抢资源的效果。我还在api上查了一下process的资料,里面有这样一句话:“对于带有 Process 对象的 Java 进程,没有必要异步或并发执行由 Process 对象表示的进程。”难道有Process的对象不能进行多线程异步操作?代码如下:Ping类package ping;import java.io.BufferedReader;import java.io.InputStreamReader;public class Ping implements Runnable {private String name;private String ip;Ping() {}Ping(String name, String ip) {this.name = name;this.ip = ip;}public String getName() {return name;}public String getIp() {return ip;}public void run() {System.out.println(this.name + "start");StringBuffer buf = new StringBuffer();String s = "";Process process;try {if (this.name.compareTo("百度") == 0) {process = Runtime.getRuntime().exec("cmd /c ping " + this.ip + " -n 5");} else {process = Runtime.getRuntime().exec("cmd /c ping " + this.ip + " -n 1");}BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));buf.append(this.name);while ((s = br.readLine()) != null) {buf.append(s + "n");}// process.waitFor();int index0 = buf.indexOf("(") + 1;int index1 = buf.indexOf("%");process.destroy();System.out.println(this.name + "t" + buf.substring(index0, index1));} catch (Exception ex) {ex.printStackTrace();}}}测试类:package ping;import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import java.util.ArrayList;import java.util.List;public class Test {public static void main(String args[]) {String driver = "com.mysql.jdbc.Driver";String url = "jdbc:mysql://127.0.0.1:3306/ping";String user = "root";String password = "123";List<Ping> list = new ArrayList<Ping>();try {Class.forName(driver);Connection conn = DriverManager.getConnection(url, user, password);Statement statement = conn.createStatement();String sql = "SELECT * FROM hostlist";ResultSet rs = statement.executeQuery(sql);while (rs.next()) {String name = rs.getString("name");String ip = rs.getString("ip");Ping p = new Ping(name, ip);list.add(p);}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException e) {e.printStackTrace();}for (int i = 0; i < list.size(); i++) {Ping p = list.get(i);new Thread(p, p.getName()).start();}}}
解决方案
问题出在下面的代码:BufferedReader br = new BufferedReader(new InputStreamReader( process.getInputStream())); buf.append(this.name); while ((s = br.readLine()) != null) { buf.append(s + "n"); } 确切的说是在readline方法中,readLine方法是存在缓冲区的,这种缓冲区会造成阻塞,这个在Process的Javadoc中也有说明:Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, and even deadlock.如果不适用readLine,应该就没有这个问题了。BTW,InputStreamReader实例化的时候最好指定编码方式,默认编码方式可能会所在native platform的编码方式不一致