2011-12-07 20 views
5

Robię program z pętli while, które realizują w ten sposób:Java: Empty pętli while

  1. Główny wątek wchodzi do pętli while.
  2. Nic się nie dzieje w pętli while.
  3. Gwint pozostanie w pętli while, dopóki warunek nie zostanie spełniony.
  4. Kolejny wątek uruchamia funkcję, która spełni dany warunek.

Oto przykład:

while(path != null); 

Jest inna funkcja w klasie, które będą określać ścieżkę zerową, a gdy tak się stanie główny wątek powinien wyjść z pętli. Inna funkcja jest wywoływana w innym wątku.

Jednak wątek główny nie opuszcza pętli, nawet jeśli ścieżka ma wartość null. Jakieś sugestie?

KOD:

try 
{ 
    for (Node n:realpath) 
    { 
     Thread.sleep(100); 
     actor.walk(n); 
    } 
    Thread.sleep(100); 
} 
catch (InterruptedException ex) 
    { 
    Logger.getLogger(VNScreen.class.getName()).log(Level.SEVERE, null, ex); 
    } 
    realpath.clear(); 
    path = null; 

if(path == null) 
    System.out.println("NULLED PATH"); 
+2

jeśli ciebie opublikuj swój pełny kod, ludzie będą mogli łatwiej znaleźć Twój problem. – ewok

+0

Ktoś zajął się tym za Ciebie, @AbrahamMiguelEspiritu, ale w przyszłości lepiej jest edytować oryginalne pytanie, aby dodać kod. Jest o wiele bardziej czytelny. – Paul

+0

Wykazać, że ścieżka jest ustawiona na wartość null, rejestrując ją. Nie jestem przekonany, że wątek jest wykonywany. – emory

Odpowiedz

10

Zajęty czekanie jest bardzo drogie. Zrobiłbym to w ten sposób:

Object LOCK = new Object(); // just something to lock on 

synchronized (LOCK) { 
    while (path != null) { 
     try { LOCK.wait(); } 
     catch (InterruptedException e) { 
      // treat interrupt as exit request 
      break; 
     } 
    } 
} 

Następnie po ustawieniu path null, po prostu zadzwoń

synchronized (LOCK) { 
    LOCK.notifyAll(); 
} 

(Można tylko zsynchronizować na this jeśli oba fragmenty kodu są w tym samym obiekcie.)

+0

Dziękuję bardzo, myślisz, gdzie powinna być ta zmienna 'lock', w klasie, która wywołuje' wait' lub w klasie, która 'notifyAll'? –

+1

@ HalilİbrahimOymacı - Myślę, że to nie ma znaczenia, o ile zmienna jest dostępna dla wszystkich kodów, które jej potrzebują. Może to być nawet oddzielny obiekt singletonowy w swojej klasie. –

3

Prawdopodobnie trzeba zadeklarować path być volatile. Jeśli zmienna nie zostanie zadeklarowana jako volatile, wówczas kompilator ma swobodę buforowania jej wartości w rejestrze, a zatem każda zmiana wartości nie zostanie rozpoznana.

Ale ogólnie ten styl kodu jest bardzo zły (z wyjątkiem niektórych rzeczy w niskim trybie rzeczywistym). Podczas gdy twoja pętla while zapętla się, zużywa 100% CPU, więc jakikolwiek inny proces może zmienić wartość path, może nigdy nie uzyskać cykli do wykonania, oraz innych procesów, które wykonują codzienne czynności, takie jak utrzymywanie połączeń komunikacyjnych lub aktualizowanie położenia kursora myszy nie uruchomi się.

Najlepsze jest wykonanie komunikacji opartej na zdarzeniach/wiadomościach/semaforach, aby twoja "pętla" czekała na sygnał przed kontynuowaniem. "Akceptowalne" polega na wykorzystaniu pewnego opóźnienia, na przykład Thread.sleep, tak abyś tylko "odpytywał" zmienną co kilka milisekund, powiedzmy. Możesz także spróbować Thread.yield, ale to coś w rodzaju "crap-shoot" i nie przyniosłoby wiarygodnych wyników w różnych środowiskach.

-1

główny wątek nie wychodzi z pętli, ponieważ ponieważ w warunku while nic nie działa, a warunek sprawdzania działa bardzo szybko i nie ma zmiennego znaczenia.masz 2 drogę do rozwiązania tego problemu: 1 w pętli while czeka na krótki czas np 5ms

while(path != null){ 
    try{ 
     Thread.currentThread().sleep(50); 
    }catch(){ 
     //do nothing 
    } 
    } 

2 zdefiniować zmienną path jako lotny:

volatile String path; 
+0

Model pamięci Java nie daje żadnej gwarancji, że pierwsze rozwiązanie będzie działać. Jest nawet prawdopodobne, że nie zadziała, jeśli uruchomisz go z argumentem '-serwer', ponieważ warunek zostanie zoptymalizowany i przekształcony na' while (true) '. – assylias

1

Zamiast używać niski podejście do wyczekiwania/powiadamiania na poziomie i aby uniknąć zajętego czekania z lotną, można użyć numeru CountDownLatch. Ponieważ istnieje tylko jedno zdarzenie, aby oczekiwać wystąpienia zatrzask jak:

CountDownLatch latch = new CountDownLatch(1); 

zastąpić while (path != null) z:

latch.await(); 

oraz w głównym kodzie, po prostu zrobić:

path = somePath; 
latch.countDown();