जावा के बिना अवैध रूप से प्रतीक्षा और सूचना का उपयोग कैसे करें?


129

मेरे पास 2 मैट्रिसेस हैं और मुझे उन्हें गुणा करना होगा और फिर प्रत्येक सेल के परिणामों को प्रिंट करना होगा। जैसे ही एक सेल तैयार होता है, मुझे इसे प्रिंट करने की आवश्यकता होती है, लेकिन उदाहरण के लिए मुझे सेल से पहले [0] [0] सेल को प्रिंट करना होगा [२] [०] भले ही [२] [०] का परिणाम पहले तैयार हो। । इसलिए मुझे इसे क्रम से प्रिंट करने की आवश्यकता है। इसलिए मेरा विचार प्रिंटर थ्रेड को तब तक इंतजार करना है जब तक यह multiplyThreadसूचित न हो जाए कि सही सेल मुद्रित होने के लिए तैयार है और फिर printerThreadसेल प्रिंट करेगा और प्रतीक्षा करने के लिए वापस जाएगा और इसी तरह ।।

इसलिए मेरे पास यह धागा है जो गुणा करता है:

public void run() 
{
    int countNumOfActions = 0; // How many multiplications have we done
    int maxActions = randomize(); // Maximum number of actions allowed

    for (int i = 0; i < size; i++)
    {       
        result[rowNum][colNum] = result[rowNum][colNum] + row[i] * col[i];
        countNumOfActions++;
        // Reached the number of allowed actions
        if (countNumOfActions >= maxActions)
        {
            countNumOfActions = 0;
            maxActions = randomize();
            yield();
        }   
    }
    isFinished[rowNum][colNum] = true;
    notify();
}

धागा जो प्रत्येक कोशिका के परिणाम को प्रिंट करता है:

