IllegalMonitorStateException पर प्रतीक्षा करें () कॉल करें


162

मैं अपने प्रोग्राम के लिए जावा में मल्टी-थ्रेडिंग का उपयोग कर रहा हूं। मैंने थ्रेड सफलतापूर्वक चलाया है लेकिन जब मैं उपयोग कर रहा हूं Thread.wait()तो यह फेंक रहा है java.lang.IllegalMonitorStateException। जब तक इसे अधिसूचित नहीं किया जाएगा, तब तक मैं थ्रेड प्रतीक्षा कैसे कर सकता हूं?


2
थ्रेड.वाइट () मौजूद नहीं है, यह यह हो सकता है। प्रतीक्षा ()
प्रेमराज

जवाबों:


175

काम synchronizedकरने के लिए आपको एक ब्लॉक में होना चाहिए Object.wait()

इसके अलावा, मैं पुराने स्कूल सूत्रण पैकेजों के बजाय संगामिति पैकेजों को देखने की सलाह देता हूं। वे सुरक्षित हैं और उनके साथ काम करना आसान है

खुश कोडिंग।

संपादित करें

मैंने मान लिया Object.wait()कि आपके अपवाद के रूप में आपका क्या मतलब है जब आप वस्तुओं को लॉक किए बिना पहुंच प्राप्त करने का प्रयास करते हैं।


1
अच्छी पकड़। मैं वह Object.wait () का मतलब है और एक धागे से कहा जाता ग्रहण
reccles

2
जिस ऑब्जेक्ट पर आप प्रतीक्षा कर रहे हैं, उस पर एक सिंक्रनाइज़ ब्लॉक। इस उत्तर को संपादित करने के लिए देखभाल करें ताकि थोड़ा और स्पष्ट हो सके? धन्यवाद।
ग्रे

55

waitमें परिभाषित किया गया है Objectऔर यह नहीं है Thread। मॉनीटर Threadथोड़ा अप्रत्याशित है।

हालांकि सभी जावा ऑब्जेक्ट्स पर नज़र रखी जाती है, आम तौर पर एक समर्पित लॉक होना बेहतर होता है:

private final Object lock = new Object();

एक नामांकित वर्ग का उपयोग करके, आप एक छोटी मेमोरी लागत (लगभग प्रति प्रक्रिया 2K) पर डायग्नॉस्टिक्स पढ़ने में थोड़ा आसान हो सकते हैं:

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

करने के लिए waitया notify/ notifyAllएक वस्तु, आप के साथ ताला पकड़े जाने की जरूरत है synchronizedबयान। इसके अलावा, आपको whileजाग्रत स्थिति की जांच करने के लिए एक लूप की आवश्यकता होगी (यह समझाने के लिए थ्रेडिंग पर एक अच्छा पाठ ढूंढें)।

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

सूचित करने के लिए:

synchronized (lock) {
    makeWakeupNeeded();
    lock.notifyAll();
}

मल्टीथ्रेडिंग में होने पर जावा भाषा और java.util.concurrent.locksताले (और java.util.concurrent.atomic) दोनों को समझना अच्छी तरह से लायक है। लेकिन java.util.concurrentजब भी आप कर सकते हैं डेटा संरचनाओं का उपयोग करें ।


5
मैंने कभी नहीं समझा कि यह कैसे काम करता है, यह देखते हुए कि प्रतीक्षा और सूचना दोनों एक ही ऑब्जेक्ट (लॉक) पर सिंक्रनाइज़ ब्लॉक में हैं। चूँकि प्रतीक्षा धागा ब्लॉक में है, तो क्या "सिंक्रनाइज़ (लॉक)" लाइन पर नोटिफ़ाइड थ्रेड ब्लॉक नहीं बनाना चाहिए?
Brent212

6
@ Brent212 के अलावा किसी भी विधि के लिए wait, हाँ आपको कभी नहीं मिलेगा notify। हालांकि, एपीआई में डॉक्स Object.wait"इस मॉनीटर का स्वामित्व जारी करता है"। इसलिए waitइसमें ऐसा लगता है जैसे कि यह एन्क्लोज़िंग synchronizedब्लॉक के बाहर है (एक ही ऑब्जेक्ट के लिए, एक ही ऑब्जेक्ट synchronizedपर कई ब्लॉक हो सकते हैं )।
टॉम ह्विटिन -

24

