Java wait() Imeelezwa: Jinsi Inavyofanya Kazi, Jinsi ya Kuitumia Salama, na Tofauti na sleep()

目次

1. Java wait() ni Nini? (Elewa Dhana ya Msingi Haraka)

java wait inahusu njia inayotumika kusitisha muda kwa uzi (mtiririko wa utekelezaji) na kusubiri taarifa kutoka kwa uzi mwingine.
Inatumika katika multithreading (kufanya kazi nyingi kwa wakati mmoja) ili kutekeleza udhibiti ulioambatana kati ya vizi.

Jambo kuu ni kwamba wait() si “kusubiri tu muda kupita.”
Mpaka uzi mwingine uita notify() au notifyAll(), uzi lengwa unabaki katika hali ya kusubiri (WAITING).

1.1 Maana ya Msingi ya wait()

Kiini cha wait() kinahitimisha kwenye pointi hizi tatu:

  • Weka uzi wa sasa katika hali ya kusubiri
  • Kuachilia kwa muda kifungo cha kipengele lengwa
  • Endelea tena ukipatiwa taarifa na uzi mwingine

Mtiririko wa dhana:

  1. Ingia katika bloku ya synchronized
  2. Itwa wait()
  3. Achilia kifungo na ingia katika hali ya kusubiri
  4. Uzi mwingine uite notify()
  5. Pata tena kifungo, kisha endelea utekelezaji

Mfano wa sarufi rahisi:

synchronized(obj) {
    obj.wait();
}

⚠ Kumbuka

  • wait() si “kusitisha kwa muda uliowekwa,” bali “kusubiri taarifa.”
  • Ikiwa hakuna anayejulisha, inaweza kusubiri milele.

1.2 wait() Ni Njia ya Object

wait() si njia ya Thread.
Ni njia ya Object.

Ufafanuzi (dhana):

public final void wait()

Kwa maneno mengine:

  • Kila kipengele cha Java kina wait()
  • Unasubiri kulingana na kipengele ambacho unachokichunguza

Madhara ya kawaida:

❌ Kufikiri ni Thread.wait()
❌ Kufikiri inasimamisha uzi moja kwa moja

Uelewa sahihi:

✔ “Subiri kwenye monitor ya kipengele (kifungo cha monitor)”

*Monitor = kifungo kinachodhibitiwa na synchronized.

1.3 Sharti la Lazimu la Kutumia wait()

Ili kutumia wait(), lazima uiite ndani ya bloku ya synchronized.

Kwa nini:

  • wait() inachilia kifungo ambacho unashikilia kwa sasa
  • Ikiwa huna kifungo, usawa hauwezi kudhaminiwa

Mfano usio sahihi:

Object obj = new Object();
obj.wait();   // ❌ IllegalMonitorStateException

Mfano sahihi:

Object obj = new Object();

synchronized(obj) {
    obj.wait();
}

Kukera kunarushwa:

IllegalMonitorStateException

Hii ina maana “wait() iliitwa bila kushikilia kifungo.”

⚠ Mahali Ambapo Wanafunzi Wapya Huwakumbwa

  • Kuchanganya na sleep() (sleep haina kufungua kifungo)
  • Kusahau kuandika synchronized
  • Kutoita notify, hivyo husimama milele
  • Kuita notify kwenye kipengele tofauti

✔ Muhtasari Muhimu Zaidi

  • wait() ni njia ya Object
  • Inaweza kutumika tu ndani ya synchronized
  • Inachilia kifungo na kusubiri taarifa
  • Si “chelewa ya muda” rahisi

2. Matumizi Sahihi ya wait() (Elewa kwa Mifano ya Msimbo)

wait() haina maana peke yake.
Inafanya kazi tu inapounganishwa na notify / notifyAll.

Katika sura hii, tutaelezea hatua kwa hatua, kuanzia usanidi mdogo hadi mifumo ya vitendo.

2.1 Sarufi ya Msingi

Muundo mdogo sahihi unaonekana hivi:

Object lock = new Object();

synchronized(lock) {
    lock.wait();
}

