4

ターゲット デバイス (スマートフォン) でスクリプトを実行し、while ループで stdout メッセージを待機しているメイン プログラムがあります。ただし、この特定のケースでは、stdout のハートビート メッセージの一部は、ほぼ 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();
}    

そのため、必要なスリープ ウィンドウで stdout から行を読み取った後、新しい割り込み可能なスレッドを開始できるようにしたいと考えています。新しい行を読み取れるようになったら、中断/停止(プロセスの強制終了に問題がある)、標準出力テキストの改行を処理してプロセスを再起動できるようにしたいと考えています。

そして、タイマー ウィンドウ (たとえば 45 秒) 内で行を読み取ることができないイベントが発生した場合、while ループから抜け出す方法も必要です。

私はすでにthread.run、thread.interruptアプローチを試しました。しかし、新しいスレッドを強制終了して開始するのに問題があります。

これが最善の方法ですか、それとも明らかな何かが欠けていますか?

4

2 に答える 2

3

の実装は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;
        }
      }
    }
  }

}
于 2010-05-18T23:35:20.357 に答える
0

特に以前に ScheduledExecutorService を使用したことがないことを考えると、それは確かにより洗練されたソリューションのように思えます。しかし、私はまだすべてのピースをまとめるのに苦労しています! ワーカーが 45 秒のカウントダウンのために呼び出されたかどうか、いつ呼び出されたかはわかりません。また、私の意図は、そのようなワーカーが stdout の行に遭遇したらカウントダウンを再開し、基本的にカウントダウンを新しい 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;
        }
    }
}
于 2010-05-19T01:12:10.747 に答える