Thread Pool mobil ishlanmada — asoslar, iplar hovuzi va ishlash prinsipi

Muallif: IT Sectr Nashr etilgan: 2026-03-18 O'qish vaqti: 11 daq

Thread Pool — bu iplarni boshqarish mexanizmi bo'lib, unda oldindan yaratilgan iplar hovuzi vazifalarni bajarish uchun qayta ishlatiladi, iplarni yaratish va yo'q qilish xarajatlaridan qochiladi. Mobil ishlanmada ip hovuzi fon operatsiyalari uchun ishlatiladi: tarmoq so'rovlari, tasvirlarni qayta ishlash, ma'lumotlar bazalari bilan ishlash. Google Android Documentation (2025) ma'lumotlariga ko'ra, ExecutorService Android-da fon iplarini boshqarishning tavsiya etilgan usulidir. iOS-da shunga o'xshash rolni OperationQueue va global concurrent navbatlari bilan GCD DispatchQueue bajaradi.

Asosiy ma'lumotlar

  • Thread Pool — ip yaratish xarajatlarisiz fon vazifalarini bajarish uchun qayta ishlatiladigan iplar hovuzi.
  • ExecutorService Android-da hovuzni ThreadPoolExecutor orqali sozlanishi parametrlar bilan boshqaradi.
  • OperationQueue iOS-da ip hovuzini maxConcurrentOperationCount orqali inkapsulatsiya qiladi.
  • Core pool size — vazifalarni bajarishga doim tayyor bo'lgan minimal ip soni.
  • Work queue hovuzda bo'sh ipni kutayotgan vazifalarni saqlaydi.

Thread Pool nima?

Thread Pool (ip hovuzi) — bu arxitektura namunasi bo'lib, unda belgilangan sonli iplar oldindan yaratiladi va ko'plab vazifalarni bajarish uchun qayta ishlatiladi. Har bir operatsiya uchun yangi ip yaratish o'rniga (bu qimmat: JVM-da har bir ip uchun taxminan 1 MB stek), vazifalar navbatga joylashtiriladi va hovuzdagi bo'sh iplar tomonidan bajariladi. Mobil ishlanmada ip hovuzi unumdorlik uchun muhim — Android va iOS ilova uchun iplar sonini cheklaydi.

Nega Thread Pool mobil ishlanmada muhim?

Ip yaratish qimmat operatsiyadir: stek ajratish, tizimda ro'yxatdan o'tish, kontekstni almashtirish. Cheklangan resurslarga ega mobil qurilmalarda nazoratsiz ip yaratish Android-da OOM (OutOfMemoryError) va iOS-da trottlingga olib keladi. Thread Pool ikkala muammoni hal qiladi: bir vaqtda ishlaydigan iplarning maksimal sonini cheklaydi va allaqachon yaratilgan iplarni qayta ishlatadi. Google raw Thread() o'rniga ExecutorService ni tavsiya qiladi, Apple Thread o'rniga OperationQueue ni tavsiya qiladi.

ParametrHovuzsiz (raw Thread)Thread Pool bilan
Ip yaratishHar bir vazifa uchunHovuz yaratishda bir marta
Maksimal iplarCheklanmagan (OOM xavfi)Core/max pool size bilan cheklangan
FoydalanishPast (ip vazifadan keyin o'ladi)Yuqori (ip qayta ishlatiladi)
BoshqarishQo'lda (join, interrupt)Avtomatik (ExecutorService)
Xotira iste'moliHar bir vazifa bilan oshadiBarqaror

Thread Pool mobil ishlanmada qanday ishlaydi?

Ip hovuzi Producer-Consumer printsipi asosida ishlaydi: vazifalar (Runnable/Callable) blokirovka qiluvchi navbatga (BlockingQueue) joylashtiriladi. Hovuzdagi iplar navbatda vazifalarni kutadi va ularni bajarish uchun oladi. Algoritm: agar bo'sh iplar corePoolSize dan kam bo'lsa, yangi ip yaratiladi. Agar corePoolSize ga erishilgan bo'lsa, vazifa navbatga joylashtiriladi. Agar navbat to'la bo'lsa va iplar maximumPoolSize dan kam bo'lsa, qo'shimcha ip yaratiladi. maximumPoolSize oshib ketganda, vazifa RejectedExecutionHandler orqali rad etiladi.

Core Pool Size vs Maximum Pool Size

Core pool size — bo'sh holatda ham hovuzda saqlanadigan iplar soni. Maximum pool size — navbat to'lib ketganda yaratilishi mumkin bo'lgan maksimal ip soni. Ularning orasidagi farq — vaqtincha yaratiladigan va bo'sh vaqt tugashidan keyin tugatiladigan qo'shimcha (overflow) iplar. Mobil qurilmalarda ip yaratishning eng yuqori yuklaridan qochish uchun corePoolSize ni maximumPoolSize ga teng qilish tavsiya etiladi.

Work Queue va RejectedExecutionHandler

BlockingQueue bajarilishni kutayotgan vazifalarni saqlaydi. Eng mashhur implementatsiyalar: LinkedBlockingQueue (cheklanmagan), ArrayBlockingQueue (cheklangan) va SynchronousQueue (saqlamasdan — vazifa darhol ipga uzatiladi). Navbat va hovuz to'lib ketganda RejectedExecutionHandler ishga tushadi. Standart siyosatlar: AbortPolicy (RejectedExecutionException tashlaydi), CallerRunsPolicy (jo'natuvchining ipida bajaradi), DiscardPolicy va DiscardOldestPolicy.