Hata hivyo, huu utaacha kusimama milele kama ilivyo.
Sababu: hakuna taarifa (notify).

2.2 Mfano na notify (Muhimu Zaidi)

wait() inamaanisha “kusubiri taarifa.”
Kwa hiyo, uzi mwingine lazima uite notify.

✔ Mfano wa Kazi Kidogo

class Example {
    private static final Object lock = new Object();

    public static void main(String[] args) {

        Thread waitingThread = new Thread(() -> {
            synchronized(lock) {
                try {
                    System.out.println("Waiting...");
                    lock.wait();
                    System.out.println("Resumed.");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread notifyingThread = new Thread(() -> {
            synchronized(lock) {
                System.out.println("Inajulisha...");
                lock.notify();
            }
        });

        waitingThread.start();
        notifyingThread.start();
    }
}

Execution Flow

  1. waitingThread acquires lock
  2. It calls wait() , releases the lock, and waits
  3. notifyingThread acquires lock
  4. It calls notify() to signal the waiting thread
  5. After re-acquiring the lock, execution resumes

2.3 Difference Between notify and notifyAll

MethodBehavior
notify()Resumes only one waiting thread
notifyAll()Resumes all waiting threads

In real-world code, notifyAll() is often considered safer.

Why:

  • With notify() , a thread that should not resume might be selected
  • When multiple conditions exist, inconsistencies become more likely

2.4 The Correct Practical Pattern (Use while)

wait() is typically used together with a condition check.

synchronized(lock) {
    while (!condition) {
        lock.wait();
    }
}

Why:

  • Spurious wakeups (resuming without notification) can happen
  • After notifyAll , the condition may still not be satisfied

❌ Incorrect example:

if (!condition) {
    lock.wait();
}

This is not safe.

⚠ Common Mistakes

  • Calling wait and notify on different objects
  • Assuming it resumes immediately after notify (it must re-acquire the lock)
  • Calling notify outside synchronized
  • Forgetting to update the condition variable

✔ Implementation Steps Summary

  1. Create a shared lock object
  2. Wrap with synchronized
  3. Check the condition with while
  4. Wait with wait()
  5. Notify from another thread using notify / notifyAll
  6. Always update the condition

3. The Difference Between wait and sleep (The Core Search Intent)

Many users who search for “java wait” want to understand how it differs from sleep().
They may look similar, but their design philosophy and use cases are completely different.

3.1 The Decisive Differences (Comparison Table)

Itemwaitsleep
Defined inObjectThread
Releases lockYesNo
Where to useMust be inside synchronizedCan be used anywhere
PurposeInter-thread communicationSimple time delay

3.2 The Biggest Difference: “Does It Release the Lock?”

✔ How wait Behaves

  • Releases the lock currently held
  • Allows other threads to acquire the lock
  • Resumes via notify
    synchronized(lock) {
        lock.wait();
    }
    

✔ How sleep Behaves

  • Stops while still holding the lock
  • Other threads cannot acquire the lock
    Thread.sleep(1000);
    

⚠ This is the most important point
sleep = “wait for time”
wait = “wait for a notification”

3.3 How to Choose in Real-World Work

✔ When to Use wait

  • Producer/Consumer patterns
  • Waiting for data to arrive
  • Waiting for a state change
  • Coordinated control between threads

✔ When to Use sleep

  • Simple delay processing
  • Adjusting retry intervals
  • Waiting in test code

3.4 Using wait with a Timeout

wait can also be called with a timeout.

lock.wait(1000);  // Subiri hadi sekunde 1

But note:

  • It may return after the timeout, but there is no guarantee the condition is satisfied
  • You must re-check the condition using while

⚠ Points That Confuse Beginners

  • Thinking sleep resumes via notification → ❌
  • Thinking wait always resumes after time → ❌
  • Thinking locks are released during sleep → ❌

✔ Conclusion

  • sleep is just a time delay
  • wait is a mechanism for inter-thread communication
  • The biggest difference is whether the lock is released

4. Advanced wait Knowledge (Must-Know for Safe Usage)

wait looks simple, but misuse can easily cause bugs.
Here we’ll explain the essential knowledge needed to implement it safely.

4.1 wait with a Timeout

wait has a timed version.

synchronized(lock) {
    lock.wait(1000);  // Subiri hadi sekunde 1
}

Behavior:

  • Waits up to the specified time
  • Returns immediately if notified
  • May also return when the time expires

⚠ Muhimu
Hata ikiwa inarudi kutokana na muda uliopita, haimaanishi “sharti ni kweli.”

Daima iunganishe na ukaguzi wa sharti.

4.2 Nini Ndiyo Kuamka Bandia (Spurious Wakeup)?

Kuamka bandia (Spurious Wakeup) ni tukio ambapo
wait inaweza kurudi hata bila taarifa.

Speci ya Java inaruhusu hili kutokea.

Hiyo inamaanisha:

  • Hakuna aliyeita notify
  • Sharti halijabadilika
  • Hata hivyo inaweza bado kurudi

Ndiyo maana kutumia while badala ya if ni lazima.

4.3 Muundo Sahihi (Funga na while)

Mfano wa utekelezaji sahihi:

synchronized(lock) {
    while (!condition) {
        lock.wait();
    }
    // Code after the condition becomes true
}

Kwa nini:

  • Ulinzi dhidi ya kuamka bandia
  • Sharti linaweza bado kuwa si sahihi baada ya notifyAll
  • Usalama wakati nyuzi nyingi zinangojea

❌ Mfano hatari:

synchronized(lock) {
    if (!condition) {
        lock.wait();  // Dangerous
    }
}

Mtindo huu unaweza kusababisha tabia isiyo sahihi.

4.4 Uhusiano na Vizuizi (Deadlocks)

wait hutoa kizuizi, lakini
vizuizi bado vinaweza kutokea wakati kizuizi nyingi zinahusika.

Mfano:

  • Nyuzi A → lock1 → lock2
  • Nyuzi B → lock2 → lock1

Hatua za kupunguza:

  • Tumia mpangilio thabiti wa upatikanaji wa kizuizi
  • Punguza idadi ya vizuizi

⚠ Makosa ya Msingi ya Kawaida

  • Kutosasisha kigezo cha sharti
  • Kuita notify bila kubadilisha hali
  • Kuweka synchronized ndani ya nyingine kupita kiasi
  • Kutokuweka mpangilio wa kizuizi thabiti kati ya vizuizi vingi

✔ Muhtasari wa Juu

  • Kufunga wait na while ni sheria isiyobadilika
  • Hata na muda uliopita, lazima upitie tena ukaguzi wa sharti
  • Ubunifu mbovu wa kizuizi unaweza kusababisha vizuizi

5. Makosa ya Kawaida na Jinsi ya Kuyatatua

wait ni API ya ngazi ya chini, hivyo makosa ya utekelezaji husababisha hitilafu moja kwa moja.
Hapa tutafupisha makosa ya kawaida, sababu zake, na jinsi ya kuyatatua.

5.1 IllegalMonitorStateException

Huu ndio kosa la kawaida zaidi.

Inapotokea:

  • Kuita wait nje ya synchronized
  • Kuita notify nje ya synchronized

❌ Mfano usio sahihi

Object lock = new Object();
lock.wait();  // Exception thrown

✔ Mfano sahihi

synchronized(lock) {
    lock.wait();
}

Muhtasari wa suluhisho:

  • Daima itii wait / notify ndani ya synchronized kwenye kitu kilicho sawa
  • Tumia kitu kimoja cha kizuizi thabiti

5.2 Haiendelee Hata Baada ya notify

Sababu za kawaida:

  • Kuita notify kwenye kitu tofauti
  • Kigezo cha sharti hakijasasishwa
  • Kushikilia kizuizi muda mrefu baada ya notify

❌ Makosa ya kawaida

synchronized(lock1) {
    lock1.wait();
}

synchronized(lock2) {
    lock2.notify();  // Different object
}

✔ Daima tumia kitu kilicho sawa

synchronized(lock) {
    lock.wait();
}

synchronized(lock) {
    condition = true;
    lock.notifyAll();
}

5.3 wait Haiishwi

Sababu kuu:

  • notify haijawahi kuitwa
  • Mantiki ya ukaguzi wa sharti si sahihi
  • Sharti la while linaendelea kuwa kweli milele

Hatua za utatuzi:

  1. Hakikisha kwamba notify inaitwa bila shaka
  2. Hakikisha kwamba kigezo cha sharti kinasasishwa
  3. Tumia logi kufuatilia mpangilio wa utekelezaji wa nyuzi

5.4 Vizuizi (Deadlocks)

Muundo wa kawaida:

synchronized(lock1) {
    synchronized(lock2) {
        ...
    }
}

Kama nyuzi nyingine inapata vizuizi kwa mpangilio wa kinyume, programu inaweza kuganda.

Hatua za kupunguza:

  • Tumia mpangilio thabiti wa upatikanaji wa kizuizi
  • Tumia kizuizi kimoja ikiwa inawezekana
  • Fikiria kutumia java.util.concurrent

5.5 Kushughulikia InterruptedException

wait inatupa InterruptedException.

try {
    lock.wait();
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
}

Ushughulikiaji unaopendekezwa:

  • Rudisha alama ya kukatiza (re-interrupt)
  • Usilete kiukosoaji

⚠ Makosa ya Kawaida Sana Katika Utendaji

  • Kufunga wait na if
  • Kuita notify kabla ya kusasisha hali
  • Kusimamia vibonye vingi kwa njia isiyo wazi
  • Kutumia bloku ya catch tupu

✔ Kanuni za Msingi za Kuepuka Makosa

  • synchronized inahitajika
  • Tumia kitu cha lock kilicho sawa kila wakati
  • Daima tumia muundo wa while
  • Sasisha hali kabla ya kuita notify
  • Shughulikia interrupts ipasavyo

6. Mbinu za Kisasa katika Java (Mtazamo wa Kitaalamu)

wait / notify ni zana za uratibu wa nyuzi za ngazi ya chini ambazo zimekuwepo tangu Java ya awali.
Katika maendeleo ya kisasa ya ulimwengu halisi, ni kawaida kutumia API salama zaidi, za ngazi ya juu badala yake.

Katika sura hii, tutafupisha kwa nini mbadala zinapendekezwa.

6.1 wait/notify Ni API za Ngazi ya Chini

Unapotumia wait, lazima usimamishe kila kitu mwenyewe.

Vitu unavyopaswa kusimamia:

  • Udhibiti wa lock
  • Vigezo vya hali
  • Utaratibu wa notifikesheni
  • Ulinzi dhidi ya kuamka bila sababu
  • Kuepuka deadlock
  • Ushughulikiaji wa interrupts

Kwa maneno mengine, ni muundo ambao kwa urahisi unakuwa chanzo cha hitilafu.

Inakuwa tata sana wakati hali nyingi na nyuzi nyingi zinahusika.

6.2 Madawa ya Mbadala ya Kawaida

Tangu Java 5, kifurushi cha java.util.concurrent kimepatikana.

BlockingQueue

Kwa kupitisha data kati ya nyuzi.

BlockingQueue<String> queue = new LinkedBlockingQueue<>();

queue.put("data");   // Waiting is handled automatically
queue.take();        // Waits until data arrives

Sifa:

  • Hakuna haja ya wait/notify
  • Ina uwezekano mdogo wa kusababisha deadlocks
  • Inatumika sana katika mifumo ya ulimwengu halisi

CountDownLatch

Inasubiri nyuzi nyingi kukamilika.

CountDownLatch latch = new CountDownLatch(1);

latch.await();   // Wait
latch.countDown();  // Signal

Matumizi:

  • Kusubiri uanzishaji ukamilike
  • Kusawazisha kazi za sambamba

ReentrantLock + Condition

API inayotoa mbinu inayofanana na wait, lakini kwa uwazi zaidi.

ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();

lock.lock();
try {
    condition.await();
} finally {
    lock.unlock();
}

Manufaa:

  • Inaweza kusimamia hali nyingi
  • Udhibiti wa lock unaobadilika zaidi

6.3 Unapaswa Kutumia Nini Katika Vitendo?

Mapendekezo kulingana na hali:

GoalRecommended Tool
Passing dataBlockingQueue
Simple synchronizationCountDownLatch
Complex condition controlReentrantLock + Condition
LearningUnderstanding wait is essential

Hitimisho:

  • Ni muhimu kuelewa wait wakati wa kujifunza
  • Katika vitendo, pendekeza kifurushi cha concurrent

⚠ Vigezo vya Uamuzi wa Kitaalamu

  • Je, unahitaji kweli kutekeleza uratibu wa nyuzi mwenyewe?
  • Je, maktaba ya kawaida inaweza kutatua hilo badala yake?
  • Je, unaweza kuhakikisha usomaji na matengenezo?

Katika hali nyingi, unaweza kutatua tatizo bila kutumia wait.

✔ Muhtasari wa Sura

  • wait ni API ya ngazi ya chini
  • Kifurushi cha concurrent ni kiwango cha kisasa
  • Kipa kipa usalama katika msimbo wa ulimwengu halisi

7. Muhtasari (Vidokezo vya Mwisho kwa Wanaoanza)

java wait ni mchakato unaotumika kusubiri mabadiliko ya hali kati ya nyuzi.
Jambo muhimu zaidi ni kwamba si ucheleweshaji wa muda tu, bali ni “mchakato wa udhibiti unaotegemea notifikesheni.”

Hebu tufupishe kile tulichokijadili kutoka kwa mtazamo wa utekelezaji.

7.1 Kiini cha wait

  • Njia ya Object
  • Inaweza kutumika tu ndani ya synchronized
  • Hutoa lock na kusubiri inapoitwa
  • Inaendelea tena kupitia notify / notifyAll

7.2 Sheria Tatu za Kuandika Msimbo Salama

1) Daima tumia synchronized
2) Funga na while
3) Sasisha hali kabla ya kuita notify

Correct template:

synchronized(lock) {
    while (!condition) {
        lock.wait();
    }
}

Notifier side:

synchronized(lock) {
    condition = true;
    lock.notifyAll();
}

7.3 Tofauti Muhimu Kutoka sleep

Itemwaitsleep
Releases lockYesNo
Use caseInter-thread communicationTime delay

Ni muhimu kutochanganya.

7.4 Inapofaa Katika Maendeleo ya Ulimwengu Halisi

