2013-09-26 14 views
31

Mam wątku, który oczekiwał na wartości logicznej zmienić tak:Czekaj, aż wartość logiczna zmienia jej stan

while(!value) 
{ 
    Thread.sleep(1000) 
} 
// Do some work after change of the value 

To nie jest moja preferowana sposób to zrobić, przyczyną ogromnego zużycia procesora.

Czy istnieje sposób blokowania wątku, dopóki wartość boolowska nie zmieni stanu?

Odpowiedz

58

To nie jest mój preferowany sposób, aby to zrobić, powodując ogromne zużycie procesora.

Jeśli to faktycznie działa kod, to po prostu zachowaj go w ten sposób. Sprawdzanie wartości logicznej raz na sekundę powoduje NIE wymierne obciążenie procesora. Absolutnie nic.

Prawdziwy problem polega na tym, że wątek sprawdzający wartość może nie zauważyć zmiany, która wydarzyła się przez arbitralnie długi czas z powodu buforowania. Aby upewnić się, że wartość jest zawsze zsynchronizowane między wątków, trzeba umieścić lotnych słowo kluczowe w definicji zmiennej, tj

private volatile boolean value; 

Należy zauważyć, że wprowadzenie dostępu w synchronized bloku, na przykład podczas korzystania z rozwiązania powiadamiania opartej opisane w innych odpowiedziach, będzie miało taki sam efekt.

+4

+1 za sugerowanie "lotnego" ... – TheLostMind

7

Jak o wait-notify

private Boolean bool = true; 
private final Object lock = new Object(); 

private Boolean getChange(){ 
    synchronized(lock){ 
    while (bool) { 
     bool.wait(); 
    } 
    } 
    return bool; 
} 
public void setChange(){ 
    synchronized(lock){ 
     bool = false; 
     bool.notify(); 
    } 
} 
+7

'bool' jest zmiennym polem, którego nie można zsynchronizować. – axtavt

+0

umm ... to w rzeczywistości egzekucyjny Point @axtavt. –

+0

A teraz synchronizujesz na nieostatnim polu. W 'setChange' najpierw ją zmodyfikujesz, a następnie powiadomisz nową instancję' false'. Wynik: wątek oczekujący na wcześniejszą "prawdziwą" instancję nigdy nie zostanie powiadomiony. Jeszcze jeden dobry przykład, dlaczego * uniknąć * tego całego mechanizmu. –

34

Potrzebny jest mechanizm, który zapobiega zajęty-oczekiwania. Stary wait/notify mechanizm jest obarczona pułapek więc wolą coś z biblioteki java.util.concurrent, na przykład CountDownLatch:

public final CountDownLatch latch = new CountDownLatch(1); 

public void run() { 
    latch.await(); 
    ... 
} 

a na drugim wywołaniu bocznej

yourRunnableObj.latch.countDown(); 

Jednak rozpoczynając wątek nic nie robić, ale czekać, aż będzie to potrzebne, nadal nie jest najlepszą drogą. Można również zatrudnić pracownika, którego zadanie należy wykonać, gdy warunek zostanie spełniony.

+0

Pomaga mi to w testowaniu biblioteki Quartz wewnątrz JUnit. Kwarc uruchamia swoje zadania w blackboksie, które ma własną pulę wątków. Mogę zasygnalizować JUnit, aby oczekiwał na zakończenie zadań kwarcowych przy użyciu dokładnego wzorca określonego w dokumentacji java. –

+0

Czy mogę zasugerować 'Java.util.concurrent.BlockingQueue' i jego różne implementacje? Metody "take()" i "offer()" są świetnym miejscem do rozpoczęcia synchronizacji. – Groostav

1

Wolę używać mechanizmu mutex w takich przypadkach, ale jeśli naprawdę chcesz używać wartości boolean, to powinieneś zadeklarować ją jako zmienną (aby zapewnić widoczność zmian między wątkami) i po prostu uruchomić cykl bez ciała z tą wartością logiczną jako warunek:

//.....some class 

volatile boolean someBoolean; 

Thread someThread = new Thread() { 

    @Override 
    public void run() { 
     //some actions 
     while (!someBoolean); //wait for condition 
     //some actions 
    } 

}; 
+15

Czy to nie przebije procesora? –

2

Ok może ten powinien rozwiązać twój problem. Zauważ, że za każdym razem, gdy wprowadzasz zmianę, wywołujesz metodę change(), która zwalnia oczekiwanie.

Integer any = new Integer(0); 

public synchronized boolean waitTillChange() { 
    any.wait(); 
    return true; 
} 

public synchronized void change() { 
    any.notify(); 
} 
+2

Integer jest niezmienny, nie można zmienić jego wartości – Andrejs

Powiązane problemy