CodeGym /Kurslar /JAVA 25 SELF /Axının vəziyyətləri və həyat dövrü

Axının vəziyyətləri və həyat dövrü

JAVA 25 SELF
Səviyyə, Dərs
Mövcuddur

1. Java-da axının əsas vəziyyətləri

Java-da axın sadəcə “işə salınıb” və ya “dayanıb” deyil. Onun tam bir həyat dövrü var və hər mərhələdə axın fərqli davranır. Bu mərhələləri anlamaq — sabit çoxaxınlı tətbiqlər yazmağın və qəribə “asılmalar” və “gözlənilməz tamamlanmalar”ın sazlanmasının açarıdır.

Hansı vəziyyətlər var?

Java aşağıdakı əsas axın vəziyyətlərini müəyyən edir (onlar Thread.State enum-unda sadalanır):

Vəziyyət Təsvir
NEW
Axın yaradılıb, lakin hələ işə salınmayıb (new Thread(...), amma start() çağırılmayıb)
RUNNABLE
Axın icra üçün hazırdır və ya hazırda icra olunur
BLOCKED
Axın monitorun azad edilməsini gözləyir (synchronized blokunda bloklanıb)
WAITING
Axın başqa bir axının onu “oyatmasını” gözləyir (məsələn, Object.wait() vasitəsilə)
TIMED_WAITING
Axın taym-out-la gözləyir (məsələn, Thread.sleep(1000), wait(1000), join(1000))
TERMINATED
Axın icrasını tamamlayıb

Maraqlı fakt:
Köhnə kitab və məqalələrdə başqa adlara və ya bir qədər fərqli sxemlərə rast gələ bilərsiniz. Amma Java 5+ ilə bu vəziyyətlər standart sayılır.

Axının həyat dövrünün vizual sxemi

stateDiagram-v2
    [*] --> NEW
    NEW --> RUNNABLE: start()
    RUNNABLE --> BLOCKED: synchronized-a daxil olma cəhdi, lakin monitor məşğuldur
    BLOCKED --> RUNNABLE: monitor azad edildi
    RUNNABLE --> WAITING: wait(), join()
    RUNNABLE --> TIMED_WAITING: sleep(), wait(timeout), join(timeout)
    WAITING --> RUNNABLE: notify()/notifyAll(), join() başa çatdı
    TIMED_WAITING --> RUNNABLE: taym-out bitdi / notify()/notifyAll()
    RUNNABLE --> TERMINATED: run() başa çatdı
    WAITING --> TERMINATED: run() başa çatdı (nadir)
    TIMED_WAITING --> TERMINATED: run() başa çatdı (nadir)

2. Axını idarəetmə metodları

Yuxu: Thread.sleep(long millis)

Bəzən axının “yuxuya getməsi” lazımdır ki, digərlərinə mane olmasın və ya hadisəni gözləsin. Thread.sleep(ms) metodu axını müəyyən edilmiş millisekund müddətinə

TIMED_WAITING
vəziyyətinə keçirir.

System.out.println("Axın 2 saniyəlik yuxuya gedir...");
Thread.sleep(2000); // 2 saniyəlik yuxuya gedirik
System.out.println("Axın oyandı!");
  • Yuxu bitəndən sonra axın
    RUNNABLE
    vəziyyətinə qayıdır (işə hazırdır).
  • Axın yuxu zamanı dayandırılarsa, InterruptedException atılır.

Başqa axının tamamlanmasını gözləmək: join()

Bəzən axını sadəcə işə salmaq yox, onun işi bitənə qədər gözləmək lazımdır. Bunun üçün Java-da join() metodu var:

Thread t = new Thread(() -> {
    System.out.println("İşləyirəm...");
    try { Thread.sleep(1000); } catch (InterruptedException e) {}
    System.out.println("Hazırdır!");
});
t.start();
System.out.println("t axınının tamamlanmasını gözləyirəm...");
t.join(); // Cari axın (məsələn, main) t-ni gözləyir
System.out.println("t axını tamamlandı!");

