2013-05-26 13 views
25

Oświadczam, że czytam o wątku, ale nigdy go nie użyłem. Więc pytam się ciebie :)Jak wstrzymać, a następnie wznowić wątek?

Mam dwie wątek: A i B, gdzie A zarządza GUI i B zarządza logiki.

Zacznę od A.

Następnie, gdy A narysuje GUI, przerywam go, aby czekać B, który osiągnie punkt X w metodzie run.

A kiedy B osiągnie punkt X do metody uruchamiania, zatrzymuję się na B i wznawiam A.

A i B akcji niektóre zmienna zarządzania GUI i logiki ...

Czy mogę to zrobić? jeśli tak, w jaki sposób? :)

+1

Tak, możesz to zrobić. Jest to podstawowe ćwiczenie wątków. Spróbuj to zrobić, jeśli Ci się nie uda, jesteśmy tu, by Ci pomóc :) – Maroun

+3

Cała idea posiadania wielu wątków polega na tym, że nie musisz wyraźnie pauzować/plonować/etc z nimi, ponieważ wiele wątków działa jednocześnie będą one dać kawałek czasu procesora w uczciwy, zrównoważony sposób. (W szczególności powinieneś próbować nigdy nie wstrzymywać wątku GUI, aby GUI zawsze reagowało) Tak, możesz to zrobić, ale nie sądzę, że musisz. – Patashu

+0

Tylko notatkę. Swing to środowisko z pojedynczym wątkiem, co oznacza, że ​​wszystkie interakcje i modyfikacje któregokolwiek z elementów interfejsu użytkownika muszą być dokonywane w kontekście wątku Dispatch Dispatching. Swing nie jest bezpieczny dla wątków, co oznacza, że ​​nigdy nie powinieneś próbować dostępu, aktualizować ani tworzyć żadnych elementów interfejsu użytkownika z dowolnego wątku innego niż EDT ... zakładaj, że używasz Swing, który jest – MadProgrammer

Odpowiedz

14

Stosując wait() i notify() metody:

oczekiwania() - Powoduje bieżącego wątku czekać, aż do następnej nici wywołuje powiadamia() Metoda z lub metody notifyAll() dla tego obiektu.

notify() - Budzi pojedynczy wątek oczekujący na monitorze tego obiektu.

+4

Polecam 'Semafor' jako uniknięcie typowych pułapek w' zsynchronizowanych' i 'wait' /' notify'. –

4

Spodziewam się, że nie trzeba wstrzymywać wątku GUI. System operacyjny zajmie się tym i musi być gotowy na odpowiedź w przypadku, gdy użytkownik coś zrobi.

Jeszcze jedna myśl polega na upewnieniu się, że współdzielone zmienne są poprawnie zsynchronizowane między dwoma wątkami. Próbowałem odpowiedzieć na pytanie dotyczące tego ostatnio, zobacz here.

3

można użyć numeru CountDownLatch. Kiedy wątek A musi poczekać na wątek B, zadzwoni countDownLatchInstance.await(); Gdy B osiągnie punkt X, wywoła countDownLatchInstance.countDown(); pozwalając A na kontynuację przepływu wykonawczego.

Kiedy mówisz

zarządza GUI

Mam nadzieję, że nie odnoszą się do UI/Main Thread

,

+0

Osobiście polecam 'Semaphore' zamiast' CountDownLatch', ponieważ 'CountDownLatch' nie może być ponownie użyty ... –

0

Java prymitywny zawiesić i wznowić wątku jest przestarzałe. Zobacz to zrozumieć w jaki sposób można osiągnąć najlepsze, co trzeba - http://docs.oracle.com/javase/7/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html Sprawdź jak można zrobić równowartość zawieszenia & wznowienia

Co należy używać zamiast Thread.suspend i Thread.resume?

Podobnie jak w przypadku Thread.stop, ostrożnym podejściem jest, aby sonda "docelowy wątek" była zmienną wskazującą pożądany stan wątku (aktywny lub zawieszony). Gdy żądany stan jest zawieszony, wątek czeka przy użyciu Object.wait. Gdy wątek zostanie wznowiony, wątek docelowy zostanie powiadomiony przy użyciu Object.notify.

