需要一个基于Java的可中断定时器线程

发布于 2024-09-02 08:42:25 字数 599 浏览 3 评论 0原文

我有一个主程序,它正在目标设备(智能手机)上运行脚本,并在一个 while 循环中等待标准输出消息。然而,在这种特殊情况下,标准输出上的一些心跳消息可能会间隔近 45 秒到 1 分钟。

例如:

stream = device.runProgram(RESTORE_LOGS, new String[] {});
stream.flush();
String line = stream.readLine();
while (line.compareTo("") != 0) {
    reporter.commentOnJob(jobId, line);
    line = stream.readLine();
}    

所以,我希望能够在从标准输出读取行并需要睡眠窗口后启动一个新的可中断线程。在能够读取新行后,我希望能够中断/停止(无法终止进程)、处理标准输出文本的换行符并重新启动进程。

如果我无法在计时器窗口(比如 45 秒)内读取一行,我也想找到一种方法来摆脱 while 循环。

我已经尝试过 thread.run、thread.interrupt 方法。但在杀死并启动新线程时遇到困难。

这是最好的出路还是我错过了一些明显的事情?

I have a Main Program which is running a script on the target device(smart phone) and in a while loop waiting for stdout messages. However in this particular case, some of the heartbeat messages on the stdout could be spaced almost 45secs to a 1minute apart.

something like:

stream = device.runProgram(RESTORE_LOGS, new String[] {});
stream.flush();
String line = stream.readLine();
while (line.compareTo("") != 0) {
    reporter.commentOnJob(jobId, line);
    line = stream.readLine();
}    

So, I want to be a able to start a new interruptible thread after reading line from stdout with a required a sleep window. Upon being able to read a new line, I want to be able to interrupt/stop(having trouble killing the process), handle the newline of stdout text and restart a process.

And it the event I am not able to read a line within the timer window(say 45secs) I want to a way to get out of my while loop either.

I already tried the thread.run, thread.interrupt approach. But having trouble killing and starting a new thread.

Is this the best way out or am I missing something obvious?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

豆芽 2024-09-09 08:42:25

看起来 System.in 的实现在不同平台上差异很大,特别是并不总是提供可中断性或异步关闭。

这是一种不依赖于这些功能的解决方法,但代价是无法正确清理;如果在超时到期之前未收到输入,Consumer 线程将处于阻塞的 read() 状态。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;

class InterruptInput
{

  private static final String EOF = new String();

  private final SynchronousQueue<String> pipe = new SynchronousQueue<String>();

  private final BufferedReader input;

  private final long timeout;

  InterruptInput(BufferedReader input, long timeout)
  {
    this.input = input;
    this.timeout = timeout;
  }

  public static void main(String... argv)
    throws Exception
  {
    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    InterruptInput input = 
      new InterruptInput(in, 5000);
    input.read();
  }

  void read()
    throws InterruptedException
  {
    System.out.println("Enter lines of input (or empty line to terminate):");
    Thread t = new Consumer();
    t.start();
    while (true) {
      String line = pipe.poll(timeout, TimeUnit.MILLISECONDS);
      if (line == EOF)
        break;
      if (line == null) {
        System.out.println("Input timed-out.");
        t.interrupt();
        break;
      }
      System.out.println("[input]: " + line);
    }
  }

  private class Consumer
    extends Thread
  {

    Consumer()
    {
      setDaemon(true);
    }

    @Override
    public void run()
    {
      while (!Thread.interrupted()) {
        String line;
        try {
          line = input.readLine();
        }
        catch (IOException ex) {
          throw new RuntimeException(ex);
        }
        try {
          if ((line == null) || (line.length() == 0)) {
            pipe.put(EOF);
            break;
          }
          else {
            pipe.put(line);
          }
        }
        catch (InterruptedException ex) {
          break;
        }
      }
    }
  }

}

It looks like the implementation of System.in varies considerably across platforms and, in particular, doesn't always offer interruptibility or asynchronous closure.

Here is a workaround that doesn't rely on those features, but at the cost of failing to clean up properly; if input isn't received before the timeout expires, the Consumer thread is left in a blocking read().

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;

class InterruptInput
{

  private static final String EOF = new String();

  private final SynchronousQueue<String> pipe = new SynchronousQueue<String>();

  private final BufferedReader input;

  private final long timeout;

  InterruptInput(BufferedReader input, long timeout)
  {
    this.input = input;
    this.timeout = timeout;
  }

  public static void main(String... argv)
    throws Exception
  {
    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    InterruptInput input = 
      new InterruptInput(in, 5000);
    input.read();
  }

  void read()
    throws InterruptedException
  {
    System.out.println("Enter lines of input (or empty line to terminate):");
    Thread t = new Consumer();
    t.start();
    while (true) {
      String line = pipe.poll(timeout, TimeUnit.MILLISECONDS);
      if (line == EOF)
        break;
      if (line == null) {
        System.out.println("Input timed-out.");
        t.interrupt();
        break;
      }
      System.out.println("[input]: " + line);
    }
  }

