Starvation mobil tətbiqlərdə — mahiyyəti, yaranma səbəbləri və thread aclığının qarşısını almaq yolları

Müəllif: IT Sectr Dərc olunub: 2026-03-18 Oxuma vaxtı: 10 dəq

Starvation (thread aclığı) — bu, thread-in işə davam etmək üçün lazım olan resursa giriş əldə edə bilmədiyi, baxmayaraq ki, özü icraya hazır olduğu vəziyyətdir. Baeldung (Java Thread Starvation, 2024)-yə görə, aclıq ədalətsiz planlaşdırma səbəbindən yaranır, aşağı prioritetli thread-lar daha yüksək prioritetli olanların xeyrinə daim təxirə salınır. Deadlock-dan fərqli olaraq, Starvation thread-i bloklamır — o RUNNABLE vəziyyətində qalır, lakin heç vaxt prosessor vaxtı almır.

Əsas məqamlar

  • Starvation — thread-in icraya hazır olmasına baxmayaraq resursa giriş əldə edə bilmədiyi vəziyyət
  • Deadlock-dan fərqli olaraq, aclıq zamanı thread RUNNABLE vəziyyətində qalır — bloklanmayıb, lakin irəliləmir
  • Ədalətsiz planlaşdırma (məsələn, synchronized vasitəsilə sinxronizasiya) — JVM-də Starvation-ın əsas səbəbi
  • Fair Lock (ReentrantLock(true)) kilidə giriş üçün növbə sırasında ədalətli qaydada girişi təmin edir
  • Thread Priority mobil inkişafda dəyişdirilməməsi tövsiyə olunur — Android Runtime özü prioritetləri idarə edir

Starvation nədir?

Starvation (thread aclığı) — bu çoxthreadli proqramlaşdırma problemidir ki, thread tapşırığı yerinə yetirmək üçün lazım olan resursa giriş əldə edə bilmir, baxmayaraq ki, resurs başqa thread tərəfindən əbədi olaraq bloklanmayıb. Thread RUNNABLE vəziyyətindədir, lakin planlayıcı və ya sinxronizasiya mexanizmi sistematik olaraq onun icrasını digər thread-ların xeyrinə təxirə salır.

Mobil inkişafda Starvation qeyri-bərabər tapşırıq icrası kimi özünü göstərir: bəzi əməliyyatlar dərhal yerinə yetirilir, digərləri isə fəlakətli gecikmələrlə. Məsələn, məlumatları sinxronizasiya edən fon thread-i, UI thread və animasiya işləyiciləri daim onu qabaqlayırsa, verilənlər bazasına giriş əldə edə bilməz. Android Developer Blog (Performance Matters, 2023) məlumatına görə, Android-də buraxılmış kadrların (jank) təxminən 12%-i renderinqin asılı olduğu fon tapşırıqlarının Starvation səbəbindən baş verir.

Starvation-ın Deadlock-dan əsas fərqi — geri dönüşlülük. Sistem yükü azalarsa və ya prioritetlər yenidən bölüşdürülərsə, aclıq çəkən thread resursu alıb işi tamamlaya bilər. Lakin daimi yüksək yük şəraitində Starvation qeyri-müəyyən müddətə davam edə bilər, asılmış tətbiq təəssüratı yaradır.

Thread aclığının səbəbləri

Ədalətsiz kilidlər (Non-Fair Locks)

Java və Kotlin-də synchronized — ədalətsiz mexanizmin klassik nümunəsidir. Yüksək rəqabət zamanı JVM eyni aktiv thread-lara qeyri-müəyyən müddətə kilidi verə bilər, digər thread-lar isə daim yarışda uduzur. Bu JVM-in xətası deyil, tətbiqin xüsusiyyətidir: ədalətsiz kilidlər girişin vahidliyi hesabına daha yüksək ötürmə qabiliyyətini təmin edir. 4-8 thread-li mobil tətbiqlər üçün bu problem xüsusilə aktualdır.

Prioritetlərin düzgün istifadə edilməməsi

