2012-08-11 12 views
10

Czy istnieje sposób użycia ExecutorService do wstrzymania/wznowienia określonego wątku?Java ExecutorService wstrzymuje/wznawia określony wątek

private static ExecutorService threadpool = Executors.newFixedThreadPool(5);

Wyobraźmy sobie, że chce zatrzymać Wich gwintu jako id = 0 (przy założeniu, że każda z nich jest przypisany identyfikator przyrostowej do wielkości puli wątków osiągnięciu).

Po chwili, naciskając przycisk, powiedzmy, chcę wznowić ten wątek i pozostawić wszystkie pozostałe wątki z ich bieżącym stanem, który można wstrzymać lub wznowić.

Na dokumentacji Java znalazłem niezakończoną wersję PausableThreadPoolExecutor. Ale to nie odpowiada temu, czego potrzebuję, ponieważ wznawia wszystkie wątki w puli.

Jeśli nie ma sposobu, aby to zrobić z domyślną implementacją ExecutorService, czy ktoś może wskazać mi implementację Java dla tego problemu?

Dzięki!

+0

Czy jesteś pewien?Wątek o podanym identyfikatorze wykonuje wybrane losowo zadanie, więc zatrzymujesz nieznaną pracę. Jaki to ma sens? –

+0

Wyobraź sobie następującą sytuację: Masz menedżera pobierania i na tym menedżerze możesz zatrzymać i wznowić pobieranie. Dla każdego, z którego pobierasz dane, nie ma znaczenia, co nie jest istotne, i chcesz zatrzymać pobieranie, aby wznowić je w dowolnym miejscu. Czy to sprawia, że ​​pytanie jest dla ciebie bardziej jasne? –

+0

Bardziej przejrzysty, ale nadal mało sensowny. Zatrzymywanie/wznawianie pobierania dotyczy logiki biznesowej, a wątek dotyczy zasobów obliczeniowych. Kontrolowanie logiki przez dodawanie/usuwanie zasobów to zły pomysł IMHO. –

Odpowiedz

7

Jesteś na niewłaściwym torze. Pula wątków jest właścicielem wątków i udostępnianie ich za pomocą kodu może zepsuć sytuację.
Powinieneś skupić się na , wykonując swoje zadania (przekazane do wątków odwołalnych/przerywalnych) i nie wchodzić w interakcje z wątkami posiadanymi bezpośrednio przez pulę.
Dodatkowo nie będzie wiedział, co praca jest wykonywana w momencie usiłuje przeszkodzić w wątku, więc nie mogę zrozumieć, dlaczego byłbyś zainteresowany robieniem tego

Aktualizacja:
Właściwym sposobem anuluj zadanie przesłane w puli wątków za pośrednictwem Future dla zadania zwróconego przez executor.
1) W ten sposób można wiedzieć na pewno, że zadanie rzeczywiście mają na celu próbuje się odwołany
2) Jeśli zadania są już przeznaczone do odwoływalny wówczas są w połowie drogi
3) Nie używaj flagę wskazać anulowanie ale zamiast używać Thread.currentThread().interrupt()

Aktualizacja:

public class InterruptableTasks { 

    private static class InterruptableTask implements Runnable{ 
     Object o = new Object(); 
     private volatile boolean suspended = false; 

     public void suspend(){   
      suspended = true; 
     } 

     public void resume(){  
      suspended = false; 
      synchronized (o) { 
       o.notifyAll(); 
      } 
     } 


     @Override 
     public void run() { 

      while(!Thread.currentThread().isInterrupted()){ 
       if(!suspended){ 
        //Do work here  
       } 
       else{ 
        //Has been suspended 
        try {     
         while(suspended){ 
          synchronized(o){ 
           o.wait(); 
          }       
         }      
        } 
        catch (InterruptedException e) {      
        }    
       }       
      } 
      System.out.println("Cancelled");   
     } 

    } 

    /** 
    * @param args 
    * @throws InterruptedException 
    */ 
    public static void main(String[] args) throws InterruptedException { 
     ExecutorService threadPool = Executors.newCachedThreadPool(); 
     InterruptableTask task = new InterruptableTask(); 
     Map<Integer, InterruptableTask> tasks = new HashMap<Integer, InterruptableTask>(); 
     tasks.put(1, task); 
     //add the tasks and their ids 

     Future<?> f = threadPool.submit(task); 
     TimeUnit.SECONDS.sleep(2); 
     InterruptableTask theTask = tasks.get(1);//get task by id 
     theTask.suspend(); 
     TimeUnit.SECONDS.sleep(2); 
     theTask.resume(); 
     TimeUnit.SECONDS.sleep(4);     
     threadPool.shutdownNow();  
    } 
+0

Czy możesz być bardziej konkretny i zapewnić mi prawdziwą implementację lub przykład? Naprawdę to doceniam, ponieważ przez dłuższy czas zmagam się z tym problemem. –

+0

@RicardoSantos: Ale dlaczego nie możesz anulować zadań? Nie jest dobrym pomysłem interakcja z wątkami, których twój kod nie jest bezpośrednio własnością użytkownika – Cratylus

+0

Zgadzam się z zaleceniem, aby zadania odwoływano. OP napisał: "wyobraź sobie, że chcę zatrzymać wątek id = 0". Nie ma to większego sensu, ponieważ w danym momencie nie wiesz, co robi wątek 0. Ale sensowne jest mówienie o zaprzestaniu wykonywania niektórych prac, stąd zalecenie dotyczące anulowania zadań. –

4

Sugestia: Podobnie jak w/zamiast flagi, której używasz, stworzyć semaphore z 1 zezwolenie (new Semaphore(1)) fo r każde zadanie, które należy wstrzymać/wznowić. Na początku cyklu roboczego za zadanie umieścić kod tak:

semaphore.acquire(); 
semaphore.release(); 

Powoduje to zadanie zdobycia pozwolenia semaforów i natychmiast puścić. Teraz, jeśli chcesz wstrzymać wątek (na przykład naciśnięty jest przycisk), zadzwoń pod numer semaphore.acquire() z innego wątku. Ponieważ semafor ma teraz 0 zezwoleń, wątek roboczy zostanie wstrzymany na początku następnego cyklu i poczekaj, aż zadzwonisz pod numer semaphore.release() z innego wątku.

(Metoda acquire() rzuca InterruptedException, jeśli wątek roboczy zostanie przerwany podczas oczekiwania. Nie ma innej metody acquireUninterruptibly(), który również stara się zdobyć pozwolenie, ale nie zostanie przerwana.)

+0

Oczywiście działa, ale brzmi bardziej jak włamanie i jest to lepsze podejście niż robienie niczego. Dziękuję za odpowiedź. Przetestuję twoje podejście i @ user384706 i zobaczę, który z nich ma lepszą wydajność. –