  private class Consumer
    extends Thread
  {

    Consumer()
    {
      setDaemon(true);
    }

    @Override
    public void run()
    {
      while (!Thread.interrupted()) {
        String line;
        try {
          line = input.readLine();
        }
        catch (IOException ex) {
          throw new RuntimeException(ex);
        }
        try {
          if ((line == null) || (line.length() == 0)) {
            pipe.put(EOF);
            break;
          }
          else {
            pipe.put(line);
          }
        }
        catch (InterruptedException ex) {
          break;
        }
      }
    }
  }

}
雨落□心尘 2024-09-09 08:42:25

这确实看起来是一个更优雅的解决方案,特别是考虑到我以前没有使用过 ScheduledExecutorService 。但我仍然在努力将所有的碎片拼凑在一起!我不确定工作人员是否以及何时调用其 45 秒倒计时?另外,我的目的是让这样的工作人员在遇到一行标准输出时重新启动倒计时,实质上将倒计时重置为新的 45 秒窗口。这有助于澄清吗?

当我努力将 ScheduledExecutorService 合并到我的解决方案中时,这里是我用来使用线程复制它的完整示例代码。让我知道你是否能比我更早到达。我能够在遇到的每个 stdout 换行符上调用一个线程,但在声明的时间窗口内没有发生中断时无法优雅地处理这种情况:( 希望代码中的注释足够详细地传达我的意图,否则请让我我知道并且我可以澄清:

import java.io.BufferedReader;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.channels.Channels;

public class InterruptInput {   
    static BufferedReader in = new BufferedReader(
            new InputStreamReader(
            Channels.newInputStream(
            (new FileInputStream(FileDescriptor.in)).getChannel())));
    boolean TimeUp = false;

    public static void main(String args[]) {
        try {

            System.out.println("Enter lines of input (user ctrl+Z Enter to terminate):");
            System.out.println("(Input thread will be interrupted in 10 sec.)");
            // interrupt input in 10 sec

            String line = in.readLine();
            while ((line.compareTo("") != 0)) {
            System.out.println("Read line:'"+line+"'");
        TimeOut ti = new TimeOut();
        Thread t = new Thread(ti);
        t.start();
        if((line = in.readLine()) != null) {
            t.interrupt();
            }
            }
        System.out.println("outside the while loop");
        } catch (Exception ex) {
            System.out.println(ex.toString()); // printStackTrace();
        }
    }

    public static class TimeOut extends Thread {
        int sleepTime = 10000;
        private volatile Thread threadToInterrupt;    
        public TimeOut() {
            // interrupt thread that creates this TimeOut.
            threadToInterrupt = Thread.currentThread();
            setDaemon(true);
        }

    public void run() {
        System.out.println("starting a new run of the sleep thread!!");
            try {
                sleep(10000); // wait 10 sec
            } catch(InterruptedException ex) {/*ignore*/
        System.out.println("TimeOut thread interrupted!!");
        //I need to exit here if possible w.out executing
            //everything after the catch block
        }
           //only intend to come here when the 10sec wait passes
           //without interruption. Not sure if its plausible

        System.out.println("went through TimeOut without interruption");
        //TimeUp = true;
        }
    }
}

that sure seems like a more elegant solution, especially given I haven't used ScheduledExecutorService before. But I'm still struggling to put all the pieces together though! I'm not sure if and when worker invoked for its 45sec countdown? Also, my intention is for such a worker to restart the countdown once it encounters a line of stdout, essentially resetting the countdown to a fresh 45sec window. Does that help clarify.

While I work to incorporate ScheduledExecutorService into my solution, here's the entire sample code i've been using to replicate it using the threads. Lemme know if I you get it to sooner than I can. I am able to invoke a thread on every newline of stdout I come across, but cannot gracefully handle the case when no interruption occurs for the declared time window :( Hope the comments in the code detailed enough to convey my intentions, else pls let me know and I could clarify:

import java.io.BufferedReader;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.channels.Channels;

public class InterruptInput {   
    static BufferedReader in = new BufferedReader(
            new InputStreamReader(
            Channels.newInputStream(
            (new FileInputStream(FileDescriptor.in)).getChannel())));
    boolean TimeUp = false;

    public static void main(String args[]) {
        try {

            System.out.println("Enter lines of input (user ctrl+Z Enter to terminate):");
            System.out.println("(Input thread will be interrupted in 10 sec.)");
            // interrupt input in 10 sec

            String line = in.readLine();
            while ((line.compareTo("") != 0)) {
            System.out.println("Read line:'"+line+"'");
        TimeOut ti = new TimeOut();
        Thread t = new Thread(ti);
        t.start();
        if((line = in.readLine()) != null) {
            t.interrupt();
            }
            }
        System.out.println("outside the while loop");
        } catch (Exception ex) {
            System.out.println(ex.toString()); // printStackTrace();
        }
    }

    public static class TimeOut extends Thread {
        int sleepTime = 10000;
        private volatile Thread threadToInterrupt;    
        public TimeOut() {
            // interrupt thread that creates this TimeOut.
            threadToInterrupt = Thread.currentThread();
            setDaemon(true);
        }

    public void run() {
        System.out.println("starting a new run of the sleep thread!!");
            try {
                sleep(10000); // wait 10 sec
            } catch(InterruptedException ex) {/*ignore*/
        System.out.println("TimeOut thread interrupted!!");
        //I need to exit here if possible w.out executing
            //everything after the catch block
        }
           //only intend to come here when the 10sec wait passes
           //without interruption. Not sure if its plausible

        System.out.println("went through TimeOut without interruption");
        //TimeUp = true;
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文