IllegalMonitorStateException ছাড়া জাভাতে অপেক্ষা ও বিজ্ঞপ্তিটি কীভাবে ব্যবহার করবেন?


129

আমার কাছে 2 টি ম্যাট্রিক রয়েছে এবং আমার সেগুলি গুণ করতে হবে এবং তারপরে প্রতিটি ঘরের ফলাফল মুদ্রণ করতে হবে। যত তাড়াতাড়ি একটি ঘর প্রস্তুত হওয়ার সাথে সাথে এটি মুদ্রণ করা দরকার, তবে উদাহরণস্বরূপ আমাকে [0] [0] সেলটি [2] [0] এর আগে প্রিন্ট করতে হবে যদিও [2] [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ব্লক বা সিঙ্ক্রোনাইজড পদ্ধতি ব্যবহার করুন তা সম্পূর্ণ আপনার উপর নির্ভর করে to
বোম্বে

1
@ বেনিবেলা তবে এটি নিশ্চিত হওয়ার জন্য ধীরে ধীরে আশা করা যায় (হুসেনের মূল প্রশ্ন সম্পর্কিত)।
টমাস

64

জাভাতে waitএবং notifyবা notifyAllপদ্ধতিগুলি ব্যবহার করার সময় নিম্নলিখিত বিষয়গুলি অবশ্যই মনে রাখতে হবে:

  1. আপনি যদি আশা করেন যে একাধিক থ্রেড লকের জন্য অপেক্ষা করবে তার notifyAllপরিবর্তে ব্যবহার করুন notify
  2. waitএবং notifyপদ্ধতি একটি সিঙ্ক্রোনাইজ প্রেক্ষাপটে কল করা আবশ্যক । আরও বিস্তারিত ব্যাখ্যার জন্য লিঙ্কটি দেখুন See
  3. সর্বদা wait()পদ্ধতিটিকে একটি লুপে কল করুন কারণ একাধিক থ্রেড যদি কোনও লকের জন্য অপেক্ষা করে থাকে এবং তাদের মধ্যে একটি তালা পেয়ে শর্তটি পুনরায় সেট করে, তবে অন্য থ্রেডগুলি তাদের আবার জাগার অপেক্ষা রাখে কিনা তা দেখার জন্য ঘুম থেকে ওঠার পরে শর্তটি পরীক্ষা করা উচিত বা প্রক্রিয়া শুরু করতে পারেন।
  4. কলিং wait()এবং notify()পদ্ধতির জন্য একই অবজেক্টটি ব্যবহার করুন ; প্রতিটি বস্তুর নিজস্ব লক থাকে তাই wait()বস্তু এ এবং notify()বস্তু বিতে কল করা কোনও অর্থবোধ করে না।

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কল না পাওয়া পর্যন্ত আপনি আপনার কোড চালিয়ে যেতে চান না । এখানে 'সিঙ্ক্রোনাইজ সহায়ক' প্রবেশ করে:

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নীচের এসই প্রশ্নের অন্যান্য বিকল্পগুলি সন্ধান করা যাক :

যদি কেউ সিঙ্ক্রোনাইজড (এটি) ব্যবহার করতে পারে তবে কেন একটি রেন্টেন্টলক ব্যবহার করবেন?

সিঙ্ক্রোনাইজেশন বনাম লক

জাভাতে সিঙ্ক্রোনাইজড (এটি) এড়ান?

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.