Mobil geliştirmede Thread — nedir, türleri ve iş parçacığı yönetimi

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

Thread — kendi yığınına sahip ve diğer iş parçacıklarından bağımsız olarak yürütülen temel işlemci zamanı birimidir. Mobil geliştirmede, iş parçacıkları uzun süren işlemler sırasında arayüzün yanıt vermeye devam etmesi için görevlerin paralel olarak yürütülmesinde kullanılır. Android, java.lang.Thread, Executors ve Kotlin Coroutines'i destekler; iOS ise Thread (Objective-C), GCD ve OperationQueue'yi destekler. Android Thread Dokümantasyonu'na göre, yerel bir iş parçacığı oluşturmak, işletim sistemi tarafından yığın için yaklaşık 1 MB ayrılmasını gerektirir.

Önemli Noktalar

  • Thread — minimum CPU planlama birimi: her iş parçacığı bağımsızdır ve kendi yığınına sahiptir
  • İş parçacığı oluşturma Android'de ~1 MB, iOS'te 512 KB yığın gerektirir, bu nedenle havuzlar doğrudan oluşturmadan daha verimlidir
  • Android: Thread, Executors, HandlerThread, Coroutines — dört soyutlama seviyesi
  • iOS: Thread (düşük seviye), GCD (DispatchQueue), OperationQueue (yüksek seviye)
  • Thread safety — mutable verilere ortak erişim senkronizasyon gerektirir: locks, atomic, serial queues

Thread Nedir

Thread (yürütme iş parçacığı) — işletim sisteminin bir CPU çekirdeğinde zamanlayabileceği bağımsız bir komut dizisidir. Her süreç (uygulama) en az bir iş parçacığı içerir — Main Thread. Görevlerin paralel yürütülmesi için ek iş parçacıkları oluşturulur. Her iş parçacığının kendi yazılım yığını (yerel değişkenlerle), program sayacı (PC) ve kayıtları vardır. Heap bellek, sürecin tüm iş parçacıkları tarafından paylaşılır.

Mobil işletim sistemlerinde, iş parçacıkları önleyici çoklu görev (preemptive multitasking) ile planlanır: İşletim sistemi, bir iş parçacığının yürütülmesini istediği zaman kesintiye uğratabilir ve kontrolü başka bir iş parçacığına devredebilir (context switch). Bağlam değiştirme, CPU kayıtlarının kaydedilmesi/geri yüklenmesi, TLB'nin güncellenmesi ve önbelleklerin temizlenmesini gerektirdiğinden maliyetli bir işlemdir (1-10 mikrosaniye). Bu nedenle aşırı sayıda iş parçacığı (yüzlerce ve binlerce) performansı düşürür — işletim sistemi yürütmeden çok bağlam değiştirmeye zaman harcar.

İş parçacığı ve süreç — farklı kavramlardır. Süreç, ayrılmış sanal belleğe sahip bir uygulama örneğidir. Bir süreç içindeki iş parçacığı, bu belleği diğer iş parçacıklarıyla paylaşır. Android'de, uygulamanın her bileşeni (Activity, Service, BroadcastReceiver) tek bir süreçte çalışır ancak farklı iş parçacıklarında yürütülebilir. Bir iOS uygulaması da GCD veya Thread aracılığıyla ek iş parçacıkları oluşturma olanağına sahip tek bir süreçtir.

İş Parçacığı Yaşam Döngüsü: Durumlar ve Geçişler