मुझे पता है कि यह धागा लगभग 2 साल पुराना है, लेकिन अभी भी इसे बंद करने की आवश्यकता है क्योंकि मैं भी इसी मुद्दे के साथ इस क्यू / ए सत्र में आया था ...

कृपया अवैध और गैर-कानूनी अपवाद की इस परिभाषा को बार-बार पढ़ें ...

IllegalMonitorException को इंगित करने के लिए फेंक दिया जाता है कि किसी थ्रेड ने ऑब्जेक्ट के मॉनिटर पर प्रतीक्षा करने या निर्दिष्ट मॉनिटर के मालिक के बिना ऑब्जेक्ट के मॉनिटर पर प्रतीक्षा करने वाले अन्य थ्रेड्स को सूचित करने का प्रयास किया है।

यह रेखा बार-बार कहती है, IllegalMonitorException तब आती है जब 2 में से एक स्थिति होती है ...।

1> निर्दिष्ट मॉनिटर के मालिक के बिना किसी ऑब्जेक्ट के मॉनिटर पर प्रतीक्षा करें।

2> निर्दिष्ट मॉनिटर के मालिक के बिना किसी ऑब्जेक्ट के मॉनिटर पर प्रतीक्षा करने वाले अन्य थ्रेड्स को सूचित करें।

कुछ को उनके जवाब मिल गए होंगे ... जो सभी नहीं करते हैं, तो कृपया 2 स्टेटमेंट देखें ...

सिंक्रनाइज़ (ऑब्जेक्ट)

object.wait ()

यदि दोनों ऑब्जेक्ट समान हैं ... तो कोई भी गैर-कानूनी वैधता नहीं आ सकती है।

अब फिर से IllegalMonitorException परिभाषा पढ़ें और आप इसे फिर से नहीं भूलेंगे ...


दरअसल, वह काम नहीं करता है। मैंने इसे आजमाया है। मैं एक रननेबल बनाता हूं, उस पर लॉक (सिंक्रनाइज़ ब्लॉक का उपयोग करके) और उस ब्लॉक के अंदर मैं यूआई-थ्रेड (एंड्रॉइड) पर रननेबल चलाता हूं और उसके बाद मैं myRunnable.wait () करता हूं, और मुझे अभी भी अपवाद मिलता है।
टेड

एक्सेलेंट स्पष्टीकरण !! मैं ऑब्जेक्ट को निर्दिष्ट किए बिना प्रतीक्षा () कर रहा था, इसलिए इसने उदाहरण लिया, और किसी अन्य ऑब्जेक्ट पर सिंक्रोनाइज़ किया। अब मैं otherObject.wait () का उपयोग कर रहा हूं और यह काम करता है!
फर्सका

6

आपकी टिप्पणियों के आधार पर ऐसा लगता है कि आप ऐसा कुछ कर रहे हैं:

