2012-11-24 7 views
8

jestem coraz IllegalThreadStateException wyjątek przy użyciu następującego kodu: już rozpoczęła ten wątek raz (przy użyciu thread.start()) i ponownie próbuje uruchomić go w innym miejscu, więc używany następujący kod:Zatrzymaj nić i ponownie rozpocząć podając IllegalThreadStateException w jeżyna

thread.interrupt(); 
thread.start(); 

Ale thread.start() rzuca IllegalThreadStateException.

Co powinienem użyć, aby go rozwiązać?

+1

właśnie dodano znacznik 'java', ponieważ jest on wspólny dla każdego' java'. –

Odpowiedz

16

Thread obiekty mają być uruchamiane tylko jeden raz. Jeśli musisz się zatrzymać/przerwać Thread, a następnie chce uruchomić go ponownie, należy utworzyć nową instancję, i nazywają start() na nim:

thread.interrupt(); // if you need to make sure thread's run() method stops ASAP 
thread = new MyThreadSubclass(); 
thread.start(); 

From the API docs

IllegalThreadStateException - jeśli wątek już się rozpoczął.

wiem, że to nie jest w 100% jasne, że nie można nazwać start() ponownie, nawet jeśli wcześniej nazywana interrupt(), ale tak właśnie to działa.

Jeśli spojrzeć na API docs for standard Java, ten problem jest bardziej przejrzysty.

+0

Dzięki Nate. Ale kiedy próbowałem użyć "thread.interrupt();" Ponownie pokazuje wyjątek jako - ** IllegalThreadStateException **. – AnkitRox

+0

@AnkitRox, dokumenty API nie pokazują, że 'interrupt()' zgłasza wszelkie wyjątki. Jednak domyślam się, że nazywasz 'interrupt()' jeszcze przed pierwszym uruchomieniem tego kodu. Naprawdę wystarczy przerwać wątek, jeśli został on uruchomiony raz. Tak więc, drugi, trzeci itd. Razy, które chcesz nazwać 'start()', możesz nazwać 'interrupt()' wcześniej. Możesz przetestować 'thread.isAlive()' przed wywołaniem 'thread.interrupt()'. Jeśli to nie zadziała, musisz pokazać więcej kodu (np. Jak utworzyć obiekt Thread). – Nate

+0

Mam klasy jako 'AsyncUploadQuestionsAndLeads', który jest rozszerzony o' wątek'. Inicjowanie obiektu wątku za pomocą: 'AsyncUploadQuestionsAndLeads uploadThread = new AsyncUploadQuestionsAndLeads (event);' i rozpoczęcie wątku z innego miejsca: 'uploadThread.start();' Po pewnym czasie, jestem używanie kodu jako: 'uploadThread.interrupt(); uploadThread.start(); ' Oto moja procedura kodowa, którą stosowałem. Jeszcze jedno Pytanie - czy wątek zatrzymuje się sam, kiedy kończy swój blok? – AnkitRox

7

Oprócz odpowiedzi Nate'a.

stany AnkitRox w swoim komentarzu:

Dzięki Nate. Próbowałem też twojej metody. Ale pojawił się problem w tym czasie, był to początek nowego wątku dla nowej instancji i poprzedni wątek również działał.

Wygląda więc na to, że problem jest „nitka wciąż działa nawet wtedy, gdy zadzwoniłem przerwanie na nim”. Rozważmy tę próbkę (jest brzydki, ale wystarczy, aby pokazać główną ideę):

final Thread t = new Thread(new Runnable() { 
    public void run() { 
     while (true) { 
      for (int i = 0; i < 100000000; i++); // simulate some action 
      System.out.println("hi, interrupted = " 
        + Thread.currentThread().isInterrupted()); 
     } 
    } 
}); 
t.start(); 
new Timer(true).schedule(
    new TimerTask() { 
     public void run() { 
      t.interrupt(); 
     } 
    }, 
    1000 // 1 second delay 
); 

Uwaga, wątek kontynuuje działanie nawet po interrupt() została wywołana. Wydajność produkowana to:

hi, interrupted = false 
hi, interrupted = true 
hi, interrupted = true 
hi, interrupted = true 
... 
hi, interrupted = true 

W rzeczywistości program nigdy się nie kończy, chyba że zostanie zamknięty. Więc co wtedy robi interrupt()? Ustawia on po prostu flagę przerwaną na na true. Po nazwie interrupt() został nazwany Thread.currentThread().isInterrupted() zaczyna zwracać false. I to wszystko.

Innym przykładem jest sytuacja, gdy interrupt() nazywa natomiast wątek jest zablokowany w wywołanie jednej z metod, które rzucają InterruptedException, wówczas sposób powraca wyrzuceniem InterruptedException.A jeśli kod wątku tylko „zjada” to wyjątek, to wątek będzie nadal działa, należy rozważyć próbkę:

final Thread t = new Thread(new Runnable() { 
    public void run() { 
     while (true) { 
      System.out.println("hi, interrupted = " 
        + Thread.currentThread().isInterrupted()); 
      try { 
       Thread.sleep(5000); 
      } catch (InterruptedException e) { 
       System.out.println("got InterruptedException"); 
      } 
     } 
    } 
}); 
t.start(); 
new Timer(true).schedule(
    new TimerTask() { 
     public void run() { 
      t.interrupt(); 
     } 
    }, 
    1000 // 1 second delay 
); 

Uwaga, wątek kontynuuje działanie nawet po interrupt() została wywołana. Wytworzony wyjściowy:

hi, interrupted = false 
got InterruptedException 
hi, interrupted = false 
hi, interrupted = false 
... 
hi, interrupted = false 

Uwaga, tym razem interrupted = false nawet po interrupt() została wywołana. Dzieje się tak dlatego, że gdy zostanie przechwycone InterruptedException, flaga przerywana zostanie zresetowana do false.

W języku Java zatrzymywanie wątku jest mechanizmem spółdzielczym. Oznacza to, że nie można tego zrobić bez współpracy z samym wątkiem. Oto ustalona wersja powyższej próbki:

final Thread t = new Thread(new Runnable() { 
    public void run() { 
     while (!Thread.currentThread().isInterrupted()) { 
      System.out.println("hi, interrupted = " 
        + Thread.currentThread().isInterrupted()); 
      try { 
       Thread.sleep(5000); 
      } catch (InterruptedException e) { 
       System.out.println("we've been interrupted"); 
       // restore the interrupted flag 
       Thread.currentThread().interrupt(); 
      } 
     } 
    } 
}); 
t.start(); 
new Timer(true).schedule(
    new TimerTask() { 
     public void run() { 
      t.interrupt(); 
     } 
    }, 
    1000 // 1 second delay 
); 

więc prawidłowe podejście powinno być okresowo sprawdzać przerwany flagę. A jeśli wykryty zostanie stan przerwania, po prostu zwróć ASAP. Inną popularną opcją nie jest używanie w ogóle Thread.interrupt(), ale some custom boolean instead.

+0

świetne wyjaśnienie. wcale nie brzydki :) – Nate

Powiązane problemy