Müxtəlif thread prioritetlərinin təyin edilməsi aşağı prioritetli thread-ların Starvation-na səbəb ola bilər. Android Runtime-da Linux-un CFS (Completely Fair Scheduler) planlayıcısı prosessor vaxtını prioritetlərə nisbətdə bölüşdürür və yüksək prioritetli thread-lar daim aktivdirsə, aşağı prioritetlilər heç vaxt CPU ala bilməz. Google Android-də thread prioritetlərini dəyişməyi qətiyyən tövsiyə etmir — sistem özü onları idarə edir.

Uzun kritik seksiyalar

Əgər thread kilidi çox uzun müddət saxlayırsa (synchronized bloku daxilində ağır hesablamalar, şəbəkə sorğuları və ya fayl əməliyyatları yerinə yetirirsə), bu kilidi gözləyən digər thread-lar aclıq çəkir. Bu, xüsusilə Android-də təhlükəlidir, burada UI thread-də uzun əməliyyatlar ANR-yə səbəb olur, onların fon thread-larına köçürülməsi isə kritik seksiyaları optimallaşdırmadan Starvation problemini işçi thread-lara ötürür.

Kotlin kodunda Starvation nümunəsi

Bir nümunəyə baxaq, burada bir thread ədalətsiz planlaşdırma səbəbindən kilidi çox tez-tez ələ keçirir. Starvation yüksək prioritetli thread-in sonsuz dövrü vasitəsilə nümayiş etdirilir ki, bu da aşağı prioritetli thread-in ümumi resursa giriş əldə etməsinə mane olur.

kotlin
class SharedResource {
    private val lock = Any()

    fun criticalSection(id: String) {
        synchronized(lock) {
            println("$id giriş əldə etdi")
            Thread.sleep(10)  // iş simulyasiyası
        }
    }
}

fun main() {
    val resource = SharedResource()

    // Yüksək prioritetli thread — daim aktiv
    val highPriority = Thread {
        while (true) {
            resource.criticalSection("High")
        }
    }

    // Aşağı prioritetli thread — heç vaxt giriş əldə edə bilməz
    val lowPriority = Thread {
        while (true) {
            resource.criticalSection("Low")
        }
    }

    highPriority.start()
    lowPriority.start()
    // "Low" heç vaxt mesaj çap etməyə bilər — Starvation!
}

Bu nümunədə highPriority thread-i daim kilidi ələ keçirir və onu yalnız 10 ms-ə buraxır. synchronized-in ədalətsiz xarakterinə görə JVM planlayıcısı yüksək ehtimalla kilidi yenidən həmin thread-ə verəcək — aşağı prioritetli thread aclıq çəkir. Həll yolu — fair flag-ı ilə ReentrantLock(true) istifadə etməkdir ki, bu da gözləmə növbəsində sıranı təmin edir.

Fair lock ilə düzəldilmiş versiya resursa girişin ədalətli bölüşdürülməsini təmin edir.

kotlin
class FairSharedResource {
    private val fairLock = ReentrantLock(true)  // fair = true

    fun criticalSection(id: String) {
        fairLock.lock()
        try {
            println("$id giriş əldə etdi (fair)")
            Thread.sleep(10)
        } finally {
            fairLock.unlock()
        }
    }
}

Starvation vs Deadlock vs Livelock

Üç klassik çoxthreadlilik problemi — Starvation, Deadlock və Livelock — tez-tez birləşdirilir, lakin onların mexanizmləri və aradan qaldırılması yolları fərqlidir. Starvation — thread hazırdır, lakin resurs almır. Deadlock — thread-lar tsiklik gözləmə ilə bloklanıb. Livelock — thread-lar aktivdir, lakin irəliləmir.

ParametrStarvationDeadlockLivelock
Thread vəziyyətiRUNNABLEBLOCKEDRUNNABLE
İrəliləməYoxYoxYox (aktiv olsa da)
CPU istehlakıAşağıMinimalYüksək (100%-ə qədər)
SəbəbƏdalətsiz planlaşdırmaTsiklik gözləməMünaqişəyə eyni reaksiya
Əsas həllFair Lock, kritik seksiyaların azaldılmasıKilid iyerarxiyasıTəkrarlama limiti, eksponensial backoff