kotlin
// Android-da Thread Pool yaratish
val threadPool = ThreadPoolExecutor(
    corePoolSize = 2,        // Kamida 2 ta ip
    maximumPoolSize = 4,     // Ko'pi bilan 4 ta ip
    keepAliveTime = 30L,     // To'lib-toshgan ipning umri
    unit = TimeUnit.SECONDS,
    workQueue = LinkedBlockingQueue<Runnable>(16),
    threadFactory = Executors.defaultThreadFactory(),
    handler = ThreadPoolExecutor.CallerRunsPolicy()
)

// Vazifalarni yuborish
threadPool.execute {
    val result = api.fetchData()
    runOnUiThread { showData(result) }
}

// Hovuzni yakunlash
threadPool.shutdown()
// Barcha vazifalar tugashini kutish
threadPool.awaitTermination(10, TimeUnit.SECONDS)

Android-da Thread Pool: ExecutorService

Android java.util.concurrent orqali bir nechta ip hovuzi implementatsiyalarini taqdim etadi. Executors — tayyor konfiguratsiyalarga ega fabrika: newFixedThreadPool(n) (barqaror hovuz), newCachedThreadPool() (cheklanmagan, iplar kerak bo'lganda yaratiladi), newSingleThreadExecutor() (bitta ip — ketma-ket bajarish). Mobil loyihalar uchun oqilona cheklov bilan (2-4 ip) newFixedThreadPool tavsiya etiladi, chunki cached hovuz juda ko'p ip yaratishi mumkin.

Android-da ThreadPoolExecutor

ThreadPoolExecutor (TPE) — sozlanishi parametrlarga ega ExecutorService ning to'liq implementatsiyasi. Android-da TPE AsyncTask, IntentService va JobIntentService ichida ishlatiladi. corePoolSize, maximumPoolSize, keepAliveTime, BlockingQueue va RejectedExecutionHandler parametrlari hovuz xatti-harakatini nozik sozlash imkonini beradi. Android uchun tavsiyalar: corePoolSize = CPU yadrolari soni - 1 (IO-bound vazifalar uchun) yoki yadrolar soni (CPU-bound vazifalar uchun). Oddiy ilovalar uchun — 2-4 ip.

kotlin
// Executors tayyor konfiguratsiyalari
// 1. 3 ta ip uchun sobit hovuz
val fixedPool = Executors.newFixedThreadPool(3)

// 2. Keshlangan hovuz (mobil uchun tavsiya etilmaydi)
val cachedPool = Executors.newCachedThreadPool()

// 3. Yagona ip (seriyalashtirish)
val singlePool = Executors.newSingleThreadExecutor()

// 4. Rejalashtiruvchi (davriy vazifalar)
val scheduler = Executors.newScheduledThreadPool(2)

// Callable va Future bilan foydalanish
val future: Future<String> = fixedPool.submit(Callable {
    "Result: ${api.call()}"
})
// Natijani olish (ipni bloklaydi)
val result = future.get(5, TimeUnit.SECONDS)

// Hovuzni yakunlash
fixedPool.shutdownNow()

CoroutineDispatcher ip hovuzi sifatida

Kotlin korutinalari CoroutineDispatcher ni taqdim etadi — ip hovuziga o'xshash abstraksiya. Dispatchers.IO 64 ta ipdan iborat hovuzdan (cheklangan) foydalanadi. Dispatchers.Default — CPU yadrolari soniga teng hovuz. CoroutineDispatcher qo'lda shutdown talab qilmaydi va avtomatik boshqariladi. Nozik sozlash uchun Executors.newFixedThreadPool(2).asCoroutineDispatcher() orqali o'z ExecutorCoroutineDispatcher-ingizni yarating. Korutinalar ip hovuzini almashtirmaydi, balki uni o'rab oladi.

iOS-da Thread Pool: OperationQueue va GCD

iOS ip hovuzini boshqarish uchun ikkita asosiy mexanizmni taqdim etadi: OperationQueue (GCD ga asoslangan yuqori darajadagi API) va GCD DispatchQueue (past darajadagi C-API). OperationQueue ip hovuzini maxConcurrentOperationCount xususiyati orqali inkapsulatsiya qiladi. Odatiy bo'lib, OperationQueue system-defined maximum dan foydalanadi (tizim yukiga bog'liq). DispatchQueue.global() tizim ip hovuzi bilan concurrent navbatni taqdim etadi.