public void run()
{
    int j = 0; // Columns counter
    int i = 0; // Rows counter
    System.out.println("The result matrix of the multiplication is:");

    while (i < creator.getmThreads().length)
    {
        synchronized (this)
        {
            try 
            {
                this.wait();
            } 
            catch (InterruptedException e1) 
            {
            }
        }
        if (creator.getmThreads()[i][j].getIsFinished()[i][j] == true)
        {
            if (j < creator.getmThreads()[i].length)
            {
                System.out.print(creator.getResult()[i][j] + " ");
                j++;
            }
            else
            {
                System.out.println();
                j = 0;
                i++;
                System.out.print(creator.getResult()[i][j] + " ");
            }
        }
    }

अब यह मुझे इन अपवादों को फेंकता है:

Exception in thread "Thread-9" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-6" Exception in thread "Thread-4" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at multiplyThread.run(multiplyThread.java:49)
java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-5" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-8" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-7" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-11" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-10" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-12" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at multiplyThread.run(multiplyThread.java:49)

लाइन 49 में multiplyThread "सूचित ()" है .. मुझे लगता है कि मुझे अलग से सिंक्रनाइज़ का उपयोग करने की आवश्यकता है लेकिन मुझे यकीन नहीं है कि कैसे।

अगर कोई इस कोड को काम करने में मदद कर सकता है तो मैं वास्तव में इसकी सराहना करूंगा।

जवाबों:


215

सूचना () को कॉल करने में सक्षम होने के लिए आपको उसी ऑब्जेक्ट पर सिंक्रनाइज़ करने की आवश्यकता है।

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

/* different thread / object */
synchronized (someObject) {
    someObject.notify();
}

29
while(!JobCompleted);विकल्प आम तौर पर एक बुरा विचार है क्योंकि यह 100% लगातार एक ही चर जाँच पर अपने CPU ऊपर बांध (देखें है यहाँ )
मैट लियोन्स

5
while(!JobCompleted) Thread.sleep(5); वह समस्या नहीं है
बेनीबेला

15
यह अभी भी कुछ पूरी तरह से अलग होने की समस्या है। मतदान (बार-बार जाँच करना कि कुछ शर्त पूरी हो गई है, यानी आप क्या कर रहे हैं) आम तौर पर अधिसूचित होने पर कम पसंद किया जाता है यदि उक्त स्थिति बदली जाती है (यानी मैंने उत्तर में उल्लिखित किया है)।
बॉम्बे

3
@huseyintugrulbuyukisik आप कॉल कर सकते हैं waitजब भी वर्तमान थ्रेड में ऑब्जेक्ट पर लॉक होता waitहै जिस पर कॉल किया जाता है। चाहे आप एक synchronizedब्लॉक का उपयोग करें या एक सिंक्रनाइज़ विधि पूरी तरह से आप पर निर्भर है।
बॉम्बे

1
@ बेनीबेला लेकिन यह सुनिश्चित करने के लिए धीमा होने की उम्मीद की जा सकती है (हुसैन के मूल प्रश्न के बारे में)।
थॉमस

64

का उपयोग करते समय waitऔर notifyया notifyAllजावा में तरीकों निम्नलिखित बातें याद रखा जाना चाहिए:

  1. notifyAllइसके बजाय का उपयोग करें notifyयदि आप उम्मीद करते हैं कि एक से अधिक थ्रेड लॉक का इंतजार कर रहे होंगे।
  2. waitऔर notifyतरीकों एक तुल्यकालन संदर्भ में बुलाया जाना चाहिए । अधिक विस्तृत विवरण के लिए लिंक देखें।
  3. हमेशा एक wait()विधि को लूप में बुलाएं क्योंकि यदि कई थ्रेड्स लॉक की प्रतीक्षा कर रहे हैं और उनमें से एक को लॉक मिला है और स्थिति को रीसेट कर देता है, तो दूसरे थ्रेड्स को स्थिति को जांचने की आवश्यकता होती है क्योंकि वे जागते हैं कि क्या उन्हें फिर से इंतजार करने की आवश्यकता है या नहीं प्रसंस्करण शुरू कर सकते हैं।
  4. कॉलिंग wait()और notify()विधि के लिए एक ही वस्तु का उपयोग करें ; हर ऑब्जेक्ट का अपना लॉक होता है इसलिए wait()ऑब्जेक्ट A और notify()ऑब्जेक्ट B पर कॉल करने का कोई मतलब नहीं होगा।

21

क्या आपको यह सब करने की आवश्यकता है? मैं सोच रहा हूं कि आपके मैट्रेस कितने बड़े हैं, और क्या एक थ्रेड प्रिंट होने का कोई फायदा है जबकि दूसरे का गुणा है।

शायद अपेक्षाकृत जटिल थ्रेडिंग कार्य करने से पहले इस समय को मापने के लायक होगा?

यदि आपको इसे थ्रेड करने की आवश्यकता है, तो मैं कोशिकाओं का गुणन करने के लिए 'एन' थ्रेड्स बनाऊंगा (शायद 'एन' आपके लिए उपलब्ध कोर की संख्या है), और फिर एक्सेलसॉर सर्विस और फ्यूचर तंत्र का उपयोग एक साथ कई गुणा निकालने के लिए करें। ।

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


1
+1 @ मुझे लगता है कि आपको java.util.concurrent पैकेज पर एक नज़र डालनी चाहिए, जैसा कि ब्रायन ने बताया है।
एटोरस

1
+1 और इस पुस्तक को भी देखें जो आपको प्रतीक्षा () और सूचित ( jcip.net
Chii

14

चलो कहते हैं कि तुम नामित कुछ वर्ग के साथ 'ब्लैक बॉक्स' अनुप्रयोग है BlackBoxClassविधि है doSomething();

इसके अलावा, आपके पास पर्यवेक्षक या श्रोता का नाम onResponse(String resp)है जिसे BlackBoxClassअज्ञात समय के बाद बुलाया जाएगा ।

प्रवाह सरल है:

private String mResponse = null; 
 ...
BlackBoxClass bbc = new BlackBoxClass();
   bbc.doSomething();
...
@override
public void onResponse(String resp){        
      mResponse = resp;       
}

हम कहते हैं कि हम नहीं जानते कि क्या हो रहा है BlackBoxClassऔर हमें जवाब कब मिलना चाहिए लेकिन जब तक आपको जवाब नहीं मिलता है या दूसरे शब्द onResponseकॉल नहीं आते तब तक आप अपना कोड जारी नहीं रखना चाहते । यहां per सिंक्रोनाइज़ हेल्पर ’दर्ज करता है:

public class SyncronizeObj {
public void doWait(long l){
    synchronized(this){
        try {
            this.wait(l);
        } catch(InterruptedException e) {
        }
    }
}

public void doNotify() {
    synchronized(this) {
        this.notify();
    }
}

public void doWait() {
    synchronized(this){
        try {
            this.wait();
        } catch(InterruptedException e) {
        }
    }
}
}

अब हम जो चाहें लागू कर सकते हैं:

public class Demo {

private String mResponse = null; 
 ...
SyncronizeObj sync = new SyncronizeObj();

public void impl(){

BlackBoxClass bbc = new BlackBoxClass();
   bbc.doSomething();

   if(mResponse == null){
      sync.doWait();
    }

/** at this momoent you sure that you got response from  BlackBoxClass because
  onResponse method released your 'wait'. In other cases if you don't want wait too      
  long (for example wait data from socket) you can use doWait(time) 
*/ 
...

}


@override
public void onResponse(String resp){        
      mResponse = resp;
      sync.doNotify();       
   }

}

7

आप केवल उन वस्तुओं पर सूचना को कॉल कर सकते हैं, जहाँ आप उनके मॉनिटर हैं। इसलिए आपको ऐसा कुछ चाहिए

synchronized(threadObject)
{
   threadObject.notify();
}

6

notify() के रूप में अच्छी तरह से सिंक्रनाइज़ करने की आवश्यकता है


3

मैं सही सरल उदाहरण आप उपयोग के लिए सही रास्ता दिखाता हूँ waitऔर notifyजावा में। इसलिए मैं थ्रेडा और थ्रेडबी नाम की दो क्लास बनाऊंगा । थ्रेडा थ्रेडबी कहेगा।

public class ThreadA {
    public static void main(String[] args){
        ThreadB b = new ThreadB();//<----Create Instance for seconde class
        b.start();//<--------------------Launch thread

        synchronized(b){
            try{
                System.out.println("Waiting for b to complete...");
                b.wait();//<-------------WAIT until the finish thread for class B finish
            }catch(InterruptedException e){
                e.printStackTrace();
            }

            System.out.println("Total is: " + b.total);
        }
    }
} 

और क्लास थ्रेडबी के लिए:

class ThreadB extends Thread{
    int total;
    @Override
    public void run(){
        synchronized(this){
            for(int i=0; i<100 ; i++){
                total += i;
            }
            notify();//<----------------Notify the class wich wait until my    finish 
//and tell that I'm finish
            }
        }
    }

3

यदि आप धागे को वैकल्पिक रूप से निष्पादित करना चाहते हैं, तो सरल उपयोग करें: -

public class MyThread {
    public static void main(String[] args) {
        final Object lock = new Object();
        new Thread(() -> {
            try {
                synchronized (lock) {
                    for (int i = 0; i <= 5; i++) {
                        System.out.println(Thread.currentThread().getName() + ":" + "A");
                        lock.notify();
                        lock.wait();
                    }
                }
            } catch (Exception e) {}
        }, "T1").start();

        new Thread(() -> {
            try {
                synchronized (lock) {
                    for (int i = 0; i <= 5; i++) {
                        System.out.println(Thread.currentThread().getName() + ":" + "B");
                        lock.notify();
                        lock.wait();
                    }
                }
            } catch (Exception e) {}
        }, "T2").start();
    }
}

प्रतिक्रिया: -

T1:A
T2:B
T1:A
T2:B
T1:A
T2:B
T1:A
T2:B
T1:A
T2:B
T1:A
T2:B

जब मैं 4 ऑपरेशन को समकालिक तरीके से करने के लिए काम करता हूं तो यह कैसे काम करता है?
साक्षी अग्रवाल

2

वेटिंग ऑब्जेक्ट्स के निष्पादन को फिर से शुरू करने के लिए हम नोटिफ़िकेशन को कॉल कर सकते हैं

public synchronized void guardedJoy() {
    // This guard only loops once for each special event, which may not
    // be the event we're waiting for.
    while(!joy) {
        try {
            wait();
        } catch (InterruptedException e) {}
    }
    System.out.println("Joy and efficiency have been achieved!");
}

एक ही कक्षा के किसी अन्य ऑब्जेक्ट पर सूचित करके इसे फिर से शुरू करें

public synchronized notifyJoy() {
    joy = true;
    notifyAll();
}

0

इस विशेष समस्या के लिए, अपने विभिन्न परिणामों को चरों में संग्रहीत क्यों नहीं किया जाए और फिर जब आपके धागे के अंतिम भाग को संसाधित किया जाता है तो आप जो भी प्रारूप चाहते हैं, उसमें प्रिंट कर सकते हैं। यह विशेष रूप से उपयोगी है यदि आप अन्य परियोजनाओं में अपने कार्य इतिहास का उपयोग करने वाले हैं।


0

यह निर्माता-उपभोक्ता पैटर्न के लिए एक स्थिति की तरह दिखता है। यदि आप जावा 5 या ऊपर का उपयोग कर रहे हैं, तो आप अवरुद्ध कतार (java.util.concurrent.BlockingQueue) का उपयोग करने पर विचार कर सकते हैं और थ्रेड समन्वय कार्य को अंतर्निहित ढांचे / एपीआई कार्यान्वयन पर छोड़ सकते हैं। जावा 5 से उदाहरण देखें: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/BlockingQueue.html या जावा 7 (एक ही उदाहरण): http: // डॉक्स। oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html


0

जब आप wait()विधि का उपयोग करके कॉल करते हैं तो आपने अपने कोड ब्लॉक को ठीक से संरक्षित किया है synchronized(this)

लेकिन जब आप notify()पहरेदार ब्लॉक का उपयोग किए बिना विधि कॉल करते हैं तो आपने एहतियात नहीं लिया है : synchronized(this)याsynchronized(someObject)

आप पर ओरेकल प्रलेखन पृष्ठ का संदर्भ लें तो वस्तु वर्ग है, जो होता है wait(), notify(), notifyAll()तरीकों, आप एहतियात नीचे इन तीनों विधियों में देख सकते हैं

इस विधि को केवल एक थ्रेड द्वारा बुलाया जाना चाहिए जो इस ऑब्जेक्ट के मॉनिटर का मालिक है

पिछले 7 वर्षों में कई चीजों को बदला गया है और synchronizedएसई प्रश्नों के नीचे अन्य विकल्पों पर नजर डालते हैं :

यदि एक सिंक्रनाइज़ (यह) का उपयोग कर सकता है तो एक रेन्ट्रेंटलॉक का उपयोग क्यों करें?

सिंक्रनाइज़ेशन बनाम लॉक

जावा में सिंक्रनाइज़ (यह) से बचें?

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