Starvation Deadlock-dan daha az kritik hesab olunur, çünki o ölümcül deyil — yük azaldıqda aclıq çəkən thread nəhayət yerinə yetiriləcək. Lakin yaddaş və CPU-nun məhdud olduğu Android tətbiqlərinin real istifadəsi şəraitində Starvation dəqiqələrlə davam edə bilər, qəbuledilməz UX yaradır.

Starvation-ı necə aşkar etmək olar

Thread Dump qısa intervallarla təkrar götürməklə — aclığı aşkarlamağın əsas üsuludur. Əgər thread ardıcıl olaraq RUNNABLE vəziyyətindədirsə, lakin onun çağırış yığını bir neçə dump ərzində dəyişmirsə — bu Starvation-ın klassik əlamətidir. Android Studio-da bunun üçün Android Profiler istifadə olunur.

Avtomatik aşkarlama tapşırıqların icra vaxtının monitorinqi vasitəsilə mümkündür. Əgər proqnozlaşdırıla bilən icra müddəti olan tapşırıq (məsələn, 50 ms) 5 saniyə və ya daha çox yerinə yetirilirsə — Starvation ehtimalı yüksəkdir. Mobil tətbiqlərdə Firebase Performance Monitoring kritik seksiyalar üçün xüsusi izlər (custom traces) konfiqurasiya etməyə və həddi dəyərlər aşıldıqda bildirişlər almağa imkan verir.

synchronized blokları səbəbindən Starvation diaqnostikası üçün Java Flight Recorder (JFR) (Android-də OpenJDK API vasitəsilə mövcuddur) və ya Async Profiler istifadə edin. Bu alətlər hansı monitorların ən uzun gözləmə müddətinə malik olduğunu və hansı thread-ların hər bir monitor üçün rəqabət apardığını göstərir. JFR məlumatları IntelliJ IDEA Ultimate ilə quraşdırılmış profiler vasitəsilə inteqrasiya olunur.

Thread aclığının qarşısını almaq üsulları

Fair Lock (true flag-ı ilə ReentrantLock)

ReentrantLock(true) thread-ların kilidi növbə sırası ilə (FIFO) almasını təmin edir. synchronized-dan fərqli olaraq, fair lock kilidi buraxmış thread-in dərhal onu yenidən ələ keçirməsi vəziyyətinə yol vermir. Bu, Starvation-ı tamamilə aradan qaldırır, baxmayaraq ki, növbənin saxlanması üçün əlavə xərclər səbəbindən ümumi ötürmə qabiliyyətini 10-20% azaldır.

Kilidsiz atomik strukturlar

Lock-free məlumat strukturları (ConcurrentHashMap, AtomicReference, LongAdder) tərifinə görə Starvation-ı istisna edir, çünki onlarda bir thread tərəfindən saxlanıla bilən kilidlər yoxdur. Bütün əməliyyatlar prosessorun CAS təlimatlarından istifadə edir ki, bu da sonlu sayda addımda ən azı bir thread-in irəliləməsini təmin edir. Mobil inkişaf üçün tapşırıq növbələri üçün ConcurrentLinkedQueue-ə üstünlük verin.

Qısa kritik seksiyalar

Kilidin saxlanma müddətinin minimallaşdırılması — Starvation riskini azaltmağın universal üsuludur. Ağır əməliyyatları (şəbəkə, disk giriş-çıxışı, mürəkkəb hesablamalar) synchronized blokundan kənara çıxarın. Oxucuların nadir yazıçılar səbəbindən aclıq çəkməməsi üçün ReadWriteLock istifadə edin. Kotlin Coroutines kitabxanası OS thread-ni bloklamayan suspending mexanizmi ilə Mutex təqdim edir.

Şərti dəyişənlər və siqnallar

Condition.await() və signal() ehtiyatla istifadə edilməlidir: Condition-da gözləyən thread digər thread-larla birlikdə oyanır (spurious wakeup) və hamısı kilid üçün rəqabət aparır. Əgər bir thread await-dən sonra dərhal gözləməyə qayıdırsa, digərləri isə kilidi ələ keçirməyə nail olursa — aclıq çəkən thread sonsuz olaraq oyanıb yuxuya gedə bilər. Şərti həmişə while dövrəsində yoxlayın, if-də deyil, təkrar yoxlamanı təmin etmək üçün.

