2

system.inの読み取りを中断することについて、SOには多くのスレッドがありますが、ここで私が探しているのは、私が達成しようとしていることを最適にコーディングする方法に関するある種のアドバイスです。

次のことを行う必要があるgetlogin()メソッドがあります。6秒後にユーザーが有効な値(「ライブ」または「テスト」)を入力しなかった場合、ユーザーに目的のログイン環境の詳細を入力するように依頼し、userlogin変数を「テスト」に設定します。そしてそれを発信者に返します。

私は実装のために次のアプローチを取りましたgetlogin()

  1. 次のことを行う2つのスレッドを起動します。

    • thread1スキャナーオブジェクトを作成してから呼び出しscanner.nextline()、ユーザー入力に応じて変数を設定しますuserlogin。終了する前にthread2を中断しthread1ます。
    • thread26秒間待機し、userloginそれでもまだ設定されていない場合は、のデフォルト値を設定しますuserloginthread1終了する前に中断しthread2ます。
  2. mainがnullとして返されるthread2のを停止するために参加しますThreaduserlogin

  3. userloginを返す

このアプローチで私が抱えている問題は、呼び出しscanner.nextline()時に中断しないことです。そのため、メインがハングするため、手順2に参加しません。中断した後に完了する方法はありますか?それとも、このアプローチは完全にやり過ぎであり、契約を達成するためのはるかに簡単な方法がありますか?thread2thread1.interruptthread1Threadthread1thread2

4

4 に答える 4

4

最も簡単な解決策は、「読み取り」スレッドで基になるストリームを公開し、タイムアウト スレッドからそのストリームを閉じることです。これにより、読み取りが中断され、例外が発生します。この例外を処理すると、ロジックを続行できるはずです。唯一の問題は、同じストリームを再利用できないことです。残念ながら、ブロッキング システム コールの中断に対処する簡単な方法はありません。

編集:

まったく異なる推論に従ってください。中断するためだけに入力ストリームを閉じることはできないため、私が考える唯一の方法は、Robot クラスが提供する「プログラムによるユーザー入力」機能を使用することです。これが私にとってうまくいく例です:

import java.awt.Robot;
import java.awt.event.KeyEvent;
import java.util.Scanner;
import java.util.concurrent.TimeUnit;

public class ConsoleTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        new TimeoutThread().start();
        new ReaderThread().start();
    }

}

class ReaderThread extends Thread {

    @Override
    public void run() {
        System.out.print("Please enter your name: ");
        try(Scanner in = new Scanner(System.in)) {
            String name = in.nextLine();
            if(name.trim().isEmpty()) {
                name = "TEST"; // default user name
            }
            System.out.println("Name entered = " + name);
        }
    }

}

class TimeoutThread extends Thread {

    @Override
    public void run() {
        try {
            Thread.sleep(TimeUnit.SECONDS.toMillis(5));
            Robot robot = new Robot();
            robot.keyPress(KeyEvent.VK_ENTER);
            robot.keyRelease(KeyEvent.VK_ENTER);
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

}

上記のコードは、タイムアウトの期限が切れると、"name" 変数を空白にする改行をシミュレートするというロジックを使用しています。次に、必要なロジックを実行し、適切なユーザー名を設定するチェックがあります。

上記のアプローチに関する落とし穴は、次のことです。

  • AWT の Robot クラスを使用しているため、ヘッドレス端末ではうまく動作しない可能性があります (?)
  • フォーカス ウィンドウがコンソール ウィンドウであると想定します。フォーカスが別の場所にある場合、ENTERアプリケーション ウィンドウではなく、そのウィンドウにキーを押したことが登録されます。

これがお役に立てば幸いです。私は今、本当にアイデアがありません。:)

于 2012-10-09T15:15:16.213 に答える
0

ラムダ式とともに FutureTask を使用することもできます。

FutureTask<String> readNextLine = new FutureTask<String>(() -> {
  return scanner.nextLine();
});

ExecutorService executor = Executors.newFixedThreadPool(2);
executor.execute(readNextLine);

try {
  String token = readNextLine.get(5000, TimeUnit.MILLISECONDS);
  ...
} catch (TimeoutException e) {
  // handle time out
}
于 2017-01-13T16:47:03.787 に答える