2012-09-25 15 views
5

Jestem nowy w wielowątkowości i Podczas gdy czytam o wielowątkowości, myśli o napisaniu tego fantazyjnego kodu wielowątkowości, aby wykonać następujące czynności.Jak czekać z wątku1, aż do powiadomienia przez wątek2

Moja klasa licznika wygląda następująco.

class Counter { 
    private int c = 0; 

    public void increment() { 
    System.out.println("increment value: "+c); 
     c++; 
    } 

    public void decrement() { 
     c--; 
     System.out.println("decrement value: "+c); 
    } 

    public int value() { 
     return c; 
    } 

} 

Ten obiekt licznika jest dzielony między dwa wątki. Po rozpoczęciu wątków muszę wykonać następujące czynności. Chcę, aby wątek2 czekał, aż wątek1 zwiększy liczbę obiektów licznika o 1. Po wykonaniu tej czynności wątek 1 informuje wątek2, a następnie wątek1 rozpocznie oczekiwanie, aż wątek2 zmniejszy wartość o 1. Następnie wątek2 rozpocznie i zmniejszy wartość o 1 i ponownie informuje wątek1, a następnie wątek2 rozpoczyna oczekiwanie na wątek1. Powtórz ten proces kilka razy.

Jak mogę to osiągnąć. Z góry bardzo dziękuję.

Wykonałem następujące czynności.

public class ConcurrencyExample { 

    private static Counter counter; 
    private static DecrementCount t1; 
    private static IncrementCount t2; 

    public static void main(String[] args) { 
    Counter counter = new Counter(); 
    Thread t1 = new Thread(new IncrementCount(counter)); 
    t1.start(); 

    Thread t2 = new Thread(new DecrementCount(counter)); 
    t2.start(); 

    } 

} 


public class DecrementCount implements Runnable { 

    private static Counter counter; 

    public DecrementCount(Counter counter) { 
    this.counter = counter; 
    } 

    @Override 
    public void run() { 
    for (int i = 0; i < 1000; i++) { 
     counter.decrement();  
     System.out.println("decreamented"); 
    } 
    } 

} 


public class IncrementCount implements Runnable { 

    private static Counter counter; 

    public IncrementCount(Counter counter) { 
    this.counter = counter; 
    } 

    @Override 
    public void run() { 
    for (int i = 0; i < 1000; i++) { 
     counter.increment(); 
     System.out.println("Incremented"); 
    } 

    } 

} 
+2

Zobacz CountDownLatch: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/CountDownLatch.html – davidmontoyago

+1

'IncrementCount' powinien wywołać' increment() ', prawda? –

+1

Najprostszym sposobem na to byłoby użycie jednego wątku. Proponuję rozważyć przykłady, w których używanie wielu wątków byłoby szybsze, a nie bardziej skomplikowane i wolniejsze. –

Odpowiedz

3

Wyjazd Semaphore. Będziesz potrzebował dwóch, po jednym dla każdego wątku: incSemaphore i decSemaphore. W DecrementCount zrobić:

for (int i = 0; i < 1000; i++) { 
    decSemaphore.acquire(); 
    counter.decrement();  
    System.out.println("decreamented"); 
    incSemaphore.release(); 
} 

Wdrożenie IncrementCount symetrycznie. Początkowa wartość incSemaphore powinna wynosić 1 i 0 dla decSemaphore.

BTW Twój Counter wymaga synchronizacji, jak również (patrz synchronized słowa kluczowego i AtomicInteger).

+0

+1 dla przejrzystości. – dcernahoschi

0

Użyj Condition z flagą boolowską.

final Lock lock = new ReentrantLock(); 
final Condition incremented= lock.newCondition(); 
final Condition decremented= lock.newCondition(); 

Zmień swój licznik do poniżej

Objaśnienie:

Użyliśmy dwóch warunków jest zwiększany i jeden z nich jest zmniejszany. w oparciu o flagę boolowską sprawdzamy, czy musimy czekać na jeden warunek, czy nie.

class Counter { 
private int c = 0; 
boolean increment = false; 

final Lock lock = new ReentrantLock(); 
final Condition incremented = lock.newCondition(); 
final Condition decremented = lock.newCondition(); 

public void increment() throws InterruptedException { 
    Lock lock = this.lock; 
    lock.lock(); 
    try { 
     while(increment) 
      decremented.await(); 
     increment = true;   
     c++; 
     System.out.println("increment value: " + c); 
     incremented.signal(); 
    } finally { 
     lock.unlock(); 
    } 

} 

public void decrement() throws InterruptedException { 

    Lock lock = this.lock; 
    lock.lock(); 
    try { 
     while (!increment) 
      incremented.await(); 
     c--; 
     System.out.println("decrement value: " + c); 
     increment = false; 
     decremented.signal(); 
    } finally { 
     lock.unlock(); 
    } 
} 

public int value() { 
    Lock lock = this.lock; 
    lock.lock(); 
    try { 
     return c; 
    } finally { 
     lock.unlock(); 
    } 
} 

} 
+0

Czy ktoś może wytłumaczyć -1? –

+0

Początkowo odpowiedź była mniej niż pożyteczna. Lepiej teraz. – Gray

+0

@Gray Dostarczony kod również. –

0

- Pierwszy swój increment() i decrement() musi używać synchronized słowa kluczowego, aby uniknąć Race Stan widoczny Zasada ta Briana

When we write a variable which has just been read by another thread, or reading a variable which is just lately written by another thread, must be using Synchronization. And those atomic statements/Methods accessing the fields' data must be also synchronized.

- Jego JVM Thread Scheduler że ma kontrolować, który wątek wejdzie w stan działania, jak długo jej tam pozostanie i dokąd pójdzie po zakończeniu swojej pracy.

- Jeden Cannot be sure którego wątek zostanie uruchomiony pierwszy .....

- Można również użyć SingleThreadExecutor z java.util.concurrent ta uzupełnia jedno zadanie przed przeniesieniem się na sekundę.

+0

błędnie cytujesz regułę Briana, ale i tak nie jest ona poprawna. Użycie lotnych jest również rozwiązaniem. –

+0

@MartinSerrano przede wszystkim, jeśli nie masz udokumentowanego dowodu, że jakieś stwierdzenie jest błędne, nie wskaż tego źle. Po drugie, zapoznaj się z czwartą edycją rozdziału "Myślenie w języku Java" Bruce'a Eikle'a, jeśli masz jakiekolwiek wątpliwości ... Teraz REGUŁA BRIANA, CO MÓWIŁEM TU, JEST PRAWA i myślę, że jeszcze nie grałeś wystarczająco płynnie. Sprawienie, że pole jest niestabilne, nie upewnia się, że instrukcje uzyskujące dostęp do tego pola mają postać Pojedynczego oświadczenia atomowego ..... –

Powiązane problemy