  • Kuelewa ni muhimu
  • Lakini katika vitendo, kipa kipaumbele kifurushi cha concurrent
  • Buni udhibiti maalum unaotegemea wait kwa umakini mkubwa

7.5 Orodha ya Mwisho

  • Je, unatumia kitu kilichofanana cha lock?
  • Je, unakuita ndani ya synchronized ?
  • Je, imefungwa na while ?
  • Je, unasasisha hali kabla ya notify ?
  • Je, unashughulikia usumbufu ipasavyo?

Kama utafuata haya, unaweza kupunguza hatari ya hitilafu kubwa kwa kiasi kikubwa.

Maswali Yanayoulizwa Mara kwa Mara

Q1. Je, wait ni njia ya darasa la Thread?

Hapana. Ni njia ya darasa la Object.

Q2. Je, naweza kutumia wait bila synchronized?

Hapana. Itazitoa IllegalMonitorStateException.

Q3. Nini nifanye: notify au notifyAll?

Kama unapa kipaumbele usalama, notifyAll inapendekezwa.

Q4. Je, wait inaweza kutumika na muda wa kusimamisha (timeout)?

Ndiyo. Tumia wait(long millis).

Q5. Kwa nini tumia while badala ya if?

Ili kulinda dhidi ya kuamka kisicho na sababu (spurious wakeups) na kurudi kabla ya hali kutimizwa.

Q6. Je, wait hutumika sana katika msimbo wa uzalishaji wa kisasa?

Katika miaka ya hivi karibuni, kutumia java.util.concurrent imekuwa njia kuu.

Q7. Je, naweza kuibadilisha na sleep?

Hapana. sleep haitozi funguo.