Przykładowy kod jest podany w tej samej odpowiedzi, aby pomóc Ci to osiągnąć.

6

Możesz blokować wątki przy użyciu metod klasy Object, ale może to być trudne. Oto przykład wewnątrz nieskończoną pętlę w miłym Runnable:

public class Example implements Runnable {  
    private volatile boolean running = true; 
    private volatile boolean paused = false; 
    private final Object pauseLock = new Object(); 

    @Override 
    public void run() { 
     while (running){ 
      synchronized (pauseLock) { 
       if (!running) { // may have changed while waiting to 
           // synchronize on pauseLock 
        break; 
       } 
       if (paused) { 
        try { 
         pauseLock.wait(); // will cause this Thread to block until 
              // another thread calls pauseLock.notifyAll() 
              // Note that calling wait() will 
              // relinquish the synchronized lock that this 
              // thread holds on pauseLock so another thread 
              // can acquire the lock to call notifyAll() 
              // (link with explanation below this code) 
        } catch (InterruptedException ex) { 
         break; 
        } 
        if (!running) { // running might have changed since we paused 
         break; 
        } 
       } 
      } 
      // Your code here 
     } 
    } 

    public void stop() { 
     running = false; 
     // you might also want to interrupt() the Thread that is 
     // running this Runnable, too, or perhaps call: 
     resume(); 
     // to unblock 
    } 

    public void pause() { 
     // you may want to throw an IllegalStateException if !running 
     paused = true; 
    } 

    public void resume() { 
     synchronized (pauseLock) { 
      paused = false; 
      pauseLock.notifyAll(); // Unblocks thread 
     } 
    } 
}; 

(Aby uzyskać więcej informacji na temat dlaczego musimy synchronizować jak pokazano powyżej wzywając jednocześnie wait i notifyAll patrz the Java tutorial on the subject.)

Jeśli inny wątek nazywa to Runnable to metoda pause(), a następnie wątek uruchamiający programowanie zostanie zablokowany po dojściu do początku pętli while.

Należy pamiętać, że nie można wstrzymać wątku w dowolnym punkcie. Potrzebujesz wątku, aby okresowo sprawdzał, czy powinien się zatrzymać i sam się zablokować.

+0

Zsynchronizowałeś się z pauseLock, metodą wznowienia, więc oczekiwanie nigdy nie zostanie powiadomione, powyższe spowoduje zakleszczenie –

+2

@DrBDOAdams 'wait' i' notify' musi ** zawsze ** zostać wywołane w bloku 'synchronized'. Zobacz [tutaj] (http: // stackoverflow.com/questions/2779484/why-must-wait-always-be-in-synchronized-block) i [here] (https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html). Rzeczywiście, 'IllegalMonitorStateException' zostanie wygenerowany, jeśli spróbujesz inaczej. Zauważ, że gdy wywoływane jest 'wait()', bieżący wątek zwalnia blokadę, którą trzyma na tym obiekcie, umożliwiając innym wątkom jego zdobycie. – megaflop

+1

Wywołanie "interrupt();" (lub nawet "Thread.interrupt();) wydaje się błędne, ponieważ ta klasa nie rozszerza" Thread ". Czy powinno to być zamiast tego wywołanie funkcji 'resume();'? –

1

tak to mam czekać wątku i powiadomić pracuje dla mnie:

public class Main { 

public static void main(String[] args) { 

    final Object lock = new Object(); 


    MyThread t = new MyThread(); 
    t.lock = lock; 
    t.run(); 

    while(true){ 
     try { 
      synchronized (lock) { 
       lock.wait(); 
      } 
      System.out.println("hello"); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     }    
    }  
} 

}

public class MyThread rozciąga Temat {

Object lock; 

@Override 
public void run(){ 

    JFrame fr = new JFrame("Anothing"); 
    JButton btn = new JButton("Next"); 
    btn.addActionListener(new ActionListener() { 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      synchronized (lock) { 
       lock.notify(); 
      } 

     } 
    }); 
    fr.setLayout(new FlowLayout()); 
    fr.add(btn); 
    fr.setSize(400, 400); 
    fr.setVisible(true); 
} 

}

Potem, ilekroć Naciskam przycisk, drugi wątek budzi się, wykonuje jedną rundę i czeka na nową cli cking.

Powiązane problemy