Executors etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
Executors etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

2 Ocak 2023 Pazartesi

Executors.newCachedThreadPool metodu - Sınırsız Sayıda Thread Kullanır OOM Verebilir

Giriş
Açıklaması şöyle. Kısa süren hemen cevap verilmesi gereken işler için uygundur. Ayrıca ani artışlar gösteren (burst) iş sayısına da uyum sağlar. Şeklen şöyle. Belirtilen süre geçince thread sayısının azaldığı görülebilir

Bu Executor tipini Swing uygulamasında uzun vadeli işleri (long term) çalıştırmak için kullandım.
Creates a thread pool that creates new threads as needed, but will reuse previously constructed threads when they are available. These pools will typically improve the performance of programs that execute many short-lived asynchronous tasks. Calls to execute will reuse previously constructed threads if available. If no existing thread is available, a new thread will be created and added to the pool. Threads that have not been used for sixty seconds are terminated and removed from the cache. Thus, a pool that remains idle for long enough will not consume any resources. Note that pools with similar properties but different details (for example, timeout parameters) may be created using ThreadPoolExecutor constructors.
Metodun içi şöyledir. En az 0, en çok 2 milyar küsur thread yaratır. Idle kalan thread 60 saniye içinde sonlanır. SynchronousQueue hemen doluyum cevabı verdiği için yeni bir thread yaratılmasına sebep olur. Bu ThreadPoolExecutor konfigürasyonu hemen işlenmesi gereken, I/O için bekleme yapan veya kısa süreli işler için kullanılır. Örneğin uzak bir sunucuya bir sürü sorgu göndermek gibi. Eğer yanlış kullanırsak bu kod çok fazla thread açmaya çalıştığı için sistemi kilitleyebilir!
public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}
Örnek
Şöyle yaparız.
ExecutorService executor = Executors.newCachedThreadPool();

20 Ocak 2021 Çarşamba

Executors.newWorkStealingPool metodu

Giriş
Açıklaması şöyle. Java 8 ile geliyor. Altta ForkJoinPool kullanır. Bu yüzden sadece "recursive divide and conquer" tarzı işler için uygundur
Creates a work-stealing thread pool using all available processors as its target parallelism level.
newWorkStealingPool metodu
İmzası şöyle.
public static ExecutorService newWorkStealingPool();
Kodu şöyle
/**
* Creates a work-stealing thread pool using all
* {@link Runtime#availableProcessors available processors}
* as its target parallelism level.
* @return the newly created thread pool
* @see #newWorkStealingPool(int)
* @since 1.8
*/
public static ExecutorService newWorkStealingPool() {
    return new ForkJoinPool(Runtime.getRuntime().availableProcessors(),
                            ForkJoinPool.defaultForkJoinWorkerThreadFactory,
                            null, true);
}
newWorkStealingPool metodu - int parallelism
Kodu şöyle
/**
* Creates a thread pool that maintains enough threads to support
* the given parallelism level, and may use multiple queues to
* reduce contention. The parallelism level corresponds to the
* maximum number of threads actively engaged in, or available to
* engage in, task processing. The actual number of threads may
* grow and shrink dynamically. A work-stealing pool makes no
* guarantees about the order in which submitted tasks are
* executed.
*
* @param parallelism the targeted parallelism level
* @return the newly created thread pool
* @throws IllegalArgumentException if {@code parallelism <= 0}
* @since 1.8
*/
public static ExecutorService newWorkStealingPool(int parallelism) {
    return new ForkJoinPool(parallelism,
                            ForkJoinPool.defaultForkJoinWorkerThreadFactory,
                            null, true);
}
Örnek
Şöyle yaparız.
ExecutorService pool = Executors.newWorkStealingPool(10);

6 Ocak 2020 Pazartesi

Executors.newSingleThreadExecutor metodu - Unbounded Kuyruk Kullanır

Giriş
Executors.newFixedThreadPool() ile Executors.newSingleThreadExecutor() aynı işi yapıyor gibi görünüyorlar ancak altta biraz farklılar. Açıklaması şöyle
In case when a thread dies due to some error or exception at the time of executing a task, a new thread is created, and all the subsequent tasks execute in that new one.

newSingleThreadExecutor metodu

Örnek

Şöyle yaratırız.
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
newSingleThreadExecutor vs newFixedThreadPool
Açıklaması şöyle. Bu metod ile döndürülen ExecutorService nesnesi ThreadPoolExecutor sınıfından kalıtmıyor. Dolayısıyla döndürülen nesneyi ThreadPoolExecutor sınıfına cast etme ve özelliklerini değiştirme imkanı yok.
It is essentially the same thing as an Executors.newSingleThreadExecutor() except that the latter is not reconfigurable, as indicated in the javadoc, whereas the former is if you cast it to a ThreadPoolExecutor.
Metodun içi bir ara şöyleydi. 
public static ExecutorService newSingleThreadExecutor() {
  return new FinalizableDelegatedExecutorService
    (new ThreadPoolExecutor(1, 1,
                            0L, TimeUnit.MILLISECONDS,
                            new LinkedBlockingQueue<Runnable>()));
}
newSingleThreadExecutor metodu - ThreadFactory
Örnek
Şöyle yaparız.
class YourThreadFactory implements ThreadFactory {
   public Thread newThread(Runnable r) {
     return new Thread(r, "Your name");
   }
 }

