2011-08-22 15 views
5

Próba przerwania działającego wątku, w tym przykładzie, t1, który jest wykonywany przez wątek w puli wątków.Przerwanie wątku spania

t2 to ten, który wysyła przerwanie.

Nie mogę zatrzymać działającego t1, t1 nie otrzymuje wyjątku InterruptedException.

Czego mi brakuje?

Executor exec1 = Executors.newFixedThreadPool(1); 

    // task to be interrupted 
    Runnable runnable = new Runnable() { 
     @Override 
     public void run() { 
      try { 
       System.out.println("starting uninterruptible task 1"); 
       Thread.sleep(4000); 
       System.out.println("stopping uninterruptible task 1"); 
      } catch (InterruptedException e) { 
       assertFalse("This line should never be reached.", true); 
       e.printStackTrace(); 
      }    
     }   
    }; 
    final Thread t1 = new Thread(runnable); 


    // task to send interrupt 
    Runnable runnable2 = new Runnable() { 
     @Override 
     public void run() { 
      try { 
       Thread.sleep(1000); 
       t1.interrupt(); 
       System.out.println("task 2 - Trying to stop task 1"); 
       Thread.sleep(5000); 

      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      }    
     }   
    }; 
    Thread t2 = new Thread(runnable2); 

    exec1.execute(t1); 
      t2.start(); 
    t2.join(); 

Odpowiedz

3

Wygląda na to, że źle zrozumiałeś wątki i Executory. Tworzysz dwa wątki dla dwóch runnables, ale uruchamiasz tylko jeden z nich (t2), t1, który przechodzisz do Executora, aby uruchomić wewnątrz niego. Ale executor nie potrzebuje Nici do dostarczenia - wymaga jedynie implementacji Runnable. Sam Executor jest pulą wątków (zwykle, ale nie jest wymagana), a po prostu tworzy (i gromadzi) wątki wewnątrz niej. Widzi, że wątek jest równie prosty, co Runnable (czyli narzędzia wątku). Tak naprawdę wysyłasz przerwanie do wątku, który nigdy się nie rozpoczął.

Jeśli naprawdę chcesz, aby twój kod działał, powinieneś usunąć Executora i po prostu uruchomić oba wątki jawnie.

+0

Dzięki BegemoT. To ma sens. – portoalet

+0

begemot ma to prawo –

0

Aby przerwać wątek Executora,

final ExecutorService exec1 = Executors.newFixedThreadPool(1); 
final Future<?> f = exec1.submit(runnable); 
... 
f.cancel(true); 
+0

Problem polega na tym, że 'Runnable' będzie teraz wykonywane dwukrotnie: raz przez pulę wątków, a raz przez wątek' t1'. –

+0

Używam executora do wykonania wątku. – portoalet

+0

'final Future f = exec1.submit (runnable); f.cancel (true);' –

0

Wywołanie Thread.interrupt niekoniecznie rzucić InterruptedException. Może po prostu ustawić przerwany stan wątku, który może być odpytywany przez Thread.interrupted() lub Thread.isInterrupted.

Aby uzyskać więcej informacji, patrz http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Thread.html#interrupt().

+0

Myliłeś się, przeczytaj uważnie dokumentację. Metoda intterupt powoduje przerwany wyjątek, jeśli przerwana wątek śpi .. –

+0

.. .Jeżeli przerwana nitka śpi ... To właśnie miałem na myśli, może wątek nie śpi, kiedy zostanie przerwany. – mort

+0

, ale wątek na pytanie jest stan snu .. –

3

Twoim błędem jest to, że próbujesz wykonać Thread na ThreadPool.

Ten pojawia do pracy, ponieważ Thread stanie wdrożyć Runnable, ale dlatego, że wątek jest tylko używany jako Runnable i nie jest uruchamiany jako Thread, wywołanie metody jak #interrupt() nie będzie miał pożądanego efektu.

Jeśli nadal potrzebujesz puli wątków, powinieneś zamiast tego skorzystać z klasy takiej jak FutureTask. Owiń swoją Runnable w FutureTask, a następnie prześlij zadanie do puli wątków. Następnie, gdy chcesz przerwać zadanie, zadzwoń pod numer futureTask.cancel(true).

1

Problem polega na tym, że nigdy nie wiadomo, który wątek zostanie użyty przez Executor do uruchomienia zadania.

Mimo że przesłano obiekt Thread, Executor użyje wątku utworzonego przez ustaloną pulę wątków. W związku z tym wątek z odniesieniem t1 nie jest wątkiem, w którym twoje zadanie zostanie wykonane. więc wywołanie t1.interrupt() nic nie da.

Aby właściwie to zrobić, należy użyć obiektu ExecutorService i użyć obiektu submit() do przesłania obiektu o rozmiarze Runnable/Callable. To zwróci wartość Future, która ujawnia metodę cancel(), której można użyć do anulowania zadania.

Powiązane problemy