Thread thread = new Thread(new Runnable(){
    public void run() { // do stuff }});

thread.start();
...
thread.wait();

तीन समस्याएं हैं।

  1. जैसा कि अन्य लोगों ने कहा है, obj.wait()केवल तभी कहा जा सकता है जब वर्तमान थ्रेड में आदिम लॉक / म्यूटेक्स हो obj। यदि वर्तमान थ्रेड लॉक को पकड़ नहीं पाता है, तो आपको वह अपवाद मिलता है जो आप देख रहे हैं।

  2. thread.wait()कॉल क्या आप यह करने के लिए उम्मीद कर रहा हो रहे हैं नहीं करता है। विशेष रूप से, नामांकित थ्रेड को प्रतीक्षा करने का कारण thread.wait() नहीं बनता है। बल्कि यह वर्तमान थ्रेड को तब तक प्रतीक्षा करने का कारण बनता है जब तक कि कुछ थ्रेड कॉल thread.notify()या thread.notifyAll()

    वास्तव में कोई भी सुरक्षित तरीका Threadनहीं है कि अगर वह नहीं चाहता है तो एक उदाहरण को रोकने के लिए मजबूर किया जाए। (जावा के पास यह निकटतम पदावनत Thread.suspend()विधि है, लेकिन यह विधि स्वाभाविक रूप से असुरक्षित है, जैसा कि जावदोक में बताया गया है।)

    यदि आप चाहते हैं कि नव Threadठहराव शुरू हो गया है, तो इसका सबसे अच्छा तरीका यह है कि एक CountdownLatchउदाहरण बनाया जाए और await()थैले पर थ्रेड कॉल करने के लिए खुद को रोकें। मुख्य धागा तब countDown()कुंडी पर कॉल करेगा ताकि रुके हुए धागे को जारी रखा जा सके।

  3. पिछले बिंदुओं पर ऑर्थोगोनल, Threadलॉक / म्यूटेक्स के रूप में ऑब्जेक्ट का उपयोग करने से समस्या हो सकती है। उदाहरण के लिए, javadoc के लिए Thread::joinकहता है:

    यह कार्यान्वयन this.waitचालू स्थिति में कॉल के एक लूप का उपयोग करता है this.isAlive। जैसा कि एक थ्रेड समाप्त होता है this.notifyAllविधि लागू होती है। यह अनुशंसित है कि आवेदन पत्र का उपयोग नहीं wait, notifyया notifyAllपर Threadउदाहरणों।


2

चूंकि आपने कोड पोस्ट नहीं किया है, इसलिए हम अंधेरे में काम कर रहे हैं। अपवाद का विवरण क्या हैं?

क्या आप थ्रेड के भीतर या उसके बाहर से थ्रेड.विट () कॉल कर रहे हैं?

मैं यह पूछता हूं क्योंकि इलीगलमोनिटरस्ट्रेटटेक्स्टैप्शन के लिए javadoc के अनुसार, यह है:

यह इंगित करने के लिए फेंक दें कि किसी थ्रेड ने ऑब्जेक्ट के मॉनिटर पर प्रतीक्षा करने या निर्दिष्ट मॉनिटर के मालिक के बिना ऑब्जेक्ट के मॉनिटर पर प्रतीक्षा करने वाले अन्य थ्रेड्स को सूचित करने का प्रयास किया है।

इस उत्तर को स्पष्ट करने के लिए, थ्रेड पर प्रतीक्षा करने के लिए यह कॉल IllegalMonitorStateException को फेंकता है, एक सिंक्रनाइज़ ब्लॉक के भीतर से कॉल किए जाने के बावजूद:


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

    @Test
    public void testRun() {
        ThreadWorker worker = new ThreadWorker();
        System.out.println ("Starting worker");
        worker.start();
        System.out.println ("Worker started - telling it to wait");
        try {
            synchronized (lock) {
                worker.wait();
            }
        } catch (InterruptedException e1) {
            String msg = "InterruptedException: [" + e1.getLocalizedMessage() + "]";
            System.out.println (msg);
            e1.printStackTrace();
            System.out.flush();
        }
        System.out.println ("Worker done waiting, we're now waiting for it by joining");
        try {
            worker.join();
        } catch (InterruptedException ex) { }

    }

@ सहकर्मी: मुझे लगता है कि आप निष्पादन थ्रेड और ऑब्जेक्ट को भ्रमित कर रहे हैं, जिसका लक्ष्य है wait()
रॉबर्ट मुंटेनू

@ रॉबर्ट - शायद मैं हूं, लेकिन मुझे ऐसा नहीं लगता। यदि आप एक थ्रेड उदाहरण शुरू करते हैं, और फिर इसे प्रतीक्षा करने के लिए कहेंगे, तो आपको एक IllegalMonitorStateException मिलेगा, जिसे मैं वर्णन करने का प्रयास कर रहा था।
CPerkins

क्या आप worker.wait()रेखा के बारे में बात कर रहे हैं ? फिर आपको कार्यकर्ता पर सिंक्रनाइज़ होना चाहिए, ताला पर नहीं।
रॉबर्ट मंटीनू

1

IllegalMonitorStateException से निपटने के लिए, आपको यह सत्यापित करना होगा कि प्रतीक्षा, सूचना और सूचना के सभी चालान तभी हो रहे हैं, जब कॉलिंग थ्रेड उपयुक्त मॉनिटर का मालिक हो। । सबसे सरल समाधान इन कॉलों को सिंक्रनाइज़ किए गए ब्लॉक के अंदर संलग्न करना है। सिंक्रनाइज़ेशन ऑब्जेक्ट जिसे सिंक्रनाइज़ स्टेटमेंट में आमंत्रित किया जाएगा, वह है जिसका मॉनिटर अधिग्रहित किया जाना चाहिए।

मॉनिटर की अवधारणा को समझने के लिए यहां सरल उदाहरण है

public class SimpleMonitorState {

    public static void main(String args[]) throws InterruptedException {

        SimpleMonitorState t = new SimpleMonitorState();
        SimpleRunnable m = new SimpleRunnable(t);
        Thread t1 = new Thread(m);
        t1.start();
        t.call();

    }

    public void call() throws InterruptedException {
        synchronized (this) {
            wait();
            System.out.println("Single by Threads ");
        }
    }

}

class SimpleRunnable implements Runnable {

    SimpleMonitorState t;

    SimpleRunnable(SimpleMonitorState t) {
        this.t = t;
    }

    @Override
    public void run() {

        try {
            // Sleep
            Thread.sleep(10000);
            synchronized (this.t) {
                this.t.notify();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

0

Thread.wait () कॉल एक कोड के अंदर समझ में आता है जो Thread.class ऑब्जेक्ट पर सिंक्रोनाइज़ करता है। मुझे नहीं लगता कि यह वही है जो आपका मतलब है।
तुम पूछो

जब तक इसे अधिसूचित नहीं किया जाएगा, तब तक मैं एक थ्रेड प्रतीक्षा कैसे कर सकता हूं?

आप केवल अपने वर्तमान थ्रेड प्रतीक्षा कर सकते हैं। कोई अन्य धागा केवल धीरे से प्रतीक्षा करने के लिए कहा जा सकता है, अगर यह सहमत है।
यदि आप किसी शर्त का इंतजार करना चाहते हैं, तो आपको एक लॉक ऑब्जेक्ट की आवश्यकता होती है - थ्रेड.क्लास ऑब्जेक्ट एक बहुत बुरा विकल्प है - यह एक सिंगलटन AFAIK है इसलिए इस पर सिंक्रनाइज़ करना (थ्रेड स्थिर तरीकों को छोड़कर) खतरनाक है।
सिंक्रनाइज़ेशन और प्रतीक्षा के लिए विवरण पहले से ही टॉम हॉकिन द्वारा समझाया गया है। java.lang.IllegalMonitorStateExceptionइसका मतलब है कि आप उस वस्तु पर प्रतीक्षा करने की कोशिश कर रहे हैं जिस पर आप सिंक्रनाइज़ नहीं हैं - ऐसा करना अवैध है।


0

यकीन नहीं होता कि इससे किसी और को मदद मिलेगी या नहीं, लेकिन उपयोगकर्ता "टॉम हॉकिन - टैकलिन" के उत्तर में मेरी समस्या को ठीक करने के लिए यह महत्वपूर्ण हिस्सा था:

synchronized (lock) {
    makeWakeupNeeded();
    lock.notifyAll();
}

बस यह तथ्य कि "लॉक" को एक तर्क के रूप में सिंक्रनाइज़ किया गया है () और इसका उपयोग "लॉक" .notifyAll () में भी किया जाता है;

एक बार जब मैंने इसे उन 2 जगहों पर बनाया तो मुझे यह काम कर गया


0

मुझे IllegalMonitorStateExceptionएक थ्रेड को / एक अलग class/ थ्रेड से जागने की कोशिश करते हुए प्राप्त हुआ । में java 8आप उपयोग कर सकते हैं lockनए संगामिति एपीआई की सुविधाओं के बजाय कीsynchronized कार्य करता है।

मैं पहले से ही asynchronousएक में websocket लेनदेन के लिए वस्तुओं का भंडारण कर रहा था WeakHashMap। मेरे मामले में समाधान एक lockवस्तु कोConcurrentHashMapsynchronous उत्तर के लिए संग्रहीत करना भी था । नोट करें condition.await(नहीं).wait )।

बहु सूत्रण को संभालने के लिए मैंने थ्रेड पूलExecutors.newCachedThreadPool() बनाने के लिए उपयोग किया ।


0

जो लोग जावा 7.0 या उससे नीचे के संस्करण का उपयोग कर रहे हैं, वे उस कोड का उल्लेख कर सकते हैं जिसका मैंने यहां उपयोग किया था और यह काम करता है।

public class WaitTest {

    private final Lock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();

    public void waitHere(long waitTime) {
        System.out.println("wait started...");
        lock.lock();
        try {
            condition.await(waitTime, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        lock.unlock();
        System.out.println("wait ends here...");
    }

    public static void main(String[] args) {
        //Your Code
        new WaitTest().waitHere(10);
        //Your Code
    }

}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.