Executors.newSingleThreadExecutor(new YourThreadFactory()).submit(someRunnable);

16 Mayıs 2019 Perşembe

Executors.newFixedThreadPool metodu - Unbounded Kuyruk Kullanır OOM Verebilir

Giriş
Bu metodun iki tane overload edilmiş hali bar.
1. Thread Sayısı
İmzası şöyle.
public static ExecutorService newFixedThreadPool(int nThreads)
2. Thread Sayısı + ThreadFactory
Yaratılan her thread'e isim falan verilebiliyor.

Metodun İçi
Metodun için şöyle.

corePoolSize ve maximumPoolSize aynıdır. keepAliveTime 0'dır . Yani Thread hep yaşar.

Kuyruk olarak unbounded kuyruk kullanır. Eğer çok fazla iş eklersek kuyruk unbounded olduğu için bellek bitebilir.
public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
}
LinkedBlockingQueue şöyledir. Yani sınırsız sayıda iş alabilir.
public LinkedBlockingQueue() {
    this(Integer.MAX_VALUE);
}
public LinkedBlockingQueue(int capacity) {...}
Açıklaması şöyle.
Creates a thread pool that reuses a fixed number of threads operating off a shared unbounded queue. At any point, at most nThreads threads will be active processing tasks. If additional tasks are submitted when all threads are active, they will wait in the queue until a thread is available. If any thread terminates due to a failure during execution prior to shutdown, a new one will take its place if needed to execute subsequent tasks. The threads in the pool will exist until it is explicitly shutdown.
Ne Zaman Terchi Etmeli

1. Çalıştırılan Thread Sayısına Üst Sınır Vermek İçin Kullanılır
Bu metod verilen servise üst sınır konulmak istenilirse faydalı. Örneğin aynı anda sadece 4 müşteriye hizmet vermek gibi. Böylece patlama anlarında çok fazla thread yaratarak sisteme aşırı yük binmesini engellenebiliyor. Açıklaması şöyle.
Use thread pools to enable graceful degradation of service during traffic bursts
Bu servisi kullanırken dikkat edilmesi gereken tasarım noktası, thread sayısı sınırlı olduğu için yeni işletilmekte olan işin, aynı ExecutorService nesnesine yeni yeni işler ekleyip sonucunun bitmesini beklememesi. Bu durum deadlock (kilitlenme) oluşmasına sebep olabilir. Açıklaması şöyle
Do not execute interdependent tasks in a bounded thread pool
2. Kısa Vadeli İşler İçin Kullanılır
Örneğin yoğun hesaplama yapılan, yani bekleme yapmayan işlerde tercih edilir. Bu Executor tipini Swing uygulamasında kısa vadeli işleri (short term) - ekrana çizilecek şeyi hesaplamak gibi - çalıştırmak için kullandım.

3. Ani Artış (Burst) İşlere İyi Uyum Sağlamaz
Kısa vadeli işlerde kullansak bile sayısal olarak ani artış gösteren işlere iyi uyum sağlamaz. Thread sayısı sabit olduğu için hepsi meşgülse işe cevap süresi uzun olabilir.

İdeal Kullanım
Veritabanındaki tabloya yazılan işleri arka tarafta (back end) işleyen asenkron işler için mükemmel bir yöntem. Sistemdeki çekirdek sayısı kadar thread açılır ve her thread tablodan okuma yapar işi çalıştırır.

Kullanım
Örnek - int
Şöyle yaparız.
ExecutorService executorService = Executors.newFixedThreadPool(3);
Örnek - int
Hem sadece 4 müşteriye hizmet verip hem de toplamda da sınırlı sayıda iş kabul etmek istersek şöyle yaparız. Eğer üst sınır aşılırsa RejectedExecutionException fırlatılır.
public static
ExecutorService newFixedThreadPoolWithQueueSize(int nThreads, int queueSize) {
  return new ThreadPoolExecutor(nThreads, nThreads,
                              5000L, TimeUnit.MILLISECONDS,
                              new ArrayBlockingQueue<Runnable>(queueSize, true));
}
Örnek - int + ThreadFactory
Thread'e isim vermek için kullanılabilir. 
Şöyle yaparız.
String someName="fileName"; // Inside first file 
...........................
.........................

Executors.newFixedThreadPool(30, new 
           ThreadFactoryBuilder().setNameFormat(someName).build());
Daha karmaşık örnekler burada.