0

専用スレッドを持つ長いタスクがあります。たとえば、次のようにします。

public static class WorkerThread extends Thread{

    @Override public void run () {
        for (int i = 1; i<=10; i++) {
            System.out.println("worker thread progress: " + i + "/10");
            try{Thread.sleep(1000);} catch (InterruptedException ignore) {}
        }

    System.out.println("the worker thread HAS FINISHED!");

    }

}

このタスク中に、ユーザーが長いタスクをキャンセルするためにコマンドラインを聞きたいです。System.in の特性により、コードは次のようになります (つまり、割り込み可能なコンソール読み取りが必要な場合は、ポーリングを使用する必要があります)。

public static class InputThread extends Thread {

    @Override public void run() {
       try{
           StringBuilder sb = new StringBuilder(); 

           do {
                while (System.in.available()==0) { Thread.sleep(200); }

                sb.append((char)System.in.read());

           } while (!sb.toString().equals("cancel\n"));

           System.out.println("the user-input thread HAS FINISHED!");

       } catch (IOException ignored) {} catch (InterruptedException ie) {}
    }

}

では、2 つのスレッドを使用してみましょう。ケースは次のとおりです。

  • WorkerThread は InputThread より前に終了します。この場合、ユーザーがスレッドをキャンセルする可能性がなくなるため、(適切に) InputThread を中断する必要があります。
  • InputThread は WorkerThread より前に終了します。ユーザーが「キャンセル」コマンドを入力したため、WorkerThread を (適切に) 中断する必要があります

優雅にとは、もちろんコードが中断可能でなければならないことを意味しますが、これは問題のポイントではありません。問題は、2 つのスレッドを開始した後、「最初のスレッドが終了する」のをどのように待つかということです。

public static void main (String [] args) throws InterruptedException {

    InputThread it = new InputThread();

    it.start();

    WorkerThread wt = new WorkerThread();

    wt.start();


}
4

5 に答える 5

1

これを行う 1 つの方法は、 を使用して、両方のランナブルの のExecutorServiceステータスを追跡することです。Future以下に小さな例を示します。

ExecutorService es = Executors.newFixedThreadPool(2); // InputThread and WorkerThread
try {
    Future<?> workerFuture = es.submit(workerThread);
    Future<?> inputFuture = es.submit(inputThread);

    while(!inputFuture.isDone() && !workerFuture.isDone()) {
        // Sleep and check status again until one of the thread is complete
    }

    if(inputFuture.isDone()) { // User inputs "cancel", so cancel worker thread
        workerFuture.cancel();
    } else { // Worker thread is complete, cancel the input thread
        inputFuture.cancel();
    }

} finally {
    es.shutdown();
}
于 2013-06-02T17:14:45.617 に答える
1

ExecutorService通信には と 割り込みを使用して 2 つのスレッドを使用できます。

private static class Worker implements Runnable {

    @Override
    public void run() {
        for (int i = 1; i <= 10; i++) {
            System.out.println("worker thread progress: " + i + "/10");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ex) {
                System.out.println("We have been cancelled");
                return;
            }
        }
    }
}

private static class Monitor implements Runnable {

    private final Future<?> workerFuture;

    public Monitor(Future<?> workerFuture) {
        this.workerFuture = workerFuture;
    }

    @Override
    public void run() {
        try (final BufferedReader br =
                new BufferedReader(new InputStreamReader(System.in))) {
            while (true) {
                if (br.ready()
                        && "cancel".equals(br.readLine())) {
                    System.out.println("Input is cancel, kill worker.");
                    workerFuture.cancel(true);
                    return;
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException ex) {
                    System.out.println("Mointor cancelled. Stop.");
                    return;
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

public static void main(String[] args) throws Exception {
    final ExecutorService executorService = Executors.newCachedThreadPool();
    final Future<?> longTask = executorService.submit(new Worker());
    final Future<?> monitor = executorService.submit(new Monitor(longTask));
    //wait for long task to complete
    try {
        longTask.get();
        monitor.cancel(true);
        System.out.println("Main task finished normally.");
    } catch (CancellationException ex) {
        System.out.println("Main task killed.");
    }
    executorService.shutdown();
    executorService.awaitTermination(1, TimeUnit.DAYS);
}

Worker中断して動作し、完了または中断されると終了します。

Monitor中断して読み取ります。読み取りが「キャンセル」の場合は、を介してExecutorServiceに割り込みを要求します。WorkerFuture

メインスレッドはWorkerが完了するのを待ち、 が正常に終了した場合はを強制終了するFutureように要求します。ExecutorServiceMonitorWorker

于 2013-06-02T17:14:54.213 に答える
1

ループでポーリングを行います (クラスが であると仮定しますT04):

public static void main (String [] args) throws InterruptedException {  

    InputThread it = new InputThread();
    it.start();

    WorkerThread wt = new WorkerThread();
    wt.start();

    while(true) {           //I think this works as polling
       if(it.isFinished()) {
           wt.finish();
           return;
       } 
       else if(wt.isFinished()) {
           it.finish();
           return;
       }
       try{Thread.sleep(50);} catch (InterruptedException ignore) {}
    }
}

そして、このコードをクラスに追加しますInputThread(スーパークラスを実行してコードを再利用できます):

public class InputThread extends Thread {
private boolean finished = false;

@Override 
public void run() {
   try{
       StringBuilder sb = new StringBuilder(); 

       do {
            while (!this.finished && System.in.available()==0) { Thread.sleep(200); }

            if(this.finished) 
                return;
            else
                sb.append((char)System.in.read());

       } while (!sb.toString().equals("cancel\n") && !this.finished);                   

       System.out.println("the user-input thread HAS FINISHED!");

       this.finished = true;

   } catch (IOException ignored) {} catch (InterruptedException ie) {}
}

public boolean isFinished() {
    return this.finished;
}

public void finish(){
    this.finished = true;
}

}

そして、あなたWorkerThreadは次のようになります:

public class WorkerThread extends Thread{
public boolean finished = false;

@Override 
public void run () {
    for (int i = 1; i<=10; i++) {
        if(this.finished)
            return;
        System.out.println("worker thread progress: " + i + "/10");
        try{Thread.sleep(1000);} catch (InterruptedException ignore) {}
    }

    System.out.println("the worker thread HAS FINISHED!");
    this.finished = true;
}

public boolean isFinished() {
    return this.finished;
}

public void finish(){
    this.finished = true;
}
}
于 2013-06-02T17:08:00.677 に答える
0

あなたの質問に答えるには:Thread.join()参照されたスレッドが終了するまで現在のスレッドを待機させます-それをメインメソッドで使用します。

また、割り込みに使用することを計画している場合は、(少なくとも) 外側のループでThread.interrupt()status-check ( ) も必要になります。キャッチするだけでは十分ではなく、現在待機している場合にのみスローされます。別のポイントでも中断されます。!isInterrupted()InterruptedExceptionsleep()

于 2013-06-02T16:33:50.127 に答える