Mobil geliştirmede Thread Pool — temeller, iş parçacığı havuzu ve çalışma prensibi

Yazar: IT Sectr Yayınlanma: 2026-03-18 Okuma süresi: 11 dk

Thread Pool — önceden oluşturulmuş bir iş parçacığı havuzunun görevleri yürütmek için yeniden kullanıldığı, iş parçacığı oluşturma ve yok etme yükünü ortadan kaldıran bir iş parçacığı yönetim mekanizmasıdır. Mobil geliştirmede, iş parçacığı havuzu arka plan işlemleri için kullanılır: ağ istekleri, görüntü işleme, veritabanı işlemleri. Google Android Dokümantasyonu'na (2025) göre ExecutorService, Android'de arka plan iş parçacıklarını yönetmek için önerilen yöntemdir. iOS'ta OperationQueue ve genel concurrent kuyruklara sahip GCD DispatchQueue benzer bir rol oynar.

Önemli noktalar

  • Thread Pool — iş parçacığı oluşturma yükü olmadan arka plan görevlerini yürütmek için yeniden kullanılabilir iş parçacıkları havuzu.
  • ExecutorService Android'de ThreadPoolExecutor aracılığıyla yapılandırılabilir parametrelerle havuzu yönetir.
  • OperationQueue iOS'ta maxConcurrentOperationCount ile iş parçacığı havuzunu kapsüller.
  • Core pool size — görevleri yürütmek için her zaman hazır olan minimum iş parçacığı sayısı.
  • Work queue havuzda boş iş parçacığı bekleyen görevleri depolar.

Thread Pool nedir?