Burada əsas axın, join() çağırılan kimi gözləməyə başlayır. Bu müddət ərzində o,

WAITING
vəziyyətində olur, ta ki t axını icranı bitirsin. Taym-outlu variant da var — join(long millis). Bu halda axın məhdud zaman gözləyir və onun vəziyyəti
TIMED_WAITING
olacaq.

Axının dayandırılması: interrupt()

Bəzən istifadəçi “Ləğv et” düyməsini basanda olduğu kimi, axından işi dayandırmasını xahiş etmək lazım olur. Bunun üçün interrupt() metodu istifadə olunur:

Thread t = new Thread(() -> {
    while (!Thread.currentThread().isInterrupted()) {
        // İşləyirik...
    }
    System.out.println("Axın dayandırma siqnalına görə tamamlandı!");
});
t.start();
// ... bir müddət sonra:
t.interrupt(); // Axına siqnal: “dayanma vaxtıdır”

Anlamaq vacibdir ki, çağırış interrupt() axını dərhal öldürmür. O, sadəcə xüsusi bir bayraq qurur. Axının özü bu bayrağı vaxtaşırı isInterrupted() vasitəsilə yoxlamalı və öz-özünə tamamlanmalıdır. Əgər axın həmin vaxt yuxu vəziyyətində (sleep()) və ya gözləmədə (wait())dirsə, o, təkcə bayrağı görməyəcək, həm də dərhal InterruptedException alacaq. Məhz belə, Java-da axınların “düzgün” dayandırılması qurulub: proqram onları güc tətbiq edərək dayandırmır, sadəcə tamamlanma vaxtının gəldiyini bildirir.

3. Vəziyyətlər arasında keçid nümunələri

Gəlin nümunələrlə axının öz vəziyyətləri arasında necə “səyahət etdiyinə” baxaq.

Nümunə 1:
NEW
→
RUNNABLE
→
TERMINATED

Thread t = new Thread(() -> System.out.println("Salam!"));
System.out.println(t.getState()); // NEW
t.start();
System.out.println(t.getState()); // RUNNABLE (və ya TERMINATED, əgər axın çox sürətlidirsə)
t.join();
System.out.println(t.getState()); // TERMINATED

Nümunə 2:
RUNNABLE
→
TIMED_WAITING
→
RUNNABLE
→
TERMINATED

Thread t = new Thread(() -> {
    try {
        System.out.println("Yuxuya gedirəm...");
        Thread.sleep(1000); // TIMED_WAITING
        System.out.println("Oyandım!");
    } catch (InterruptedException e) {
        System.out.println("Axın dayandırıldı!");
    }
});
t.start();

Nümunə 3:
RUNNABLE
→
WAITING
join() ilə

Thread t1 = new Thread(() -> {
    try { Thread.sleep(500); } catch (InterruptedException ignored) {}
    System.out.println("t1 tamamlandı");
});
Thread t2 = new Thread(() -> {
    try {
        t1.join(); // t2, t1-i gözləyir, WAITING vəziyyətindədir
        System.out.println("t2, t1-i gözlədi");
    } catch (InterruptedException ignored) {}
});
t1.start();
t2.start();

Nümunə 4:
BLOCKED

Object lock = new Object();

Thread t1 = new Thread(() -> {
    synchronized (lock) {
        try { Thread.sleep(1000); } catch (InterruptedException ignored) {}
        System.out.println("t1 synchronized blokundan çıxdı");
    }
});
Thread t2 = new Thread(() -> {
    synchronized (lock) {
        System.out.println("t2 synchronized-a daxil oldu");
    }
});
t1.start();
Thread.sleep(100); // t1-ə lock-u ələ keçirməyə imkan verək
t2.start();
Thread.sleep(100); // t2-yə synchronized-a daxil olmağa cəhd etməsi üçün imkan verək
System.out.println("t2-nin vəziyyəti: " + t2.getState()); // BLOCKED

4. Axının vəziyyətini necə bilmək olar? Metodlar isAlive() və getState()

  • isAlive() — axın işə salınıb və hələ tamamlanmayıbsa true qaytarır (
    TERMINATED
    artıq false deməkdir).
  • getState() — axının cari vəziyyətini qaytarır (Thread.State enum-dan dəyər).
