Livelock (aktiv bloklama) — çoxiplikli proqramlaşdırmada iplərin bloklanmadığı, lakin bir-birinin hərəkətlərinə sonsuz reaksiya verərək faydalı iş görmədiyi vəziyyətdir. Baeldung (Java Concurrency Guide, 2024)-a görə, Livelock zamanı iplər qonşu iplərin vəziyyətinə cavab olaraq daim vəziyyət dəyişir, lakin heç biri məqsədə çatmır. Deadlock-dan fərqli olaraq, Livelock 100% CPU sərf edir ki, bu da mobil cihazın batareyasını tez boşaldır.
Əsas məqamlar
Livelock (aktiv bloklama) — çoxiplikli sistemdə iplərin bloklanmadığı, lakin faydalı iş də görmədiyi vəziyyətdir. Hər bir ip işi davam etdirə bilmədiyini aşkarlayır və bunu düzəltməyə çalışır, lakin onun hərəkətləri digər iplərdə eyni reaksiyaya səbəb olur. Nəticədə sistem irəliləyiş əldə etmədən sonsuz olaraq vəziyyətlər arasında keçid edir.
Livelock-un klassik analogiyası — dar dəhlizdə iki nəfərin qarşılaşmasıdır. Hər biri yol vermək üçün kənara çəkilir, lakin hər ikisi eyni anda eyni hərəkəti edir və yenə üz-üzə gəlir. Onlar yerində dayanmır (bu Deadlock olardı), aktiv hərəkət edir, lakin yenə də ayrıla bilmir. Proqramlaşdırmada bu, daim resursları boşaldan və yenidən ələ keçirən iplərə uyğun gəlir.
Mobil inkişafda Livelock xüsusilə təhlükəlidir, çünki o, istifadəçi üçün görünməzdir: tətbiq donmur, interfeys bloklanmır, lakin batareya fon iplərinin 100% CPU yükü səbəbindən 2-3 dəfə tez boşalır. Google testlərinə görə (Android Battery Optimization, 2023), fon Service-də Livelock cihazın batareya ilə işləmə müddətini 40% qısalda bilər.
Livelock bir neçə ipin eyni münaqişə reaksiya strategiyasından istifadə etdiyi zaman yaranır. Əgər İp A resursu ələ keçirə bilmir və cari resursunu boşaldırsa, İp B də eyni anda eyni şeyi edirsə, hər ikisi dövrü təkrarlayır və vəziyyət sonsuz təkrarlanır. Bu, xüsusilə TryLock və uğursuzluqda avtomatik boşaltma alqoritmləri üçün xarakterikdir.
İplər təkrar cəhddən əvvəl sabit gecikmədən istifadə etdikdə, sinxron dövrə girə bilərlər. Hər iki ip eyni vaxt gözləyirsə, yenə eyni anda resursu ələ keçirməyə çalışacaq və eyni anda boşaldacaq. Problem, Ethernet-də CSMA/CD alqoritmində olduğu kimi, təsadüfi komponentli (jitter) exponential backoff istifadə edilərək həll olunur.
Mobil inkişafda Livelock tez-tez tapşırıq sıralarının yanlış implementasiyası zamanı yaranır. Məsələn, işçi ip mesajın emalını bitirdikdə, lakin prioritetləşdirmə məntiqinə görə daim nəzarəti eyni şeyi edən başqa bir işçiyə ötürdükdə. Bu hallar qeyri-standart RejectedExecutionHandler siyasəti olan fərdi ThreadPoolExecutor-lar üçün xarakterikdir.
İki ipin TryLock istifadə edib uğursuzluqda resursu boşaltdığı bir vəziyyəti nəzərdən keçirək. Aktiv bloklama ona görə yaranır ki, hər iki ip eyni məntiqi tətbiq edir və sinxron olaraq cəhdləri təkrarlayır.
import java.util.concurrent.locks.ReentrantLock
import java.util.concurrent.TimeUnit
class LivelockWorker(private val name: String,
private val lock1: ReentrantLock,
private val lock2: ReentrantLock) {
fun execute() {
while (true) {
if (lock1.tryLock(50, TimeUnit.MILLISECONDS)) {
if (lock2.tryLock(50, TimeUnit.MILLISECONDS)) {
println("$name — yerinə yetirildi!")
lock2.unlock()
lock1.unlock()
return
} else {
lock1.unlock() // boşaldırıq və təkrar edirik
}
}
Thread.sleep(50) // sabit gecikmə — Livelock-un əsas amili
}
}
}
Əgər iki LivelockWorker nümunəsi lock1 və lock2-ni fərqli sıra ilə ələ keçirməklə işə salınarsa, onlar aktiv bloklamaya girəcəklər. Hər biri birinci resursu ələ keçirəcək, ikincini ala bilməyəcək, birincini boşaldacaq, 50 ms gözləyəcək və təkrarlayacaq — sonsuz, CPU sərf edərək. Düzəliş — gecikməyə təsadüfi komponent (jitter) əlavə etmək və təkrar cəhd sayını məhdudlaşdırmaq.
Düzəldilmiş versiya təsadüfi jitter ilə exponential backoff istifadə edir. Hər uğursuz cəhddən sonra gözləmə müddəti təsadüfi çarpan əlavə edilərək artır, bu da iplər arasında sinxronluğu pozur.
fun executeWithBackoff() {
var delay = 10L
var attempts = 0
while (attempts < 5) {
if (lock1.tryLock(delay, TimeUnit.MILLISECONDS)) {
if (lock2.tryLock(delay, TimeUnit.MILLISECONDS)) {
println("Uğur!")
lock2.unlock(); lock1.unlock()
return
}
lock1.unlock()
}
delay = (delay * 2 + (0..50).random())
attempts++
}
println("5 cəhddən sonra alınmadı")
}
Xarici oxşarlığa baxmayaraq, Livelock və Deadlock prinsipial olaraq fərqli mexanizmlərə və nəticələrə malikdir. Deadlock zamanı iplər bloklanır və CPU sərf etmir — tətbiq sadəcə donur. Livelock zamanı iplər aktivdir, 100% CPU sərf edir, lakin faydalı iş görmür. Aradan qaldırma strategiyasının seçimi bloklama növünün düzgün müəyyən edilməsindən asılıdır.
| Parametr | Deadlock | Livelock |
|---|---|---|
| İplərin vəziyyəti | BLOCKED / WAITING | RUNNABLE |
| CPU sərfiyyatı | Minimal | Yüksək (90-100%) |
| Batareya sərfiyyatı | Aşağı | Yüksək |
| Aşkarlama | Thread Dump | CPU Profiler + vizual analiz |
| Tipik səbəb | Bloklamaların fərqli ələ keçirmə sırası | Münaqişəyə eyni reaksiya strategiyası |
| Düzəliş | Bloklama iyerarxiyası | Retry limit + exponential backoff |
Mobil inkişafda praktik fərq çox böyükdür. Deadlock ANR və tətbiqin yenidən başlamasına gətirib çıxarır — Google Play Console vasitəsilə aşkarlanır və bildirilir. Livelock diqqətdən kənar qalır: tətbiq işləyən kimi görünür, lakin batareya bir saata boşalır və istifadəçi sadəcə tətbiqi silir. Firebase Analytics məlumatlarına görə (App Retention Report, 2024), istifadəçilərin 68%-i tətbiqi silir, əgər o fonda həddindən artıq batareya sərf edirsə.
Livelock-un aşkarlanması Deadlock-dan daha çətindir, çünki sistem aşkar siqnallar vermir — istisna yoxdur, ANR yoxdur, səhv mesajları yoxdur. Əsas diaqnostika metodu — CPU Profiler Android Studio-da. Əgər ip daim RUNNABLE vəziyyətindədirsə, lakin faydalı giriş-çıxış və ya hesablama əməliyyatları yerinə yetirmirsə — bu, Livelock şübhəsidir.
Əlavə əlamət — tətbiq boş vəziyyətdə ikən anormal batareya sərfiyyatı. Android Battery Historian (Android SDK tərkibində alət) komponentlər üzrə enerji sərfiyyatı qrafikləri qurur. Əgər CPU Wakelock görünən səbəb olmadan saxlanılırsa — Method Tracing işə salmaq və şübhəli iplərin çağırış stack-lərini təhlil etmək lazımdır.
Kod səviyyəsində təkrar cəhdlərin loglanması threadId və vaxt göstərilməklə kömək edir. Əgər log saniyədə minlərlə təkrar cəhd göstərirsə və heç bir uğur yoxdursa — bu Livelock-dur. Hystrix-ə bənzər circuit breaker və ya hədd aşıldıqda əməliyyatı söndürən və Crashlytics vasitəsilə tərtibatçıya xəbər verən retry sayğacı tətbiq etmək tövsiyə olunur.
Ən sadə və ən etibarlı üsul — resursun ələ keçirilməsi cəhdlərinin sayını məhdudlaşdırmaqdır. Əgər N cəhddən sonra əməliyyat uğursuz olarsa, ip xəta vəziyyətinə keçir və istifadəçini xəbərdar edir. N empirik olaraq seçilir: mobil tətbiqlər üçün adətən 3-5 cəhd. Bu, yüksək yük altında nadir yanlış işə düşmələr bahasına sonsuz Livelock-u tamamilə aradan qaldırır.
Cəhdlər arasında sabit gecikmə əvəzinə eksponensial artan fasilə istifadə olunur. Formula: delay = min(baseDelay * 2^attempt, maxDelay) + random(0, jitter). Bu yanaşma təkcə iplərin sinxronluğunu pozmur, həm də yüksək rəqabət zamanı ümumi sistem yükünü azaldır. Şəbəkə protokollarının alqoritmlərində istifadə olunur və Google tərəfindən Firebase Realtime Database retry məntiqi üçün tövsiyə edilir.
Müxtəlif iplərə fərqli strategiyalar təyin etmək Livelock-un səbəbini — münaqişəyə eyni reaksiyanı — aradan qaldırır. Məsələn, yüksək prioritetli ip resursu boşaltmadan alır, aşağı prioritetli isə boşaldır və gözləyir. Mobil inkişafda UI ipi bloklamaların ələ keçirilməsində prioritetə malik ola bilər, fon işçi ipləri isə timeout ilə TryLock istifadə edə bilər.
Bəzi arxitekturalarda Livelock dizayn səviyyəsində qarşısı alınır: resursların yalnız bir istiqamətdə boşaldılması. Məsələn, İp A həmişə nəzarəti İp B-yə sabit kanal (Channel) vasitəsilə ötürürsə və B heç vaxt nəzarəti A-ya qaytarmağa çalışmırsa — reaksiya dövrü mümkün deyil. Android CameraX və MediaPipe-də tək istiqamətli emal mərhələləri olan boru kəməri arxitekturası qonşu mərhələlər arasında Livelock-u tamamilə aradan qaldırır.
Tez-tez verilən suallar
Sonsuz döngü xarici amillərdən asılı deyil və digər iplərlə qarşılıqlı əlaqə olmadan bir əməliyyatı təkrarlayır. Livelock — bu həmişə digər iplərin hərəkətlərinə reaksiyadır: ip qonşu iplərin vəziyyətinə cavab olaraq davranışını dəyişir, qapalı əks əlaqə yaradır. Livelock zamanı Thread Dump daimi kontekst dəyişməsini göstərir.
Verilənlər bazalarında Livelock, tranzaksiyanın daim təxirə salınması səbəbindən yaranır. Məsələn, DBMS wait-die alqoritmindən istifadə edir: başlama vaxtı daha kiçik olan tranzaksiya daha yenisi ilə toqquşarsa, geri qaytarılır və yenidən başladılır, lakin hər dəfə eyni toqquşmaya düşür. Bu, randomized restart delay ilə həll olunur.
Bəzi sistemlərdə Livelock Deadlock-dan daha üstün hesab olunur, çünki iplər aktiv qalır və problemi aşkarlaya bilir. Məsələn, optimist bloklama (optimistic locking) alqoritmlərində livelock-a bənzər davranışa icazə verilir, əgər retry limit sonlu tamamlanmanı təmin edirsə. Bu, performans və irəliləyiş təminatı arasında kompromisdir.
Livelock testlərdə çox çətin təkrarlanır, çünki iplərin vaxtlarının dəqiq üst-üstə düşməsini tələb edir. Vahid testlər deterministik şəkildə icra olunur və nadir hallarda aktiv bloklamanı aşkarlayır. Yük altında çoxsaylı işə salmalarla Stress Testing və profilerdə CPU istehlakının monitorinqi tövsiyə olunur.
Serverdə Livelock performans deqradasiyasına və timeout-lara gətirib çıxarır, lakin server üfüqi miqyaslanır. Android-də Livelock batareyanı boşaldır və cihazı qızdırır, daha pis UX yaradır. Bundan əlavə, mobil cihazlarda CPU nüvələrinin sayı məhduddur, buna görə Livelock daha tez bütün sistemin işlək vəziyyətini itirməsinə səbəb olur.
Nəticə
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.
Həm də oxuyun