7 Temmuz 2019 Pazar

CountDownLatch Sınıfı - Tüm Thread'lerin Bitmesini Beklemek İçindir

Giriş
Şu satırı dahil ederiz.
import java.util.concurrent.CountDownLatch;
CountdownLatch ve CompletableFuture
Eğer sonuç dönmek istersek bu sınıf  yerine CompletableFuture kullanılabilir.

CountdownLatch ve Semaphore Farkı
CountdownLatch ve Semaphore ilk bakışta iki yapı da birbirlerine benziyor gibi görünüyor ancak farklı işlere yarıyorlar.

Semaphore serbest olan kaynakları sayan bir sayaç. CountDownLatch thread'lerin buluşma noktası olarak kullanılıyor. CountDownLatch isminden de anlaşıldığı gibi sadece geriye sayım yapan (tek yönlü) bir sayaç.

Yani Semaphore ise hem aşağı hem de yukarı oynayabilen (çift yönlü) bir sayaç. Ayrıca CountDownLatch vs. Semaphore sorusu da göz atmaya değer.

CountdownLatch ve CyclicBarrier
Her iki sınıf ta benzer işi görür. CountDownLatch tekrar sıfırlanıp kullanılamaz.. CyclicBarrier ise tekrar kullanılabilir.

Abort İşlemi
Eğer thread'lerden birisi geriye sayımı iptal etmek isterse diğer thread'leri haberdar etmenin bir yolu yok. Tek çözüm CountDownLatch sınıfından kalıtmak. Şöyle yaparız.

Kullanım
Açıklaması şöyle
The CountDownLatch class enables us to coordinate threads by introducing awareness of the number of threads that are carrying out related tasks and keeping track of the number of threads that have completed their task.

This is done by initializing the CountDownLatch with the number of worker threads. Each worker thread should then invoke the countDown() method on the CountDownLatch. The thread that needs to wait for the worker threads to complete should invoke the await() method on the CountDownLatch. This will cause this thread to wait until all worker threads have invoked the countDown() method, in effect counting down from the number of worker threads to zero. Once the countdown reaches zero, the thread calling await() can proceed.
Yani iki tane önemli metod var. Bunlar 
1. countDown() . Sayacı bir eksiltir
2. await() : Sayacın 0 olmasını bekler

Örnek - Threal'leri Aynı Anda Başlatmak
Şöyle yaparız
private static final int PARTIES = 3;

public static void main(String[] args) throws InterruptedException {
  CountDownLatch entryBarrier = new CountDownLatch(1);
  CountDownLatch exitBarrier = new CountDownLatch(PARTIES);
  for (int p = 0; p < PARTIES; p++) {
    int delay = p + 1;
    Runnable task = new Worker(delay, entryBarrier, exitBarrier);
    new Thread(task).start();
  }
  logger.info("all threads waiting to start");
  sleep(1);
  entryBarrier.countDown();
  logger.info("all threads started");
  exitBarrier.await();
  logger.info("all threads finished");
}
Thread tarafında şöyle yaparız
private static class Worker implements Runnable {
  private final int delay;
  private final CountDownLatch entryBarrier;
  private final CountDownLatch exitBarrier;
  Worker(int delay, CountDownLatch entryBarrier, CountDownLatch exitBarrier) {
    this.delay = delay;
    this.entryBarrier = entryBarrier;
    this.exitBarrier = exitBarrier;
  }
  @Override
  public void run() {
    try {
      entryBarrier.await();
      work();
      exitBarrier.countDown();
    } catch (InterruptedException e) {
      throw new RuntimeException(e);
     }
   }
  private void work() {
    logger.info("work {} started", delay);
    sleep(delay);
    logger.info("work {} finished", delay);
   }
}
Örnek - Threal'lerin Bitmesini Beklemek

Elimizde şöyle bir kod olsun.
private static class MyTimerTask extends TimerTask {

  private CountDownLatch latch;

  public MyTimerTask(CountDownLatch lock) {
    this.latch = lock;
  }

  @Override
  public void run() {
    System.out.println("inside timer");
    latch.countDown();
  }
}
Şöyle yaparız.
CountDownLatch cdl = new CountDownLatch(1);
Timer timer = new Timer();
timer.schedule(new MyTimerTask(cdl), 3000);

try {
  cdl.await();
} catch (InterruptedException ex) {
}

//execute this code after timer finished
System.out.println("finish");
Diğer
CountDownLatch basitçe şöyle de gerçekleştirilebilirdi.
Integer threadCount = 10;

for (int i = 0; i < threadCount; i++)
{
  new Thread(() ->
  {
    try
    {
      doFirst();
      synchronized (threadCount)
      {
        threadCount--;
        while (threadCount > 0)
          threadCount.wait();
        threadCount.notifyAll();
      }
      doSecond();
    }
    catch (Exception e) { e.printStackTrace(); }
  }).start();
}

// all threads are started, to wait until they've finished, call threadCount.wait();
constructor metodu - int
Sayacı ilklendirir. Şöyle yaparız.
CountDownLatch latch = new CountDownLatch(1);
coundDown metodu
Thread içinde çağrılır. Sayıcın değerini düşürür. Şöyle yaparız.
latch.countDown();
await metodu - TimeUnit 
İmzası şöyle.
boolean await(long timeout, TimeUnit unit);
Açıklaması şöyle
The boolean await(long timeout, TimeUnit unit) method causes the current thread to wait until one of the events occurs:
- the given timeout elapses
- the latch has counted down to 0 due to calls of the countDown() method
- the thread is interrupted

The method returns true if the current count reached 0 and false if the timeout elapsed before the current count reached 0. If the current count is 0 then this method returns true immediately.
Sayacın 0 olmasını bekler. Şöyle yaparız. InterruptedException fırlatabilir.
long timeout = ...;
TimeUnit unit = ...;
if (!latch.await(timeout, unit))
{
  throw new TimeoutException();
}
...
await metodu 
Açıklaması şöyle
The void await() method causes the current thread to wait until one of the events occurs:
- the latch has counted down to 0 due to calls of the countDown() method
- the thread is interrupted

If the current count is 0 then this method returns immediately.
Örnek
Şöyle yaparız. InterruptedException fırlatabilir.
 try {
  latch.await();
} catch (InterruptedException ex) {
}
getCount metodu
Açıklaması şöyle
The long getCount() method returns the current count of the latch.

Hiç yorum yok:

Yorum Gönder