OperationQueue va maxConcurrentOperationCount

OperationQueue ip hovuzini maxConcurrentOperationCount orqali boshqaradi. Qiymat 1 seriyali navbatni yaratadi (single thread pool ga o'xshash). Qiymat 1 dan katta — belgilangan cheklov bilan concurrent hovuz. Odatiy bo'lib, maxConcurrentOperationCount = NSOperationQueueDefaultMaxConcurrentOperationCount (tizim optimumi, odatda 4-8 ip). Operation bog'liqliklar, ustuvorliklar va bekor qilishni qo'llab-quvvatlaydi. Har bir operatsiya tizim hovuzidagi istalgan bo'sh ipda bajariladi.

swift
// OperationQueue 3 ta ip hovuzi bilan
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 3
queue.qualityOfService = .utility

// Operatsiyalarni yaratish
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) }
}

// Bog'liqlik: operation2 operation1ni kutadi
operation2.addDependency(operation1)

// Navbatga qo'shish
queue.addOperations([operation1, operation2], waitUntilFinished: false)

// Barcha operatsiyalarni bekor qilish
queue.cancelAllOperations()

GCD DispatchQueue ip hovuzi sifatida

DispatchQueue — Apple'dan ip hovuzi. Concurrent navbat (qos: .utility) qurilmaning joriy yukiga optimallashtirilgan tizim ip hovuzidan foydalanadi. Turli QoS (userInteractive, userInitiated, utility, background) turli ustuvorliklar bilan turli hovuzlarga xaritalanadi. DispatchGroup bir nechta vazifalarni sinxronlashtirish imkonini beradi. DispatchWorkItem bekor qilish va qualityOfService ni qo'llab-quvvatlaydi. Nozik nazorat uchun DispatchQueue(label: qos: attributes: .concurrent) orqali o'z concurrent navbatlaringizni yarating.

swift
// GCD DispatchQueue ip hovuzi sifatida
let customQueue = DispatchQueue(
    label: "com.app.background",
    qos: .utility,
    attributes: .concurrent,
    autoreleaseFrequency: .workItem
)

// Vazifalarni hovuzga yuborish
customQueue.async { self.processFile(file1) }
customQueue.async { self.processFile(file2) }

// Sinxronizatsiya uchun 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() // Ikkala vazifa ham tugadi
}

// Semaphore orqali bir vaqtda ishlashni cheklash
let semaphore = DispatchSemaphore(value: 3)
for url in urls {
    pool.async {
        semaphore.wait()
        download(url)
        semaphore.signal()
    }
}

Thread Pool sozlash parametrlari