Thread Pool (iş parçacığı havuzu) — belirli sayıda iş parçacığının önceden oluşturulduğu ve birden çok görevi yürütmek için yeniden kullanıldığı bir mimari desendir. Her işlem için yeni bir iş parçacığı oluşturmak yerine (ki bu pahalıdır: JVM'de iş parçacığı başına yaklaşık 1 MB yığın), görevler bir kuyruğa yerleştirilir ve havuzdaki mevcut iş parçacıkları tarafından yürütülür. Mobil geliştirmede, iş parçacığı havuzu performans için kritiktir — Android ve iOS uygulama başına iş parçacığı sayısını sınırlar.

Mobil geliştirmede Thread Pool neden önemlidir

İş parçacığı oluşturmak pahalı bir işlemdir: yığın ayırma, sistem kaydı, bağlam değiştirme. Sınırlı kaynaklara sahip mobil cihazlarda, kontrolsüz iş parçacığı oluşturma Android'de OOM'ye (OutOfMemoryError) ve iOS'ta kısıtlamaya yol açar. Thread Pool her iki sorunu da çözer: aynı anda çalışan maksimum iş parçacığı sayısını sınırlar ve önceden oluşturulmuş iş parçacıklarını yeniden kullanır. Google raw Thread() yerine ExecutorService, Apple Thread yerine OperationQueue önerir.

ParametreHavuzsuz (raw Thread)Thread Pool ile
İş parçacığı oluşturmaHer görev içinHavuz oluştururken bir kez
Maksimum iş parçacığıSınırsız (OOM riski)core/max pool size ile sınırlı
KullanımDüşük (görevden sonra iş parçacığı ölür)Yüksek (iş parçacığı yeniden kullanılır)
YönetimManuel (join, interrupt)Otomatik (ExecutorService)
Bellek tüketimiHer görevle artarSabit

Mobil geliştirmede Thread Pool nasıl çalışır?

İş parçacığı havuzu Üretici-Tüketici prensibiyle çalışır: görevler (Runnable/Callable) bir engelleme kuyruğuna (BlockingQueue) yerleştirilir. Havuzdaki iş parçacıkları kuyrukta görev bekler ve yürütmek için alır. Algoritma: boş iş parçacığı sayısı corePoolSize'dan azsa yeni bir iş parçacığı oluşturulur. corePoolSize'a ulaşılırsa görev kuyruğa yerleştirilir. Kuyruk doluysa ve iş parçacığı sayısı maximumPoolSize'dan azsa ek bir iş parçacığı oluşturulur. maximumPoolSize aşılırsa görev RejectedExecutionHandler aracılığıyla reddedilir.

Core Pool Size vs Maximum Pool Size

Core pool size — boştayken bile havuzda tutulan iş parçacığı sayısı. Maximum pool size — kuyruk taştığında oluşturulabilecek maksimum iş parçacığı sayısı. Aralarındaki fark, geçici olarak oluşturulan ve boşta kalma zaman aşımından sonra sonlandırılan ek (overflow) iş parçacıklarıdır. Mobil cihazlarda, iş parçacığı oluşturmadan kaynaklanan tepe yüklerden kaçınmak için corePoolSize'ın maximumPoolSize'a eşit ayarlanması önerilir.

Work Queue ve RejectedExecutionHandler

BlockingQueue yürütülmeyi bekleyen görevleri depolar. En popüler uygulamalar: LinkedBlockingQueue (sınırsız), ArrayBlockingQueue (sınırlı) ve SynchronousQueue (depolama yok — görev doğrudan bir iş parçacığına iletilir). Kuyruk ve havuz dolduğunda RejectedExecutionHandler tetiklenir. Standart politikalar: AbortPolicy (RejectedExecutionException fırlatır), CallerRunsPolicy (gönderenin iş parçacığında yürütür), DiscardPolicy ve DiscardOldestPolicy.

kotlin
// Android'de Thread Pool oluşturma
val threadPool = ThreadPoolExecutor(
    corePoolSize = 2,        // Minimum 2 iş parçacığı
    maximumPoolSize = 4,     // Maksimum 4 iş parçacığı
    keepAliveTime = 30L,     // Taşma iş parçacığının yaşam süresi
    unit = TimeUnit.SECONDS,
    workQueue = LinkedBlockingQueue<Runnable>(16),
    threadFactory = Executors.defaultThreadFactory(),
    handler = ThreadPoolExecutor.CallerRunsPolicy()
)

// Görev gönderme
threadPool.execute {
    val result = api.fetchData()
    runOnUiThread { showData(result) }
}

// Havuzu kapatma
threadPool.shutdown()
// Tüm görevlerin tamamlanmasını bekleme
threadPool.awaitTermination(10, TimeUnit.SECONDS)

Android'de Thread Pool: ExecutorService

Android, java.util.concurrent aracılığıyla birden çok iş parçacığı havuzu uygulaması sağlar. Executors — hazır yapılandırmalara sahip bir fabrika: newFixedThreadPool(n) (sabit havuz), newCachedThreadPool() (sınırsız, ihtiyaç duyuldukça iş parçacığı oluşturulur), newSingleThreadExecutor() (tek iş parçacığı — sıralı yürütme). Mobil projeler için, makul bir sınırla (2-4 iş parçacığı) newFixedThreadPool önerilir, çünkü önbelleğe alınmış havuz çok fazla iş parçacığı oluşturabilir.

Android'de ThreadPoolExecutor

ThreadPoolExecutor (TPE) — yapılandırılabilir parametrelere sahip ExecutorService'in tam uygulaması. Android'de TPE, AsyncTask, IntentService ve JobIntentService'in içinde kullanılır. corePoolSize, maximumPoolSize, keepAliveTime, BlockingQueue ve RejectedExecutionHandler parametreleri, havuz davranışının ince ayarını yapmaya olanak tanır. Android için öneriler: corePoolSize = CPU çekirdek sayısı - 1 (IO-bound görevler için) veya çekirdek sayısı (CPU-bound görevler için). Tipik uygulamalar için: 2-4 iş parçacığı.

kotlin
// Executors hazır yapılandırmaları
// 1. 3 iş parçacıklı sabit havuz
val fixedPool = Executors.newFixedThreadPool(3)

// 2. Önbelleğe alınmış havuz (mobil için önerilmez)
val cachedPool = Executors.newCachedThreadPool()

// 3. Tek iş parçacığı (serileştirme)
val singlePool = Executors.newSingleThreadExecutor()

// 4. Zamanlayıcı (periyodik görevler)
val scheduler = Executors.newScheduledThreadPool(2)

// Callable ve Future ile kullanım
val future: Future<String> = fixedPool.submit(Callable {
    "Result: ${api.call()}"
})
// Sonucu alma (iş parçacığını bloke eder)
val result = future.get(5, TimeUnit.SECONDS)

// Havuzu kapatma
fixedPool.shutdownNow()

CoroutineDispatcher iş parçacığı havuzu olarak

Kotlin coroutine'leri CoroutineDispatcher sağlar — iş parçacığı havuzuna benzer bir soyutlama. Dispatchers.IO, 64 iş parçacığından (sınırlı) oluşan bir havuz kullanır. Dispatchers.Default — CPU çekirdek sayısına eşit bir havuz. CoroutineDispatcher manuel kapatma gerektirmez ve otomatik olarak yönetilir. İnce ayar için, Executors.newFixedThreadPool(2).asCoroutineDispatcher() aracılığıyla özel bir ExecutorCoroutineDispatcher oluşturun. Coroutine'ler iş parçacığı havuzunun yerini almaz, onu sarar.

iOS'ta Thread Pool: OperationQueue ve GCD

iOS, iş parçacığı havuzu yönetimi için iki ana mekanizma sağlar: OperationQueue (GCD üzerine inşa edilmiş üst düzey API) ve GCD DispatchQueue (alt düzey C-API). OperationQueue, maxConcurrentOperationCount özelliği aracılığıyla iş parçacığı havuzunu kapsüller. Varsayılan olarak OperationQueue, sistem tarafından tanımlanan bir maksimum kullanır (sistem yüküne bağlıdır). DispatchQueue.global(), bir sistem iş parçacığı havuzuyla concurrent kuyruk sağlar.

OperationQueue ve maxConcurrentOperationCount

OperationQueue, iş parçacığı havuzunu maxConcurrentOperationCount aracılığıyla yönetir. Değer 1, seri bir kuyruk oluşturur (tek iş parçacıklı havuza benzer). 1'den büyük bir değer, belirtilen sınırla concurrent bir havuz oluşturur. Varsayılan olarak, maxConcurrentOperationCount = NSOperationQueueDefaultMaxConcurrentOperationCount (sistem optimumu, genellikle 4-8 iş parçacığı). Operation, bağımlılıkları, öncelikleri ve iptali destekler. Her işlem, sistem havuzundaki mevcut herhangi bir iş parçacığında yürütülür.

swift
// 3 iş parçacıklı havuzla OperationQueue
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 3
queue.qualityOfService = .utility

// İşlem oluşturma
let operation1 = BlockOperation {
    let data = fetchData(from: url1)
    DispatchQueue.main.async { updateUI(data) }
}

let operation2 = BlockOperation {
    let data = fetchData(from: url2)
    DispatchQueue.main.async { updateUI(data) }
}

// Bağımlılık: operation2, operation1'i bekler
operation2.addDependency(operation1)

// Kuyruğa ekleme
queue.addOperations([operation1, operation2], waitUntilFinished: false)

// Tüm işlemleri iptal etme
queue.cancelAllOperations()

GCD DispatchQueue iş parçacığı havuzu olarak

DispatchQueue — Apple'ın iş parçacığı havuzudur. Bir concurrent kuyruk (qos: .utility), geçerli cihaz yükü için optimize edilmiş sistem iş parçacığı havuzunu kullanır. Farklı QoS seviyeleri (userInteractive, userInitiated, utility, background), farklı önceliklere sahip farklı havuzlara eşlenir. DispatchGroup birden çok görevi senkronize etmeye olanak tanır. DispatchWorkItem, iptal ve qualityOfService'i destekler. İnce kontrol için, DispatchQueue(label: qos: attributes: .concurrent) aracılığıyla özel concurrent kuyruklar oluşturun.

swift
// GCD DispatchQueue iş parçacığı havuzu olarak
let customQueue = DispatchQueue(
    label: "com.app.background",
    qos: .utility,
    attributes: .concurrent,
    autoreleaseFrequency: .workItem
)

// Havuza görev gönderme
customQueue.async { self.processFile(file1) }
customQueue.async { self.processFile(file2) }

// Senkronizasyon için DispatchGroup
let group = DispatchGroup()
let pool = DispatchQueue.global(qos: .utility)

pool.async(group: group) { fetchData() }
pool.async(group: group) { processImage() }

group.notify(queue: .main) {
    self.showResult() // Her iki görev de tamamlandı
}

// Semaphore ile eşzamanlılığı sınırlama
let semaphore = DispatchSemaphore(value: 3)
for url in urls {
    pool.async {
        semaphore.wait()
        download(url)
        semaphore.signal()
    }
}

Thread Pool yapılandırma parametreleri

İş parçacığı havuzu yapılandırması, uygulama performansını doğrudan etkiler. Yanlış parametreler, CPU'nun yetersiz kullanımına (çok az iş parçacığı) veya sistem aşırı yüklenmesine (çok fazla) yol açar. Mobil uygulamalar için optimum değerler, sınırlı kaynaklar ve güç tüketimi nedeniyle sunucu tarafından farklılık gösterir. Ana parametreler şunlardır: corePoolSize, maxPoolSize, kuyruk kapasitesi ve keepAliveTime.

Optimum havuz boyutunun hesaplanması

IO-bound görevler için formül: corePoolSize = CPU çekirdek sayısı × 2 (iş parçacıkları G/Ç bekler). CPU-bound görevler için: corePoolSize = CPU çekirdek sayısı (iş parçacıkları sürekli hesaplamalarla meşgul). Modern mobil cihazlarda (6-8 çekirdek) bu, CPU-bound için 6-8 iş parçacığı ve IO-bound için 12-16 iş parçacığı verir. Pratik testler, tipik bir mobil uygulama için 3-4 iş parçacığının optimum olduğunu gösterir — daha fazla iş parçacığı, performans artışı olmadan güç tüketimini artırır.

Kuyruk kapasitesi ve taşma davranışı

İş kuyruğunun (work queue) boyutu, kaç görevin yürütmeyi bekleyebileceğini belirler. Sınırsız kuyruk (LinkedBlockingQueue sınırsız), hızlı görev gelişinde OOM'ye yol açabilir. Sınırlı kuyruk (ArrayBlockingQueue sabit boyutlu), dolduğunda görevleri reddeder. Mobil uygulamalar için 16-32 görev kapasiteli ArrayBlockingQueue önerilir. CallerRunsPolicy, mobil için en iyi RejectedExecutionHandler'dır: görevi kaybetmek yerine göndereni yavaşlatır (geri basınç).

ParametreMobil için öneriGerekçe
corePoolSize2-4Mobil cihazın sınırlı kaynakları
maxPoolSizecorePoolSize (veya +1-2)İş parçacığı oluşturmadan kaynaklanan tepe yüklerden kaçınma
keepAliveTime15-30 saniyeSık oluşturma olmadan hızlı bellek serbest bırakma
Kuyruk kapasitesi16-32Ara belleğe alma ve OOM riski arasında denge
HandlerCallerRunsPolicyGörev kaybı olmadan geri basınç

İş parçacığı havuzuyla çalışırken yaygın hatalar

Mobil uygulama geliştiricileri, iş parçacığı havuzunu kullanırken sıklıkla çökmelere, bellek sızıntılarına ve dengesiz çalışmaya yol açan hatalar yapar. En yaygın olanlar: ExecutorService için shutdown() çağırmamak, her işlem için yeni havuz oluşturmak, çok büyük havuz, görevler arasında deadlock, Android'de CachedThreadPool kullanmak.

Thread Pool'da Deadlock

Deadlock, havuzdaki bir görevin aynı havuzdaki başka bir görevin sonucunu beklemesi ancak tüm iş parçacıklarının beklemeyle meşgul olması durumunda oluşur. Örnek: görev A, aynı havuza görev B'yi gönderir ve future.get() çağırır — havuz tükenmişse, görev A görev B'yi bekler ve boş iş parçacığı olmadığı için görev B yürütülemez. Çözüm: farklı görev seviyeleri için ayrı havuzlar kullanın veya bloke edici .get() yerine async callback kullanın.

kotlin
// Thread Pool'da Deadlock
val pool = Executors.newFixedThreadPool(1)

// Görev A, görev B'yi bekliyor — deadlock!
val futureA = pool.submit {
    // Bu görev asla yürütülmeyecek
    val futureB = pool.submit { 42 }
    futureB.get() // Sonsuza kadar bloke
}

// Düzeltme: ayrı havuzlar
val workerPool = Executors.newFixedThreadPool(2)
val callbackPool = Executors.newSingleThreadExecutor()

workerPool.submit {
    callbackPool.submit {
        // Ayrı havuzda çalışıyor — deadlock imkansız
    }
}

// Veya CompletableFuture kullanın
workerPool.submit {
    CompletableFuture
        .supplyAsync { 42 }
        .thenAccept { result ->
            println(result)
        }
}

Sonlandırılmamış havuz ve sızıntılar

Bir Activity'de oluşturulan ExecutorService, onDestroy()'de kapatılmalıdır. Bu yapılmazsa, Activity yok edildikten sonra bile iş parçacıkları bellekte asılı kalır. Çözüm: havuzu Activity yerine Application kapsamında veya ViewModel'de tutun. Coroutine'ler için viewModelScope veya lifecycleScope kullanın. Havuz bir Activity içinde oluşturulmuşsa, onDestroy()'de pool.shutdown() çağırdığınızdan emin olun. Test için, anında durdurma için es.shutdownNow() kullanın.

Sıkça sorulan sorular

Thread Pool normal bir iş parçacığından nasıl farklıdır?

Thread Pool birden çok görevi yürütmek için önceden oluşturulmuş iş parçacıklarını yeniden kullanır. Normal bir iş parçacığı (raw Thread) oluşturulur, bir görevi yürütür ve yok edilir. Bir iş parçacığı oluşturmak yaklaşık 1 MB bellek ve ~1 ms zaman alır. Thread Pool yükü azaltır, maksimum iş parçacığı sayısını sınırlar ve yönetim için API (shutdown, awaitTermination) sağlar.

Bir mobil uygulama için havuzda kaç iş parçacığı olmalı?

Tipik bir mobil uygulama için 2-4 iş parçacığı idealdir. CPU-bound görevler için — CPU çekirdek sayısı. IO-bound görevler için — çekirdek sayısı × 2. Daha fazla iş parçacığı, performans artışı olmadan güç tüketimini ve bağlam değiştirmeyi artırır. Android'de çekirdekleri belirlemek için Process.availableProcessors() kullanın. iOS'ta — ProcessInfo.processInfo.processorCount.

CachedThreadPool nedir ve Android'de neden tehlikelidir?

CachedThreadPool ihtiyaç duyuldukça iş parçacığı oluşturur ve mevcut olanları yeniden kullanır. Sorun: maksimum iş parçacığı sayısını sınırlamaz. Aynı anda 100 görev gelirse 100 iş parçacığı oluşturulur. Bu, Android'de OOM'ye yol açar (her iş parçacığı ~1 MB). Açık bir sınırla newFixedThreadPool(n) kullanın. CachedThreadPool yalnızca garantili küçük hacimli kısa süreli patlama görevleri için kabul edilebilir.

ExecutorService için shutdown() çağırmak gerekli mi?

Evet, havuz yönetilen bir kapsayıcıya (coroutine'ler gibi) ait değilse. shutdown() yeni görevleri kabul etmeyi durdurur ve mevcut görevler tamamlandıktan sonra iş parçacıklarını sonlandırır. shutdown() olmadan iş parçacıkları bellekte asılı kalır ve uygulama sonlanmaz. Activity için onDestroy()'de çağırın. ViewModel için coroutineScope kullanın. Havuzu kapatmak, Cursor veya InputStream'i kapatmaya benzer şekilde kaynak yönetiminin zorunlu bir parçasıdır.

OperationQueue ve DispatchQueue iş parçacığı havuzu mudur?

Evet, OperationQueue ve DispatchQueue iOS tarafından sağlanan iş parçacığı havuzlarıdır. OperationQueue, maxConcurrentOperationCount ile eşzamanlılığı sınırlar. DispatchQueue.global(), doğrudan kontrol olmadan sistem iş parçacığı havuzunu kullanır. Java ThreadPoolExecutor'un aksine, corePoolSize veya kuyruk kapasitesini yönetmezsiniz — sistem, geçerli yüke ve cihaz güç tüketimine göre havuzu otomatik olarak optimize eder.

Özet

  • Thread Pool — arka plan görevleri için yeniden kullanılabilir iş parçacıkları havuzu, iş parçacığı oluşturma yükünü azaltır.
  • Android ThreadPoolExecutor ve açık havuz boyutu sınırıyla Executors.newFixedThreadPool(n) kullanır.
  • iOS maxConcurrentOperationCount ile OperationQueue ve QoS havuzlarıyla GCD DispatchQueue sağlar.
  • Core pool size — minimum iş parçacığı sayısı; maximum pool size — kuyruk taştığında maksimum.
  • Deadlock havuzda bir görevin aynı havuzdaki başka bir görevi beklemesiyle oluşur.
  • CallerRunsPolicy mobil uygulamalar için tercih edilir — görev kaybı olmadan göndereni yavaşlatır.
  • Tipik bir mobil uygulama için optimum havuz boyutu, temizlik için shutdown() ile 2-4 iş parçacığıdır.

Anahtar teslim bir mobil uygulama geliştireceğiz

IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.

Projeyi tartış

Ayrıca okuyun