Her iş parçacığı Java/Kotlin (Android) ve NSThread (iOS) içinde beş durumdan geçer: New (oluşturuldu), Runnable (yürütmeye hazır), Running (CPU'da çalışıyor), Blocked/Waiting (kaynak veya bildirim bekliyor), Terminated (sonlandırıldı). Durumlar arasındaki geçişler, işletim sistemi zamanlayıcısı ve senkronizasyon temelleri tarafından yönetilir. Geliştirici, iş parçacığının önceliğini (Thread.setPriority()) ve durumunu (sleep, join, interrupt) etkileyebilir.

Android'de, bir iş parçacığı meşgul bir monitörü (synchronized) almaya çalıştığında, Object.wait() veya Thread.sleep() çağırdığında Blocked durumuna geçer. iOS'te — NSCondition.wait(), pthread_cond_wait() veya dispatch_semaphore_wait() çağrıldığında. Blocked durumunda, iş parçacığı CPU tüketmez ancak bellek (yığın) kaplar. Bir iş parçacığı başka bir iş parçacığından InterruptedException (Java) alarak veya isCancelled (Kotlin Coroutines) kontrol ederek kesintiye uğratılabilir (interrupted).

DurumAçıklamaGeçiş Yöntemi
Newİş parçacığı oluşturuldu ancak başlatılmadıThread() yapıcısı
Runnableİş parçacığı yürütmeye hazır, CPU bekliyorthread.start()
Runningİş parçacığı CPU çekirdeğinde çalışıyorİşletim sistemi zamanlayıcısı
Blocked/Waitingİş parçacığı kaynak, monitör veya bildirim bekliyorsynchronized, wait(), sleep()
Terminatedİş parçacığı run()'ı tamamladı veya kesintiye uğradırun() tamamlandı, interrupt()

Context Switch ve Maliyeti

Context switch (bağlam değiştirme) — işletim sisteminin mevcut iş parçacığının durumunu (kayıtlar, PC, TLB) kaydettiği ve başka bir iş parçacığının kaydedilmiş durumunu yüklediği işlemdir. Mobil sistemlerde (Linux + ART, iOS için XNU), context switch 1-10 mikrosaniye sürer. Bir iş parçacığı 100 mikrosaniyelik bir görevi yürütüyorsa ve context switch 5 mikrosaniye sürüyorsa, zamanın %5'i boşa harcanır. Context switch'leri en aza indirmek için iOS work stealing ile GCD'yi, Android ise fixedThreadCount ile havuzları kullanır.

Android'de Thread: Thread'den Coroutines'e

Android, düşük seviyeli java.lang.Thread'den modern coroutine'lere evrilmiştir. Her soyutlama seviyesi, daha az ek yük ile daha fazla yetenek sunar. Thread temel sınıftır ancak doğrudan oluşturulması önerilmez: yeni bir iş parçacığı havuz tarafından yönetilmez, izlenmesi ve iptal edilmesi zordur. AsyncTask (API 30'dan itibaren kullanımdan kaldırıldı) bir adım ileriydi ancak bellek sızıntıları ve yapılandırmaların kullanışsız yönetiminden muzdaripti.

HandlerThread, Looper ile mesaj kuyruğunu işleyebilen özel bir Thread alt sınıfıdır. Arka plan iş parçacığında sıralı görevlerin yürütülmesi için kullanılır, örneğin Room'a veya dosyalara veri yazmak. HandlerThread, start() çağrılarak oluşturulur, ardından Handler(handlerThread.looper) aracılığıyla mesajlar ve Runnable gönderilebilir. handlerThread.quit() çağrısı Looper'ı durdurur ve iş parçacığını sonlandırır.

kotlin
// Android: Thread, HandlerThread ve Executors
import android.os.Handler
import android.os.HandlerThread
import java.util.concurrent.Executors

class ThreadExample {

    // 1. Doğrudan Thread oluşturma (önerilmez)
    fun directThread() {
        val thread = Thread(Runnable {
            Thread.sleep(1000)
            print("Direct thread executed")
        })
        thread.start()
    }

    // 2. Sıralı arka plan görevleri için HandlerThread
    fun handlerThreadExample() {
        val handlerThread = HandlerThread("BackgroundQueue")
        handlerThread.start()

        val handler = Handler(handlerThread.looper)
        handler.post {
            // Arka plan iş parçacığında sıralı yürütme
            Thread.sleep(500)
            print("HandlerThread: görev tamamlandı")
        }

        // İş parçacığını durdurma (görevler bittiğinde çalışır)
        handlerThread.quitSafely()
    }

    // 3. Executors — iş parçacığı havuzu
    fun executorExample() {
        val executor = Executors.newFixedThreadPool(4)
        for (i in 1..10) {
            executor.execute {
                print("Task $i on thread ${Thread.currentThread().getName()}")
            }
        }
        executor.shutdown()
    }

    // 4. Kotlin Coroutines — modern standart
    suspend fun coroutineExample() = kotlinx.coroutines.withContext(
        kotlinx.coroutines.Dispatchers.Default
    ) {
        print("Coroutine on thread: ${Thread.currentThread().getName()}")
    }
}

ThreadExample, Android'deki dört iş parçacığı soyutlama seviyesinin tümünü gösterir. Doğrudan Thread oluşturmak en düşük seviyeli ve en verimsiz yaklaşımdır. HandlerThread, arka planda sıralı görevler için kullanışlıdır. Executors.newFixedThreadPool(4), 10'a kadar görevin paralel yürütülmesi için 4 iş parçacıklı bir havuz oluşturur. Kotlin Coroutines ve Dispatchers.Default — modern, verimli ve güvenli bir yöntemdir.

HandlerThread: Sıralı Arka Plan Görevleri

HandlerThread — yerleşik Looper ve mesaj kuyruğuna sahip özelleştirilmiş bir Thread alt sınıfıdır. start() çağrılarak oluşturulur, ardından Handler(handlerThread.looper) aracılığıyla Runnable ve mesajlar gönderilebilir. HandlerThread görevleri kesinlikle sırayla yürütür — sonraki görev, önceki tamamlanana kadar başlamaz. Bu, işlem sırasının kritik olduğu Room veya dosyalara veri yazmak için kullanışlıdır. quitSafely() çağrısı, mevcut görev tamamlandıktan sonra Looper'ı durdurur.

iOS'te Thread: Thread, GCD ve OperationQueue

iOS ayrıca iş parçacıklarıyla çalışmak için üç seviye sunar. Thread (Swift'te Thread, Objective-C'de NSThread) — doğrudan yerel bir iş parçacığı oluşturan düşük seviyeli bir API. DispatchQueue aracılığıyla GCD (Grand Central Dispatch) — iOS geliştiricileri için ana araçtır, iş parçacığı havuzunu otomatik olarak yönetir. OperationQueue — bağımlılıklar, öncelikler ve iptal desteği ile GCD üzerinde yüksek seviyeli bir soyutlamadır.

Modern iOS geliştirmede doğrudan Thread kullanımı son derece nadirdir — GCD, otomatik bellek ve iş parçacığı yönetimi ile gerekli tüm yetenekleri sağlar. Thread yalnızca belirli durumlar için kullanılır: thread-local storage (threadDictionary) ayarlama, arka plan iş parçacığı için RunLoop oluşturma veya pthread_t bekleyen C kütüphaneleriyle entegrasyon.

swift
import Foundation

class ThreadManager {

    // 1. Thread (düşük seviye)
    func createThread() {
        let thread = Thread {
            // Kod yeni bir iş parçacığında yürütülür
            print("Current thread: \(Thread.current)")
        }
        thread.name = "com.app.worker"
        thread.qualityOfService = .utility
        thread.start()
    }

    // 2. GCD — DispatchQueue
    func gcdExample() {
        // Paralel kuyruk
        let queue = DispatchQueue(label: "com.app.concurrent",
                                 qos: .utility,
                                 attributes: .concurrent)

        queue.async {
            print("GCD async task")
        }

        // Yazma senkronizasyonu için Barrier
        queue.async(flags: .barrier) {
            // Yazma sırasında özel erişim
            print("Barrier write: exclusive access")
        }
    }

    // 3. Bağımlılıklı OperationQueue
    func operationQueueExample() {
        let queue = OperationQueue()
        queue.maxConcurrentOperationCount = 2
        queue.qualityOfService = .background

        let download = BlockOperation {
            print("Downloading...")
        }
        let process = BlockOperation {
            print("Processing...")
        }
        let save = BlockOperation {
            print("Saving...")
        }

        // Bağımlılıklar: download -> process -> save
        process.addDependency(download)
        save.addDependency(process)

        queue.addOperations([download, process, save], waitUntilFinished: false)
    }
}

// GCD barrier ile thread-safe koleksiyon
class ThreadSafeArray<T> {
    private var array: [T] = []
    private let queue = DispatchQueue(label: "com.app.concurrent",
                                       attributes: .concurrent)

    var count: Int {
        return queue.sync { array.count } // concurrent read
    }

    func append(_ element: T) {
        queue.async(flags: .barrier) { // exclusive write
            self.array.append(element)
        }
    }
}

ThreadSafeArray sınıfı, GCD barrier aracılığıyla Eşzamanlı Okuma / Özel Yazma modelini gösterir. queue.sync{} ile okuma, birden çok iş parçacığından paralel olarak yürütülür. queue.async(flags: .barrier) ile yazma, yazma tamamlanana kadar diğer tüm işlemleri (hem okuma hem yazma) bloke eder. Bu, synchronized bloklarından daha verimlidir çünkü yazma olmadığında okuyucuları bloke etmez.

iOS Thread vs GCD: Thread Ne Zaman Doğrudan Kullanılmalı

iOS'te doğrudan Thread kullanımı üç durumda haklı çıkar: thread-local storage (Thread.current.threadDictionary) — iş parçacığına bağlı verileri saklamak için; arka plan iş parçacığında performSelector:onThread: ile özel bir RunLoop oluşturmak için; pthread_t bekleyen C/C++ kütüphaneleriyle entegrasyon için. Diğer tüm durumlarda, DispatchQueue aracılığıyla GCD tercih edilir — iş parçacığı havuzunu ve enerji tüketimini otomatik olarak yönetir.

İş Parçacığı Senkronizasyonu: locks, atomic, serial queues

Race condition (yarış durumu), iki veya daha fazla iş parçacığı aynı anda paylaşılan verilere eriştiğinde ve iş parçacıklarından en az biri yazma yaptığında ortaya çıkar. Sonuç, yürütme sırasına (timing) bağlıdır ve tahmin edilemez. Race condition'ları önlemek için senkronizasyon temelleri kullanılır. Mobil geliştirmede kilitler (synchronized, NSLock), atomik işlemler (AtomicInteger, iOS atomic özellikleri) ve kuyruklar (serial queue) mevcuttur.

Temel seçimi senaryoya bağlıdır. Basit sayaçlar ve bayraklar için atomik işlemler yeterlidir (AtomicInteger, atomic özellik). Birden çok işlemli kritik bölümler için — kilitler (synchronized, NSLock). Karmaşık veri yapıları için — serial DispatchQueue veya GCD barrier. Kilitleri anlamak daha kolaydır ancak deadlock ve livelock'a yatkındır. Kuyruklar daha karmaşıktır ancak daha güvenlidir.

kotlin
// Android/Kotlin'de senkronizasyon
import java.util.concurrent.atomic.AtomicInteger
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock

class Counter {

    // 1. AtomicInteger — basit sayaçlar için
    private val atomicCount = AtomicInteger(0)
    fun incrementAtomic() = atomicCount.incrementAndGet()

    // 2. synchronized — kritik bölümler için
    @Synchronized
    fun synchronizedOperation() {
        // Her seferinde yalnızca bir iş parçacığı
        doWork()
    }

    // 3. Coroutine'lerden Mutex — suspend-safe
    private val mutex = Mutex()
    suspend fun mutexOperation() {
        mutex.withLock {
            // protected code — thread-safe
            doWork()
        }
    }

    private fun doWork() { /* critical section */ }
}

// Deadlock örneği: A, B'yi kilitler, B, A'yı kilitler
class DeadlockExample {
    private val lockA = Any()
    private val lockB = Any()

    fun methodA() = synchronized(lockA) {
        Thread.sleep(100)
        synchronized(lockB) { print("OK") }
    }

    fun methodB() = synchronized(lockB) {
        Thread.sleep(100)
        synchronized(lockA) { print("OK") }
    }
}

Counter, senkronizasyona üç yaklaşımı gösterir. AtomicInteger.incrementAndGet() — kilitsiz atomik işlem (CAS). @Synchronized — Java'nın yerleşik monitörü, tüm nesneyi kilitler. Mutex.withLock — coroutine mutex'i, iş parçacığını bloke etmek yerine coroutine'i askıya alır (daha verimli). DeadlockExample, klasik bir deadlock'u gösterir: iki iş parçacığı kilitleri farklı sırayla alır.

Thread Havuzları: Executors Neden Thread'den Daha İyi

Thread Pool (iş parçacığı havuzu) — görevleri yürütmek için yeniden kullanılan önceden oluşturulmuş iş parçacıkları kümesidir. Her görev için yeni bir iş parçacığı oluşturmak yerine (pahalı), havuz havuzdan boş bir iş parçacığı alır. Boş iş parçacığı yoksa, görev kuyruğa alınır. Havuz boyutu otomatik olarak yönetir: yük piklerinde yeni iş parçacıkları oluşturulur, boştaki iş parçacıkları sonlandırılır. Bu, iş parçacığı oluşturma ek yükünü onlarca kat azaltır.

Android'de Executors.newFixedThreadPool(4), 4 iş parçacıklı bir havuz oluşturur. Aynı anda 10 görev gelirse, 4'ü hemen başlar, 6'sı kuyrukta bekler. Executors.newCachedThreadPool(), ihtiyaç halinde iş parçacıkları oluşturur (sınırsız) ve boştakileri 60 saniye sonra sonlandırır. iOS için GCD, boyutu CPU çekirdeği sayısına ve mevcut yüke karşılık gelen genel kuyruk havuzlarını otomatik olarak sağlar.

Kotlin Coroutines'te, iş parçacığı havuzları dispatcher'ların içinde gizlidir. Dispatchers.Default, boyutu CPU çekirdeği sayısına eşit olan bir havuz kullanır (minimum 2). Dispatchers.IO — 64 iş parçacığı (yüzlerce IO-bound görev için yeterlidir, çoğu CPU kullanmadan G/Ç bekleyecektir). Her dispatcher, havuz boyutunu yüke göre otomatik olarak ölçeklendirerek boştayken pil gücünden tasarruf sağlar.

Sıkça Sorulan Sorular

Mobil geliştirmede Thread nedir?

Thread — bir uygulamadaki temel kod yürütme birimidir. Her süreç, belleği paylaşan ancak kendi yığınına sahip birden çok iş parçacığına sahip olabilir. Mobil geliştirmede, iş parçacıkları UI'yı bloke etmeden görevleri paralel yürütmek için kullanılır. Android, Thread, Executors, HandlerThread ve Coroutines kullanır. iOS, Thread, GCD (DispatchQueue) ve OperationQueue kullanır.

Neden doğrudan Thread oluşturulması önerilmez?

Thread oluşturmak Android'de ~1 MB, iOS'te ~512 KB yığın ayrılmasını gerektirir — bu pahalı bir işlemdir. 1000 görev için 1000 iş parçacığının doğrudan oluşturulması, yalnızca yığınlar için yaklaşık 1 GB artı context switch ek yükü gerektirir. Thread yerine havuzlar (Executors, GCD) veya coroutine'ler kullanın — iş parçacıklarını yeniden kullanarak ek yükü onlarca kat azaltırlar.

Race condition nedir ve nasıl önlenir?

Race condition — birden çok iş parçacığının yazma ile paylaşılan verilere aynı anda eriştiğinde öngörülemeyen davranış. Üç şekilde önlenebilir: atomik türler (AtomicInteger) kullanmak, kilitler (synchronized, NSLock) kullanmak veya kuyruk (DispatchQueue serial, Kotlin'de Actor) aracılığıyla erişimi sıralamak. En iyi uygulama, paylaşılan mutable durumu en aza indirmek ve immutability kullanmaktır.

Thread ve coroutine arasındaki fark nedir?

Thread — yaklaşık 1 MB yığın kaplayan ve işletim sistemi çekirdeğine bağlı yerel bir sistem nesnesidir. Coroutine — belirli bir iş parçacığına bağlı olmayan ve bloke etmeden askıya alınabilen (suspend) hafif bir Kotlin yürütme birimidir. Tek bir iş parçacığı binlerce coroutine yürütebilir. Coroutine'ler bellek açısından daha verimlidir ve callback olmadan asenkron kod yazmayı sağlar.

Mobil uygulamada deadlock nasıl tespit edilir?

Deadlock, ANR olmadan uygulamanın tamamen donması olarak kendini gösterir. Android'de, tüm iş parçacıklarının yığın dökümü için Thread.getAllStackTraces() kullanın — iki iş parçacığı birbirinin kilitlerini bekleyecektir. iOS'te — Thread.callStackSymbols. Araçlar: Android Studio Profiler (Threads sekmesi), Instruments (iOS, Thread State View). Önleme: kilitleri sabit sırayla alın, time-out ile tryLock kullanın.

Özet

  • Thread — minimum CPU birimi: kendi yığını ile bağımsız yürütme, heap bellek paylaşılır
  • Beş durum: New, Runnable, Running, Blocked/Waiting, Terminated
  • Android Thread → AsyncTask → Executors → HandlerThread → Coroutines yolunda evrildi
  • iOS Thread, GCD (DispatchQueue) ve OperationQueue sunar — düşükten yüksek seviyeye
  • Race condition kilitler (synchronized, NSLock), atomik türler ve serial queues ile çözülür
  • Deadlock çapraz kilit almada oluşur — sabit sıra ile önlenir
  • Thread Pool yeni Thread oluşturmaktan daha verimlidir: iş parçacıklarını yeniden kullanır, context switch ek yükünü azaltı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