Thread t = new Thread(() -> {});
System.out.println(t.isAlive()); // false (NEW)
t.start();
System.out.println(t.isAlive()); // true (RUNNABLE/WAITING/...)
t.join();
System.out.println(t.isAlive()); // false (TERMINATED)

5. Niyə axını birbaşa “öldürmək” olmaz və digər praktiki məsləhətlər

“kill” metodu yoxdur!

Java-da əmrlə axını “öldürməyə” imkan verən metod yoxdur. Niyə? Çünki bu, təhlükəlidir: əgər axın hansısa resursu (fayl, qoşulma, bloklama) saxlayırsa, onu məcburi məhv etmək sistemi uyğunsuz vəziyyətdə qoya bilər.

Köhnəlmiş metodlar: stop(), suspend(), resume()

Java-nın qədim versiyalarında stop(), suspend(), resume() metodları vardı. İndi onlar @Deprecated kimi işarələnib və onların istifadəsi qətiyyən tövsiyə edilmir. Niyə?

  • stop() axını istənilən anda öldürə bilər və məlumatı uyğunsuz vəziyyətdə qoya bilər.
  • suspend() bloklanmanı saxlayan axını “dondura” bilər və onda bütün proqram asılar.
  • resume() bəzən artıq tamamlanmış axını “əridə” bilmir.

Müasir yanaşma:
Axın dayandırma bayrağına (isInterrupted()) və ya digər siqnallara reaksiya verərək özünü düzgün şəkildə tamamlamalıdır.

Ən yaxşı təcrübələr

  • Köhnəlmiş kimi işarələnmiş metodları çağırmayın.
  • Axını dayandırmaq üçün dayandırma bayrağından istifadə edin (interrupt() və yoxlama isInterrupted()).
  • Sazlama zamanı axınların vəziyyətlərini izləyin — bu, asılmaları və deadlock-ları tapmağa kömək edəcək.
  • Əgər axının işinin tamamlanmasını gözləmək lazımdırsa, join()-u unutmayın.

6. Axının həyat dövrü ilə işləyərkən tipik səhvlər

Səhv №1: Axını təkrar işə salmaq.
Java-da axını yalnız bir dəfə işə salmaq olar. start() metodunu ikinci dəfə çağırsanız — IllegalThreadStateException alacaqsınız. Tapşırığı təkrar etmək lazımdırsa — yeni bir Thread obyekti yaradın.

Thread t = new Thread(() -> {});
t.start();
t.start(); // İstisna atacaq!

Səhv №2: run() ilə start()-ı qarışdırmaq.
Birbaşa run() çağırmaq kodu yeni axında işə salmır — o, cari axında (məsələn, main) icra olunur. Yalnız start() həqiqətən yeni axını işə salır.

Səhv №3: InterruptedException-i emal etməmək.
Əgər axın yatır və ya gözləyirsə və o dayandırılarsa, InterruptedException atılacaq. Onu görməməzlikdən gəlsəniz, axın “əbədi yuxuya” gedə və ya gözlənilmədən tamamlana bilər.

Səhv №4: Axının vəziyyətini yoxlamamaq.
Bəzən proqram ona görə asılır ki, bir axın artıq tamamlanmış və ya heç vaxt başlamayacaq başqa bir axını gözləyir. Diaqnostika üçün getState() və isAlive() istifadə edin.

Səhv №5: Axını idarə etmək üçün köhnəlmiş metodlardan istifadə etmək.
stop(), suspend(), resume() metodları — zərərlidir. “Hər şeyi tez düzəltmək” çox cazibədar görünsə belə, onlardan istifadə etməyin.

1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Kosmik missiyanın başa çatmasının yoxlanması 🛰️
Kosmik missiyanın başa çatmasının yoxlanması 🛰️
1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
İki işçinin işinin sinxronlaşdırılması 🤝
İki işçinin işinin sinxronlaşdırılması 🤝
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION