2010-03-01 11 views
6
import java.util.Arrays; 
import java.util.Iterator; 
import java.util.List; 
import java.util.concurrent.Callable; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.Future; 
import java.util.concurrent.TimeUnit; 

class Task implements Callable<String> { 
    public String call() throws Exception { 
     String s = "initial"; 
     try { 
      System.out.println("Started.."); 
      /*for (int i=0;i<10000;i++) { 
       if (i % 2 == 0) { 
        System.out.println("Even"); 
       } 
      }*/ 
      boolean flag = true; 
      while(flag) { 

      } 
      System.out.println("Finished!"); 
      s = "Done"; 
     } 
     catch (RuntimeException e) { 
      s = "RuntimeException"; 
     } 
     catch (Exception e) { 
      s = "Exception"; 
     } 
     finally { 

     } 
     return s; 
    } 
} 

public class ExecutorServiceTest { 

    public static void main(String[] args) throws Exception { 
     ExecutorService executor = Executors.newSingleThreadExecutor(); 
     List<Future<String>> result = executor.invokeAll(Arrays.asList(new Task()), 5, TimeUnit.SECONDS); 
     executor.shutdown(); 
     Iterator<Future<String>> iter = result.iterator(); 
     while (iter.hasNext()) { 
      System.out.println("Came here"); 
      Future<String> fut = iter.next(); 
      System.out.println(fut.get()); 
     } 
    } 
} 

Czy istnieje sposób, w jaki mogę zatrzymać wątek wykonujący nieskończoną pętlę?Zatrzymaj nieskończoną pętlę w zadaniu ExecutorService

Odpowiedz

7

Tak, można zamienić flag (lub logicznie &&) na !Thread.currentThread().isInterrupted().

W ten sposób, gdy zadanie jest canceled,, pętla zostanie zakończona.

Pętla będzie wyglądać mniej więcej tak:

while(!Thread.currentThread().isInterrupted() && flag) { 
    /* Do work. */ 
} 

stosowanie powinno być coś takiego:

ExecutorService executor = Executors.newSingleThreadExecutor(); 
Future<String> task = executor.submit(new Task()); 
String str; 
try { 
    str = task.get(5, TimeUnit.SECONDS); 
} finally { 
    task.cancel(true); 
} 
0

myśleć o użyciu synchronized (this) { this.wait() } zamiast sleep wewnątrz call(), a następnie po ustawieniu logiczną flag zewnętrznie (być może bezpośrednio lub za pomocą metody flag(), z bezpośrednim dostępem upewnij się, że zmienna flagi to volatile) zadzwoń pod numer task.notifyAll(), aby obudzić śpiący wątek (upewnij się, że obiekt zadania jest zmienną lokalną zamiast anonimowej, aby można było wywoływać metody na nim i uczynić flagę atrybutem klasy w zakresie Task).

Będzie to również bardziej skuteczne, ponieważ niepotrzebnie zapętla cykle odpadów - dokładny mechanizm nazywany jest "strzeżonym blokiem" (http://java.sun.com/docs/books/tutorial/essential/concurrency/guardmeth.html). Po przebudzeniu się z oczekiwania przetestuj zmienną flagi, aby upewnić się, że została ustawiona.

Edytuj: przyjrzało się bliżej oryginalnemu pytaniu i stworzyło przykład używając istniejącego kodu i zasad (jest więcej niż jeden sposób na skórze kota :)). Spróbuj tego - pętla zostanie zamknięta z powodu przerwanego stanu bieżącego wątku, który został anulowany z powodu przekroczenia limitu czasu:

package ett; 
import java.util.Arrays; 
import java.util.List; 
import java.util.concurrent.Callable; 
import java.util.concurrent.CancellationException; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.Future; 
import java.util.concurrent.TimeUnit; 

class Task implements Callable<String> { 
    public String call() throws Exception { 
     String s = "initial"; 
     System.out.println("Started.."); 
     for (int i=0;;i++) { 
      if (i % 2 == 0) { 
       System.out.println("Even"); 
      } 
      Thread.yield(); 
      if (Thread.interrupted()) break; 
     } 
     System.out.println("Finished!"); 
     s = "Done"; 

     return s; 
    } 
} 

public class ExecutorServiceTest { 

    public static void main(String[] args) throws Exception { 
     ExecutorService executor = Executors.newSingleThreadExecutor(); 
     List<Future<String>> result = executor.invokeAll(Arrays.asList(new Task()), 1, TimeUnit.SECONDS); 
     executor.shutdown(); 

     System.out.println("came here"); 

     for (Future<String> f : result) { 
      try { 
       System.out.println(f.get()); 
      } catch (CancellationException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
} 
Powiązane problemy