Ip hovuzi konfiguratsiyasi bevosita ilova unumdorligiga ta'sir qiladi. Noto'g'ri parametrlar CPU dan to'liq foydalanilmasligiga (juda kam ip) yoki tizimning haddan tashqari yuklanishiga (juda ko'p ip) olib keladi. Mobil ilovalarda optimal qiymatlar cheklangan resurslar va energiya iste'moli tufayli server qiymatlaridan farq qiladi. Asosiy parametrlar: corePoolSize, maxPoolSize, queue capacity va keepAliveTime.

Optimal hovuz hajmini hisoblash

IO-bound vazifalar uchun formula: corePoolSize = CPU yadrolari soni × 2 (iplar kiritish-chiqarishni kutadi). CPU-bound vazifalar uchun: corePoolSize = CPU yadrolari soni (iplar doim hisoblashlar bilan band). Zamonaviy mobil qurilmalarda (6-8 yadro) bu CPU-bound uchun 6-8 ip va IO-bound uchun 12-16 ip beradi. Amaliy testlar shuni ko'rsatadiki, oddiy mobil ilova uchun 3-4 ip optimal — ko'proq iplar unumdorlikni oshirmasdan energiya iste'molini oshiradi.

Queue Capacity va to'lib toshganda xatti-harakat

Vazifalar navbatining (work queue) hajmi nechta vazifa bajarilishni kutishi mumkinligini aniqlaydi. Cheklanmagan navbat (cheklovsiz LinkedBlockingQueue) vazifalarning tez kelishida OOM ga olib kelishi mumkin. Cheklangan navbat (barqaror hajmdagi ArrayBlockingQueue) to'lib toshganda vazifalarni rad etadi. Mobil ilovalar uchun 16-32 vazifa sig'imiga ega ArrayBlockingQueue tavsiya etiladi. CallerRunsPolicy mobil qurilmalar uchun eng yaxshi RejectedExecutionHandler: vazifani yo'qotish o'rniga jo'natuvchini sekinlashtiradi (pressure back).

ParametrMobil uchun tavsiyaAsoslash
corePoolSize2-4Mobil qurilmaning cheklangan resurslari
maxPoolSizecorePoolSize (yoki +1-2)Ip yaratishdagi eng yuqori yuklardan qochish
keepAliveTime15-30 soniyaTez xotirani bo'shatish, lekin tez-tez yaratmasdan
Queue capacity16-32Buferlash va OOM xavfi o'rtasidagi muvozanat
HandlerCallerRunsPolicyVazifalarni yo'qotmasdan orqa bosim (backpressure)

Ip hovuzi bilan ishlashda tipik xatolar

Mobil ilova ishlab chiquvchilari ip hovuzidan foydalanishda ko'pincha xatolarga yo'l qo'yadilar, bu esa ishdan chiqishlarga, xotira oqishlariga va beqaror ishlashga olib keladi. Eng keng tarqalgan: ExecutorService uchun shutdown() ni chaqirmaslik, har bir operatsiya uchun yangi hovuz yaratish, juda katta hovuz, vazifalar o'rtasida deadlock, Android-da CachedThreadPool dan foydalanish.

Thread Pool-da Deadlock

Deadlock hovuzdagi vazifa boshqa vazifaning natijasini kutganda yuzaga keladi, lekin barcha iplar kutish bilan band. Misol: A vazifasi B vazifasini bir xil hovuzga yuboradi va future.get() ni chaqiradi — agar hovuz tugagan bo'lsa, A vazifasi B vazifasini kutadi, B vazifasi esa bajarilmaydi, chunki bo'sh ip yo'q. Yechim: turli darajadagi vazifalar uchun alohida hovuzlar yoki blokirovka qiluvchi .get() o'rniga async callback dan foydalaning.

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

// A vazifasi B vazifasini kutmoqda — deadlock!
val futureA = pool.submit {
    // Bu vazifa hech qachon bajarilmaydi
    val futureB = pool.submit { 42 }
    futureB.get() // Abadiy bloklangan
}

// Tuzatish: alohida hovuzlar
val workerPool = Executors.newFixedThreadPool(2)
val callbackPool = Executors.newSingleThreadExecutor()

workerPool.submit {
    callbackPool.submit {
        // Alohida hovuzda bajariladi — deadlock mumkin emas
    }
}

// Yoki CompletableFuture dan foydalaning
workerPool.submit {
    CompletableFuture
        .supplyAsync { 42 }
        .thenAccept { result ->
            println(result)
        }
}

Tugallanmagan hovuz va oqishlar

Activity-da yaratilgan ExecutorService onDestroy() da tugatilishi kerak. Agar bu qilinmasa, iplar Activity yo'q qilinganidan keyin ham xotirada qoladi. Yechim: hovuzni Activity o'rniga Application scope yoki ViewModel da saqlang. Korutinalar uchun viewModelScope yoki lifecycleScope dan foydalaning. Agar hovuz Activity ichida yaratilgan bo'lsa, onDestroy() da albatta pool.shutdown() ni chaqiring. Test uchun darhol to'xtatish uchun es.shutdownNow() dan foydalaning.

Tez-tez so'raladigan savollar

Thread Pool oddiy ipdan qanday farq qiladi?

Thread Pool allaqachon yaratilgan iplarni ko'plab vazifalarni bajarish uchun qayta ishlatadi. Oddiy ip (raw Thread) yaratiladi, bitta vazifani bajaradi va yo'q qilinadi. Ip yaratish taxminan 1 MB xotira va ~1 ms vaqt oladi. Thread Pool qo'shimcha xarajatlarni kamaytiradi, maksimal ip sonini cheklaydi va boshqarish API sini (shutdown, awaitTermination) taqdim etadi.

Mobil ilova uchun hovuzda nechta ip bo'lishi kerak?

Oddiy mobil ilova uchun 2-4 ip optimal. CPU-bound vazifalar uchun — CPU yadrolari soni. IO-bound vazifalar uchun — yadrolar soni × 2. Ko'proq iplar energiya iste'moli va kontekst almashinuvini oshiradi, unumdorlikni oshirmaydi. Android-da yadrolarni aniqlash uchun Process.availableProcessors() dan foydalaning. iOS-da — ProcessInfo.processInfo.processorCount.

CachedThreadPool nima va nima uchun Android-da xavfli?

CachedThreadPool ehtiyojga qarab iplar yaratadi va mavjud iplarni qayta ishlatadi. Muammo: maksimal ip sonini cheklamaydi. Agar 100 ta vazifa bir vaqtda kelsa, 100 ta ip yaratiladi. Bu Android-da OOM ga olib keladi (har bir ip ~1 MB). Aniq cheklov bilan newFixedThreadPool(n) dan foydalaning. CachedThreadPool faqat kichik hajm kafolatlangan qisqa muddatli burst vazifalar uchun ruxsat etiladi.

ExecutorService uchun shutdown() chaqirish kerakmi?

Ha, agar hovuz boshqariladigan konteynerga (korutinalar kabi) tegishli bo'lmasa. shutdown() yangi vazifalarni qabul qilishni to'xtatadi va joriy vazifalar tugagandan so'ng iplarni tugatadi. shutdown() bo'lmasa, iplar xotirada qoladi, ilova tugamaydi. Activity uchun onDestroy() da chaqiring. ViewModel uchun coroutineScope dan foydalaning. Hovuzni tugatish resurslarni boshqarishning majburiy qismidir, Cursor yoki InputStream ni yopishga o'xshash.

OperationQueue va DispatchQueue ip hovuzimi?

Ha, OperationQueue va DispatchQueue iOS tomonidan taqdim etilgan ip hovuzidir. OperationQueue maxConcurrentOperationCount orqali bir vaqtda ishlashni cheklaydi. DispatchQueue.global() to'g'ridan-to'g'ri nazoratsiz tizim ip hovuzidan foydalanadi. Java ThreadPoolExecutor dan farqli o'laroq, siz corePoolSize yoki queue capacity ni boshqarmaysiz — tizim hovuzni joriy yuk va qurilma energiya iste'moliga qarab avtomatik optimallashtiradi.

Xulosa

  • Thread Pool — ip yaratish xarajatlarini kamaytirib, fon vazifalarini bajarish uchun qayta ishlatiladigan iplar hovuzi.
  • Android aniq hovuz hajmi cheklovi bilan ThreadPoolExecutor va Executors.newFixedThreadPool(n) dan foydalanadi.
  • iOS maxConcurrentOperationCount bilan OperationQueue va QoS hovuzlari bilan GCD DispatchQueue ni taqdim etadi.
  • Core pool size — minimal ip soni; maximum pool size — navbat to'lib ketganda maksimal.
  • Deadlock hovuzda bir vazifaning bir xil hovuzdan boshqa vazifani kutishi bilan yuzaga keladi.
  • CallerRunsPolicy mobil ilovalar uchun afzal — vazifalarni yo'qotmasdan jo'natuvchini sekinlashtiradi.
  • Oddiy mobil ilova uchun optimal hovuz hajmi shutdown() orqali yopiladigan 2-4 ip.

Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz

IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.

Loyihani muhokama qilish

Shuningdek o'qing