首页 > 解决方案 > 我的代码在遇到 Thread.sleep() 时一直挂起,并且卡在了一个 while 循环中,我该如何修复我的代码才能正常运行?

问题描述

谢谢你的帮助。我尝试了从创建新线程开始的一切。改变我使用 writer.flush() 和 writer.newLine() 的方式。似乎代码一直挂在 while 循环中,不断地运行 Thread.sleep() 不间断。我无法提供批处理文件,因为它是敏感信息,但代码顶部的 String 命令变量是我用来访问命令的路径。如果您确实回答了这个问题,请先使用测试 bat 文件和两个输入字段运行代码。

批处理脚本:

@ECHO OFF
SET /P _inputname= Please enter an name:
SET /P _inputpassword= Please enter an password:
IF "%_inputpassword%"=="1234" GOTO :they_said_1234

ECHO You entered the wrong password!
pause
GOTO 
:they_said_1234
ECHO You entered 1,2,3,4!
pause

Java 代码:

  import java.io.*;
  import java.nio.CharBuffer;
  import java.util.ArrayList;


public class command{
public static void main(String[] args) {

    //String command="cmd /c d: && cd UPSDATA\\Virtualization Scripts\\EMC ESXi Grab\\EMC-ESXi-GRAB-1.3.7 && GRAB_RUN ";
    //String command="cmd /c date";
    String command = "cmd /c cd C:\\Users\\HFB2VZN\\Desktop\\folderG";

    try {
        Process process = Runtime.getRuntime().exec(command);
        try (Writer writer = new OutputStreamWriter(process.getOutputStream());
             Reader reader = new InputStreamReader(process.getInputStream())) {

            CharBuffer buf = CharBuffer.allocate(80);
            int tries = 2;

            while (process.isAlive()) {
                while (reader.ready() && reader.read(buf) > 0) {
                    //3
                   System.out.println("buf.flip() ran");
                    System.out.append(buf.flip());
                    buf.clear();
                }

                if (tries-- == 0) {
                    System.out.println("Destroyed");
                    process.destroy();
                    break;
                }
                //1
                writer.write("random");
                writer.flush();


                while (!reader.ready()) {
                    //2
                    System.out.println("while() loop, Thread runs in non stop loop");
                    Thread.sleep(800);

                }

            }
        }
    } catch (IOException | InterruptedException e) {
        e.printStackTrace();
    }


}

}`

标签: javamultithreadingbatch-file

解决方案


此示例相比,执行批处理文件会慢得多,并且有多个命令可能意味着在生成下一个输出之前的一段时间内没有可用的输出。不考虑这可能会导致循环不同步,并且在进程终止后,您不能在while (!reader.ready()) {…}不检查进程是否仍然存在的情况下执行循环。

由于您的批处理文件的第二个GOTO缺少目标(它可能应该向后分支),因此该批处理文件可能比预期的更早终止。由于没有人读取错误通道,因此不会被注意到。这可能是挂在那个循环中的原因。进一步注意,每次循环迭代都会为批处理文件生成一个输入,但将迭代次数限制为2每个tries变量。对于需要三个输入(名称、密码、暂停)的批处理文件,这太少了。

主要问题是,没有办法检测子进程是否真的在等待我们的输入。这是我们必须在这里解决的问题。但是暂时停止产生输出并不总是意味着程序现在等待输入。

我修复了你的最后一个GOTO跳转到批处理文件的开头,并使用以下代码进行了两次尝试,第二次输入了正确的密码。

try {
    Process process = Runtime.getRuntime().exec(command);
    try(Writer writer = new OutputStreamWriter(process.getOutputStream());
        Reader reader = new InputStreamReader(process.getInputStream())) {

        CharBuffer buf = CharBuffer.allocate(80);
        int tries = 2;
        while(process.isAlive()) {
            do {
                if(!buf.hasRemaining()) {
                    buf.flip();
                    buf = CharBuffer.allocate(buf.capacity()*2).put(buf);
                }
                do {} while(reader.ready() && reader.read(buf) > 0);
                if(buf.position() > 0) {
                    char c = buf.get(buf.position()-1);
                    if(c==':' || c=='.') break;
                }
                long deadLine = System.nanoTime() + TimeUnit.SECONDS.toNanos(1);
                for(long remaining = 1;
                        !reader.ready() && process.isAlive() && remaining > 0;
                        remaining = deadLine - System.nanoTime()) {
                    LockSupport.parkNanos(Math.min(
                        TimeUnit.MILLISECONDS.toNanos(100),
                        remaining));
                }
            } while(reader.ready());

            String input = buf.flip().toString();
            buf.clear();
            System.out.print(input);
            String value;
            if(input.endsWith("name:")) value = "aName";
            else if(input.endsWith("password:")) value = tries>1? "wrongPassword": "1234";
            else {
                value = "<any key>";
                tries--;
            }
            System.out.println("<- "+value);
            writer.write(value);
            writer.flush();
            if(tries == 0) {
                System.out.println("Destroying");
                process.destroy();
                break;
            }
        }
    }
} catch(IOException e) {
    e.printStackTrace();
}

当然,如果您无法修复该GOTO语句,则必须在第一次尝试时提供正确的密码。

上面的代码将最多等待一秒钟以等待新输出的可用性,除非它识别出输出中的预期提示之一。当进程不再存在时,它不会等待。


推荐阅读