Tez-tez verilən suallar

Starvation ilə Priority Inversion arasında nə fərq var?

Priority Inversion — bu, aşağı prioritetli thread-in yüksək prioritetli thread üçün lazım olan kilidi saxladığı vəziyyətdir. Nəticədə yüksək prioritetli thread aşağı prioritetlini gözləyir — prioritetlər tərsinə çevrilir. Starvation daha geniş problemdir: thread prioritetdən asılı olmayaraq, ədalətsiz planlaşdırma və ya uzun kritik seksiyalar səbəbindən resurs almır.

Starvation təkthreadli tətbiqdə yarana bilərmi?

Xeyr, Starvation — çoxthreadlilik problemidir. Təkthreadli kodda resurslar üçün rəqabət və thread planlaşdırması yoxdur. Lakin Starvation asinxron təkthreadli kodda (məsələn, JavaScript event loop) yarana bilər, əgər bir mikrotapşırıq setTimeout vasitəsilə sıfır gecikmə ilə digərlərinin icrasını sonsuz təxirə salırsa.

Java Memory Model Starvation ilə necə əlaqəlidir?

JMM (Java Memory Model) thread-lar arasında dəyişikliklərin görünmə qaydalarını müəyyən edir, lakin ədalətli planlaşdırmanı təmin etmir. JMM-ə uyğun olaraq synchronized sequential consistency — əsas düzgünlüyü təmin edir, lakin Starvation-ın qarşısını almır. Ədalət üçün JMM spesifikasiyasına daxil olmayan əlavə mexanizmlər tələb olunur.

Android UI thread-də Starvation nədir?

UI thread (Main Thread) klassik mənada aclıq çəkə bilməz, çünki ən yüksək prioritetə malikdir. Lakin Starvation UI thread aclıq çəkən fon thread-in nəticəsini gözlədikdə yaranır. Tipik ssenari: AsyncTask və ya korutin məlumatları yükləyir, lakin digər thread-larla rəqabət səbəbindən verilənlər bazasına giriş əldə edə bilmir və UI gözləmədə donur.

Kotlin Coroutines-də Starvation-ın qarşısını necə almaq olar?

Korutinlərdə Starvation-ın qarşısını almaq üçün Dispatchers.IO-da limitedParallelism istifadə edin ki, thread-ların tükənməsindən qaçınasınız. Sinxronizasiya üçün kotlinx.coroutines.sync-dən Mutex tətbiq edin — o, korutini dayandırır, thread-i bloklamır, bu da aclıq riskini azaldır. Korutinlərdə runBlocking-dən çəkinin, çünki o, hovuz thread-ni ələ keçirib digər korutinlərin Starvation-na səbəb ola bilər.

Nəticə

  • Starvation — thread icraya hazır olduğu halda ədalətsiz planlaşdırma səbəbindən resurs almadığı vəziyyət
  • Deadlock-dan fərqli olaraq, aclıq zamanı thread RUNNABLE vəziyyətindədir və yük azaldıqda icra oluna bilər
  • Ədalətsiz kilidlər (synchronized) və prioritetlərin düzgün istifadə edilməməsi — Starvation-ın əsas səbəbləri
  • Fair Lock (true flag-ı ilə ReentrantLock) FIFO giriş sırasını təmin edir və aclığı tamamilə aradan qaldırır
  • Lock-free strukturlar (ConcurrentHashMap, AtomicReference) Starvation-ı arxitektura səviyyəsində istisna edir
  • Thread Dump təkrar götürmələrlə və Java Flight Recorder — Starvation diaqnostikasının effektiv üsulları
  • Qısa kritik seksiyalar və ReadWriteLock yüksək yüklü sistemlərdə aclıq ehtimalını azaldır

Açar təslim mobil tətbiq hazırlayacağıq

IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.

Layihəni müzakirə et

Həm də oxuyun