Java’da ExecutorService ve Thread Havuzları
Java’da concurrency (eşzamanlılık) ve multithreading (çoklu iş parçacığı) uygulamalarında, thread yönetimini verimli ve kolay bir şekilde yapmak çok önemlidir. Bu noktada, Java’nın sunduğu ExecutorService ve thread havuzları devreye girer. ExecutorService, Java’nın thread’leri daha verimli ve kolay yönetebilmek için sunduğu güçlü bir araçtır. Bu yazıda, ExecutorService’in ne olduğunu, thread havuzlarını nasıl kullanacağımızı ve thread yönetimini nasıl daha verimli hale getirebileceğimizi detaylı bir şekilde ele alacağız.
ExecutorService Nedir?
ExecutorService, Java’nın java.util.concurrent
paketinde bulunan ve thread’lerin yönetimini kolaylaştırmak amacıyla kullanılan bir arayüzdür. Thread’leri manuel olarak oluşturmak ve yönetmek yerine, ExecutorService kullanarak bu süreci daha kontrollü ve verimli bir şekilde gerçekleştirebilirsiniz. ExecutorService, thread’lerin yeniden kullanılmasını sağlayarak sistem kaynaklarının boşa harcanmasının önüne geçer ve aynı anda birden fazla işlemi daha verimli bir şekilde yönetmenize yardımcı olur.
ExecutorService Kullanarak Thread Yönetimi
ExecutorService ile bir thread havuzu oluşturabilir ve belirli sayıda thread’in görevleri gerçekleştirmesini sağlayabilirsiniz. Bu thread’ler işlerini bitirdikten sonra başka görevleri almak için yeniden kullanılabilir, böylece her iş için yeni bir thread oluşturmaya gerek kalmaz.
Örnek: ExecutorService Kullanımı
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(3); // 3 thread'lik bir havuz oluştur
for (int i = 0; i < 5; i++) {
Runnable worker = new WorkerThread("Görev " + i);
executor.execute(worker); // Thread havuzuna görevleri ekleyin
}
executor.shutdown(); // Yeni görev kabul edilmez, mevcut görevler bitirilir
while (!executor.isTerminated()) {
}
System.out.println("Tüm görevler tamamlandı");
}
}
class WorkerThread implements Runnable {
private String message;
public WorkerThread(String message) {
this.message = message;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " (Başlıyor) : " + message);
processMessage();
System.out.println(Thread.currentThread().getName() + " (Bitti) : " + message);
}
private void processMessage() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Bu örnekte, Executors.newFixedThreadPool(3)
ile 3 thread’lik bir havuz oluşturduk ve 5 farklı görev ekledik. ExecutorService, 3 thread’i kullanarak bu görevleri paralel olarak gerçekleştirdi. Bu sayede, aynı anda çalışan thread sayısını kontrol edebilir ve kaynakları daha verimli kullanabilirsiniz.
ExecutorService Metotları
ExecutorService, thread yönetimini kolaylaştıran birçok metot sunar. Bu metotlardan bazıları şunlardır:
- execute(Runnable command): Belirtilen görevi thread havuzuna ekler ve mevcut bir thread ile bu görevi çalıştırır.
- shutdown(): Yeni görevlerin kabul edilmesini durdurur, fakat mevcut görevlerin bitirilmesine izin verir.
- shutdownNow(): Tüm görevleri durdurmaya çalışır ve bekleyen görevleri çalıştırmaz.
- isShutdown(): Executor’un kapatılıp kapatılmadığını kontrol eder.
- isTerminated(): Tüm görevlerin tamamlanıp tamamlanmadığını kontrol eder.
Thread Havuzu (Thread Pool) Nedir?
Thread havuzu, bir uygulamada aynı anda çalışan thread sayısını kontrol etmek ve kaynak kullanımını optimize etmek için kullanılan bir tekniktir. Her yeni görev için bir thread oluşturmak yerine, önceden belirlenmiş sayıda thread’in yeniden kullanılması sağlanır. Bu sayede, thread oluşturma ve yok etme işlemlerinin getirdiği maliyet en aza indirgenmiş olur.
Thread Havuzu Türleri
Java, farklı thread havuzu türleri sunar. Bu havuzlar, farklı kullanım senaryolarına göre seçilebilir:
1. Fixed Thread Pool
Sabit sayıda thread içeren bir havuzdur. Executors.newFixedThreadPool(int nThreads)
kullanılarak oluşturulur. Bu havuz, belirli sayıda thread’in yeniden kullanılmasını sağlar.
ExecutorService fixedPool = Executors.newFixedThreadPool(4);
2. Cached Thread Pool
Gerektiği kadar thread oluşturan ve kullanılmayan thread’leri bir süre sonra serbest bırakan bir havuzdur. Kısa süreli fakat çok sayıda görev içeren durumlarda kullanışlıdır. Executors.newCachedThreadPool()
kullanılarak oluşturulur.
ExecutorService cachedPool = Executors.newCachedThreadPool();
3. Single Thread Executor
Tek bir thread kullanan bir havuzdur. Görevler bir kuyruğa alınır ve sırayla gerçekleştirilir. Executors.newSingleThreadExecutor()
kullanılarak oluşturulur.
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
4. Scheduled Thread Pool
Belirli aralıklarla veya belirli bir süre sonra görevlerin çalıştırılması için kullanılır. Executors.newScheduledThreadPool(int corePoolSize)
kullanılarak oluşturulur.
ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(2);
Fixed Thread Pool vs Cached Thread Pool
- Fixed Thread Pool: Sabit sayıda thread kullanarak belirli sayıda görevi paralel olarak çalıştırır. Sistemin kapasitesine göre kaç thread kullanılacağını ayarlamak mümkündür. Sabit görev sayısının olduğu durumlarda kullanışlıdır.
- Cached Thread Pool: Gerektiği kadar yeni thread oluşturur ve bu thread’ler kullanılmadığında serbest bırakılır. Kısa süreli ve çok sayıda küçük görevler için uygundur, ancak uzun süreli görevlerde çok fazla thread oluşarak sistem kaynakları tüketilebilir.
ExecutorService ve Thread Havuzlarının Avantajları
- Kaynak Yönetimi: Thread’lerin yeniden kullanılması, thread oluşturma ve yok etme maliyetini azaltır. Bu sayede sistem kaynakları daha verimli kullanılır.
- Kolay Yönetim: ExecutorService, thread’lerin yönetimiyle ilgili karmaşıklığı azaltır. Thread’leri manuel olarak yönetmek yerine, görevlerin belirli bir thread havuzunda sıraya alınmasını sağlar.
- Ölçeklenebilirlik: Thread havuzları, iş yükünü dengelemek ve uygulamanın performansını artırmak için ölçeklenebilir bir çözüm sunar.
Örnek: ScheduledExecutorService Kullanımı
ScheduledExecutorService, görevlerin belirli bir süre sonra veya belirli bir aralıkla çalıştırılmasını sağlar. Örneğin, belirli bir görevi her 5 saniyede bir çalıştırmak için kullanılabilir.
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Runnable task = () -> System.out.println("Zamanlı görev çalışıyor: " + System.currentTimeMillis());
scheduler.scheduleAtFixedRate(task, 0, 5, TimeUnit.SECONDS); // Her 5 saniyede bir çalıştır
}
}
Bu örnekte, scheduleAtFixedRate()
metodu ile belirli bir görevi her 5 saniyede bir çalıştırıyoruz. Bu tür kullanım, periyodik görevler için oldukça faydalıdır.
Bu makalede, Java’da ExecutorService ve thread havuzları kullanarak thread yönetimini nasıl daha verimli hale getirebileceğimizi ele aldık. ExecutorService, thread oluşturma ve yönetim işlemlerini kolaylaştırarak daha güvenilir ve verimli uygulamalar geliştirmemize yardımcı olur.
- Java Concurrency ve Multithreading Bölüm 5: Asenkron Akış ve Reactive Programming
- Java Concurrency ve Multithreading Bölüm 4: CompletableFuture ile Asenkron İşlemler
- Milyon Dolarlık Yazılım Projesi: PHP ile Adım Adım Geliştirme
- Java Concurrency ve Multithreading Bölüm 3: ExecutorService ve Thread Havuzları
- Milyon Dolarlık Bir Proje Kodluyoruz