জাভা: সর্বদা আবার বিজ্ঞপ্তি () বনাম notifyAll ()


377

যদি "মধ্যে পার্থক্য জন্য এক Google এর notify()এবং notifyAll()" তাহলে ব্যাখ্যা অনেকটা পপ আপ করবে (পৃথক্ javadoc অনুচ্ছেদ রেখে)। এটা সব থ্রেড অপেক্ষা সংখ্যা জাগানো হচ্ছে নিচে boils: এক notify()এবং সব notifyAll()

তবে (যদি আমি এই পদ্ধতির মধ্যে পার্থক্যটি সঠিকভাবে বুঝতে পারি), কেবলমাত্র একটি থ্রেড সর্বদা আরও মনিটর অধিগ্রহণের জন্য নির্বাচিত হয়; প্রথম ক্ষেত্রে ভিএম দ্বারা নির্বাচিত একটি, দ্বিতীয় ক্ষেত্রে সিস্টেম থ্রেড শিডিয়ুলার দ্বারা নির্বাচিত একটি। তাদের উভয়ের জন্য সঠিক নির্বাচনের পদ্ধতি (সাধারণ ক্ষেত্রে) প্রোগ্রামারটির জানা নেই।

নোটিফাই () এবং নোটিফাইএল () এর মধ্যে তখন কী কার্যকর পার্থক্য ? আমি কিছু অনুপস্থিত করছি?


6
একযোগে ব্যবহারের জন্য দরকারী লাইব্রেরিগুলি সম্মতিযুক্ত লাইব্রেরিতে রয়েছে। আমি প্রস্তাব করি এগুলি প্রায় প্রতিটি ক্ষেত্রেই আরও ভাল পছন্দ। কনক্যুরেন্সির গ্রন্থাগারের পূর্ব তারিখ জাভা 5.0 (যার মধ্যে তারা 2004 এ স্ট্যান্ডার্ড হিসাবে যুক্ত হয়েছিল)
পিটার লরে

4
আমি পিটারের সাথে একমত নই। সম্মতিযুক্ত গ্রন্থাগারটি জাভাতে প্রয়োগ করা হয়েছে, এবং প্রতিবার যখন আপনি লক (), আনলক () ইত্যাদি কল করেন তখন প্রচুর জাভা কোড কার্যকর করা হয় synchronizedcertain বরং বিরল ব্যবহারের ক্ষেত্রে।
আলেকজান্ডার রায়ঝভ

2
মূল ভুল বোঝাবুঝি এটি হ'ল : ... আরও মনিটর অধিগ্রহণের জন্য সর্বদা কেবল একটি থ্রেড নির্বাচন করা হয়; প্রথম ক্ষেত্রে ভিএম দ্বারা নির্বাচিত একটি, দ্বিতীয় ক্ষেত্রে সিস্টেম থ্রেড শিডিয়ুলার দ্বারা নির্বাচিত একটি। জড়িত থাকা যে মূলত একই রকম। বর্ণিত আচরণটি সঠিক হলেও, যা অনুপস্থিত তা notifyAll()হ'ল, প্রথম ধরণের পরে অন্য থ্রেড জেগে থাকবে এবং মনিটরটি একের পর এক অর্জন করবে। ইন notifyকেস, অন্যান্য থ্রেড কেউই এমনকি woken করা হয়। কাজেই তারা খুব আলাদা!
BeeOnRope

1) যদি অনেক থ্রেড কোনও অবজেক্টের জন্য অপেক্ষা করে থাকে এবং বিজ্ঞপ্তি () কেবলমাত্র একবার তাকে বলা হয় object অপেক্ষমান থ্রেডগুলির একটি বাদ দিয়ে কি বাকি থ্রেড চিরকাল অপেক্ষা করে? 2) যদি বিজ্ঞপ্তি () ব্যবহার করা হয় তবে কেবলমাত্র একটি অপেক্ষা অপেক্ষার থ্রেড কার্যকর করা শুরু করে। যদি নোটিফিয়াল () ব্যবহার করা হয় তবে সমস্ত অপেক্ষার থ্রেডকে অবহিত করা হয় তবে তাদের মধ্যে কেবল একটিই কার্যকর করতে শুরু করে, তবে এখানে বিজ্ঞপ্তি () ব্যবহার কী?
চেতন গওদা

@ চেটানগৌদা বনাম সমস্ত থ্রেডকে অবহিত করা ঠিক ঠিক একটি স্বেচ্ছাচারিত থ্রেডের মধ্যে উল্লেখযোগ্য পার্থক্য রয়েছে যতক্ষণ না আপাতদৃষ্টিতে সূক্ষ্ম তবে গুরুত্বপূর্ণ তাত্পর্য আমাদেরকে আঘাত করে you / সংকেত। সকলকে অবহিত করে, সমস্ত থ্রেডগুলি একের পর এক কোনও ক্রমাগত কোনও বিজ্ঞপ্তি ছাড়াই কার্যকর করা হবে এবং শেষ করা হবে - এখানে আমাদের থ্রেডগুলি বলা উচিত blockedএবং তা নয় waitinghen যখন blockedঅন্য থ্রেডটি syncব্লকের অভ্যন্তরে না থাকে ততক্ষণ তার এক্সিকিউট সাময়িকভাবে স্থগিত করা হয় ।
ব্যবহারকারী 104309

উত্তর:


248

তবে (যদি আমি এই পদ্ধতির মধ্যে পার্থক্যটি সঠিকভাবে বুঝতে পারি), কেবলমাত্র একটি থ্রেড সর্বদা আরও মনিটর অধিগ্রহণের জন্য নির্বাচিত হয়।

এটি সঠিক নয়। o.notifyAll()উঠছে সব থ্রেড যে অবরুদ্ধ করছে o.wait()কল। থ্রেডগুলিকে কেবল o.wait()একের পর এক থেকে ফেরার অনুমতি দেওয়া হয়েছে তবে তারা প্রতিটি তার পালা পাবে।


সহজ কথায় বলতে গেলে এটি আপনার থ্রেডগুলি কেন বিজ্ঞপ্তির অপেক্ষায় রয়েছে তার উপর নির্ভর করে। আপনি কি অপেক্ষমান থ্রেডগুলির মধ্যে একটিটি বলতে চান যে কিছু ঘটেছে, বা আপনি একই সাথে সমস্ত কিছু বলতে চান?

কিছু ক্ষেত্রে, সমস্ত অপেক্ষার থ্রেডগুলি অপেক্ষা শেষ হওয়ার পরে দরকারী পদক্ষেপ নিতে পারে। একটি উদাহরণ থ্রেডগুলির একটি সেট হবে যা কোনও নির্দিষ্ট কাজ শেষ হওয়ার জন্য অপেক্ষা করছে; কাজটি শেষ হয়ে গেলে, সমস্ত অপেক্ষার থ্রেডগুলি তাদের ব্যবসার সাথে চালিয়ে যেতে পারে। এই ক্ষেত্রে আপনি একই সময়ে সমস্ত অপেক্ষার থ্রেড জাগ্রত করতে বিজ্ঞপ্তি (সমস্ত) ব্যবহার করবেন ।

অন্য কেস, উদাহরণস্বরূপ পারস্পরিক একচেটিয়া লক করা, কেবলমাত্র অপেক্ষমান থ্রেডগুলির মধ্যে একটি সূচিত হওয়ার পরে দরকারী কিছু করতে পারে (এই ক্ষেত্রে লকটি অর্জন করে)। এই জাতীয় ক্ষেত্রে, আপনি বরং বিজ্ঞপ্তি () ব্যবহার করবেন । যথাযথভাবে প্রয়োগ করা হয়েছে, আপনি এই পরিস্থিতিতেও notifyAll () ব্যবহার করতে পারেন তবে আপনি অযথা থ্রেডগুলি জাগিয়ে তুলবেন যা কোনওভাবেই করতে পারে না।


অনেক ক্ষেত্রে শর্তের অপেক্ষার কোডটি একটি লুপ হিসাবে লেখা হবে:

synchronized(o) {
    while (! IsConditionTrue()) {
        o.wait();
    }
    DoSomethingThatOnlyMakesSenseWhenConditionIsTrue_and_MaybeMakeConditionFalseAgain();
}

এইভাবে, যদি কোনও o.notifyAll()কল একাধিক অপেক্ষার থ্রেড জাগ্রত করে এবং মেকস থেকে ফিরে আসা প্রথমটি o.wait()শর্তটিকে মিথ্যা অবস্থায় ফেলে দেয়, তবে অন্য থ্রেডগুলি জাগ্রত হয়েছিল সেগুলি অপেক্ষায় ফিরে যাবে।


29
আপনি যদি কেবল একটি থ্রেডকে অবহিত করেন তবে একাধিক কোনও অবজেক্টের জন্য অপেক্ষা করছেন, ভিএম কীভাবে কোনটি অবহিত করবেন তা নির্ধারণ করবেন?
উভচর

6
আমি জাভা স্পেস সম্পর্কে নিশ্চিত করে বলতে পারি না, তবে সাধারণত আপনার এই জাতীয় বিবরণ সম্পর্কে অনুমান করা এড়ানো উচিত। আমি মনে করি আপনি অনুমান করতে পারেন যে ভিএম এটি বুদ্ধিমান এবং বেশিরভাগ ন্যায্য উপায়ে করবে though
লিডম্যান

15
লিডম্যান মারাত্মকভাবে ভুল, জাভা স্পেসিফিকেশন স্পষ্টভাবে জানিয়েছে যে বিজ্ঞপ্তি () ন্যায্য হওয়ার নিশ্চয়তা নেই। অর্থাত্ প্রত্যেকটি কলটি একই সূত্রটি আবার জাগাতে পারে (মনিটরে থ্রেডের সারিটি শেষ বা ফিফোর নয়)। তবে শিডিয়ুলারটি ন্যায্য হওয়ার গ্যারান্টিযুক্ত। যে কারণে বেশিরভাগ ক্ষেত্রে যেখানে আপনার 2 টিরও বেশি থ্রেড রয়েছে আপনার সমস্ত বিজ্ঞপ্তি পছন্দ করা উচিত।
ইয়ান টিএম

45
@ ইয়ানটিএম আমি সবই গঠনমূলক সমালোচনার পক্ষে, তবে আমি মনে করি আপনার সুরটি কিছুটা অন্যায়। আমি স্পষ্টভাবে বলেছি "নির্দিষ্ট করে বলতে পারি না" এবং "আমার মনে হয়"। খুব সহজ, আপনি কি সাত বছর আগে এমন কিছু লিখেছিলেন যা 100% সঠিক নয়?
লিডম্যান

10
সমস্যাটি হ'ল এটি গৃহীত উত্তর, এটি ব্যক্তিগত গর্বের প্রশ্ন নয়। আপনি যদি জানেন যে আপনি এখন ভুল ছিলেন, দয়া করে এটি বলার জন্য আপনার উত্তরটি সম্পাদনা করুন এবং নীচে xagyg শিক্ষাগত এবং সঠিক উত্তরটি নির্দেশ করুন।
ইয়ান টিএম 21

330

স্পষ্টতই, notifyওয়েট সেটে একটি থ্রেড জেগে (কোনও), notifyAllওয়েটিং সেটে সমস্ত থ্রেড জাগিয়ে তোলে। নিম্নলিখিত আলোচনাটি যে কোনও সন্দেহ পরিষ্কার করতে হবে। notifyAllবেশিরভাগ সময় ব্যবহার করা উচিত। কোনটি ব্যবহার করবেন তা আপনি যদি নিশ্চিত না হন তবে ব্যবহার করুন notifyAlllease অনুগ্রহ করে নিম্নলিখিতটি দেখুন।

খুব সাবধানে পড়ুন এবং বুঝতে পারেন। আপনার কোনও প্রশ্ন থাকলে দয়া করে আমাকে একটি ইমেল প্রেরণ করুন।

প্রযোজক / ভোক্তার দিকে তাকান (ধারণা দুটি পদ্ধতি সহ একটি প্রযোজকগণের শ্রেণি)। এটি ভেঙে গেছে (কারণ এটি ব্যবহার করে notify) - হ্যাঁ এটি কাজ করে - এমনকি বেশিরভাগ সময়, তবে এটি অচলাবস্থার কারণও হতে পারে - কেন আমরা তা দেখব:

public synchronized void put(Object o) {
    while (buf.size()==MAX_SIZE) {
        wait(); // called if the buffer is full (try/catch removed for brevity)
    }
    buf.add(o);
    notify(); // called in case there are any getters or putters waiting
}

public synchronized Object get() {
    // Y: this is where C2 tries to acquire the lock (i.e. at the beginning of the method)
    while (buf.size()==0) {
        wait(); // called if the buffer is empty (try/catch removed for brevity)
        // X: this is where C1 tries to re-acquire the lock (see below)
    }
    Object o = buf.remove(0);
    notify(); // called if there are any getters or putters waiting
    return o;
}

প্রথমত,

আমরা কেন অপেক্ষাটি ঘিরে কিছুক্ষণ লুপের প্রয়োজন?

আমরা whileযদি এই পরিস্থিতিটি পাই তবে আমাদের একটি লুপ দরকার :

গ্রাহক 1 (সি 1) সিঙ্ক্রোনাইজড ব্লকে প্রবেশ করুন এবং বাফারটি খালি রয়েছে, সুতরাং সি 1 ওয়েটে সেট ( waitকলের মাধ্যমে ) স্থাপন করা হবে । গ্রাহক 2 (সি 2) সিঙ্ক্রোনাইজড পদ্ধতিতে (উপরে Y বিন্দুতে) প্রবেশ করতে চলেছে, তবে প্রযোজক পি 1 একটি বস্তুকে বাফারে রাখে এবং পরবর্তীকালে কল দেয় notify। একমাত্র অপেক্ষার থ্রেডটি সি 1, সুতরাং এটি জেগে উঠেছে এবং এখন এক্স পয়েন্টে (উপরে) অবজেক্ট লকটি পুনরায় অর্জন করার চেষ্টা করছে।

এখন সি 1 এবং সি 2 সিঙ্ক্রোনাইজেশন লকটি অর্জন করার চেষ্টা করছে। তাদের মধ্যে একটি (নিরপেক্ষতান্ত্রিকভাবে) নির্বাচিত হয় এবং পদ্ধতিতে প্রবেশ করে, অন্যটি অবরুদ্ধ (অপেক্ষায় নয় - তবে অবরুদ্ধ, পদ্ধতিতে লকটি অর্জনের চেষ্টা করছেন)। ধরা যাক সি 2 প্রথমে লক পায়। সি 1 এখনও ব্লক করছে (এক্স এ লকটি অর্জনের চেষ্টা করছে)। সি 2 পদ্ধতিটি সম্পূর্ণ করে এবং লকটি প্রকাশ করে। এখন, সি 1 লকটি অর্জন করে। অনুমান করুন কী, ভাগ্যবান আমাদের একটি whileলুপ রয়েছে, কারণ, সি 1 লুপ চেক (গার্ড) সম্পাদন করে এবং বাফার থেকে অ-অস্তিত্বের উপাদান অপসারণ থেকে বিরত থাকে (সি 2 ইতিমধ্যে এটি পেয়েছে!)। যদি আমাদের কাছে না থাকে while, আমরা IndexArrayOutOfBoundsExceptionসি 1 হিসাবে বাফার থেকে প্রথম উপাদানটি সরিয়ে দেওয়ার চেষ্টা করব!

এখন,

ঠিক আছে, এখন কেন আমাদের সমস্ত বিজ্ঞপ্তি দরকার?

উপরের প্রযোজক / গ্রাহক উদাহরণে দেখে মনে হচ্ছে আমরা দূরে সরে যেতে পারি notify। এটি এইভাবে মনে হচ্ছে, কারণ আমরা প্রমাণ করতে পারি যে প্রযোজক এবং গ্রাহকের জন্য অপেক্ষা লুপের প্রহরীগুলি পরস্পর একচেটিয়া। এটির মতো দেখে মনে হচ্ছে যে putপদ্ধতিটির পাশাপাশি পদ্ধতিতেও আমাদের কাছে কোনও থ্রেড অপেক্ষা করতে পারে না get, কারণ এটি সত্য হওয়ার জন্য নিম্নলিখিতটি সত্য হতে হবে:

buf.size() == 0 AND buf.size() == MAX_SIZE (ধরুন MAX_SIZE 0 নয়)

যাইহোক, এটি যথেষ্ট ভাল নয়, আমাদের ব্যবহারের প্রয়োজন notifyAll। দেখা যাক কেন ...

ধরুন আমাদের কাছে সাইজের 1 বাফার রয়েছে (উদাহরণটিকে অনুসরণ করা সহজ করে তুলতে)। নিম্নলিখিত পদক্ষেপগুলি আমাদের অচলাবস্থার দিকে নিয়ে যায়। নোট করুন যে কোনও সময় কোনও থ্রেড নোটিফিকেশনের সাথে জাগ্রত হয়, এটি জেভিএম দ্বারা অ-নিরপেক্ষভাবে নির্বাচন করা যেতে পারে - এটি কোনও অপেক্ষার থ্রেড জাগ্রত হতে পারে। আরও মনে রাখবেন যে যখন একাধিক থ্রেড কোনও পদ্ধতিতে প্রবেশের পথে বাধা দিচ্ছে (যেমন লক অর্জনের চেষ্টা করছে) তখন অধিগ্রহণের ক্রমটি হ'ল অ-নিরোধক হতে পারে। এটিও মনে রাখবেন যে থ্রেড কেবল যে কোনও একটি সময়ে একটি পদ্ধতিতে থাকতে পারে - সিঙ্ক্রোনাইজড পদ্ধতিগুলি ক্লাসে যে কোনও (সিঙ্ক্রোনাইজড) পদ্ধতিতে কেবল একটি থ্রেড কার্যকর করতে দেয় (অর্থাত লকটি ধারণ করে)। নিম্নলিখিত ইভেন্টগুলির ক্রম যদি ঘটে থাকে - অচলাবস্থার ফলাফল:

পদক্ষেপ 1:
- পি 1 বাফারে 1 টি রাখে

পদক্ষেপ 2:
- পি 2 প্রচেষ্টা put- চেক অপেক্ষার লুপ - ইতিমধ্যে একটি চর - অপেক্ষা করছে its

পদক্ষেপ 3:
- পি 3 প্রচেষ্টা put- চেক অপেক্ষার লুপ - ইতিমধ্যে একটি চর - অপেক্ষা করে its

ধাপ 4:
- গ 1 প্রচেষ্টা 1 গৃহস্থালির কাজ পেতে
প্রবেশের উপর ব্লক - 1 গৃহস্থালির কাজ পেতে C2 এ প্রচেষ্টা - getপদ্ধতি
প্রবেশের উপর ব্লক - 1 গৃহস্থালির কাজ পেতে C3 এ প্রচেষ্টা - getপদ্ধতি

পদক্ষেপ 5:
- সি 1 getপদ্ধতিটি সম্পাদন করছে - গৃহস্থালীর কল পেয়েছে, কল পেয়েছে notify, প্রস্থান করবে
- notifyজাগ্রত P2
- BUT, C2 পদ্ধতিতে প্রবেশ করে P2 করার আগে (পি 2 অবশ্যই লকটি পুনঃব্যবহার করতে হবে), সুতরাং putপদ্ধতিতে প্রবেশের জন্য পি 2 ব্লক
- সি 2 চেকগুলি অপেক্ষা লুপ, আর বাফারে আর অক্ষর নয়, তাই অপেক্ষা করে
- সি 3 পরে সি 3 পদ্ধতিতে প্রবেশ করে তবে পি 2 এর আগে চেকগুলি অপেক্ষা লুপ, বাফারে আর অক্ষর নেই, তাই অপেক্ষা করে

পদক্ষেপ 6:
- এখন: পি 3, সি 2, এবং সি 3 অপেক্ষা করছে!
- অবশেষে পি 2 লকটি অর্জন করে, বাফারে একটি চর রাখে, কলকে বিজ্ঞপ্তি দেয়, পদ্ধতি থেকে বেরিয়ে আসে

পদক্ষেপ 7:
- পি 2 এর বিজ্ঞপ্তিটি পি 3 জাগায় (মনে রাখবেন যে কোনও থ্রেড জাগানো যায়)
- পি 3 অপেক্ষা লুপের শর্তটি পরীক্ষা করে, বাফারে ইতিমধ্যে একটি চর রয়েছে, তাই অপেক্ষা করে।
- কল করার জন্য আরও তিনটি থ্রেড নেই এবং তিনটি স্থায়ীভাবে চাকরিপ্রাপ্ত!

সমাধান: প্রযোজক / ভোক্তা কোড (উপরে) notifyদিয়ে প্রতিস্থাপন করুন notifyAll


1
ফিনউইউ - পি 3 কে অবশ্যই শর্তটি আবার চেক করতে হবে কারণ notifyকারণগুলির জন্য P3 (এই উদাহরণে নির্বাচিত থ্রেড) অপেক্ষা করছিল এমন বিন্দু থেকে এগিয়ে যেতে (অর্থাত whileলুপের মধ্যে)। অন্যান্য উদাহরণ রয়েছে যা অচলাবস্থা সৃষ্টি করে না, তবে এই ক্ষেত্রে notifyডেডলক-মুক্ত কোডের গ্যারান্টি দেয় না। ব্যবহার notifyAllকরে।
xagyg

4
@ মার্কাস খুব কাছাকাছি বিজ্ঞপ্তি সমস্ত দিয়ে, প্রতিটি থ্রেডটি লকটি পুনরুদ্ধার করবে (একবারে একটি), তবে নোট করুন যে একটি থ্রেড লকটি পুনরায় অর্জন করার পরে এবং পদ্ধতিটি কার্যকর করে (এবং তারপরে বেরিয়েছে) ... পরবর্তী থ্রেডটি লকটিকে পুনঃপ্রকাশ করে, "যখন" পরীক্ষা করে এবং "অপেক্ষা" - এ ফিরে যাবে (শর্তটি অবশ্যই কী তার উপর নির্ভর করে)। সুতরাং, বিজ্ঞপ্তিটি একটি থ্রেড জাগায় - আপনি সঠিকভাবে লিখেছেন। notifyAll সমস্ত থ্রেড জাগ্রত করে এবং প্রতিটি থ্রেড একবারে লকটি পুনরায় জিজ্ঞাসা করে - "সময়" এর শর্তটি পরীক্ষা করে এবং হয় পদ্ধতিটি কার্যকর করে অথবা "অপেক্ষা" করে আবার।
xagyg

1
@ অ্যাকজিগ, আপনি এমন একটি দৃশ্যের কথা বলছেন যেখানে প্রতিটি প্রযোজকের কাছে কেবলমাত্র একটি একক চর রাখা যায়? যদি তা হয় তবে আপনার উদাহরণটি সঠিক তবে আইএমও খুব আকর্ষণীয় নয়। আমি প্রস্তাবিত অতিরিক্ত পদক্ষেপের সাহায্যে আপনি একই সিস্টেমটিকে অচল করতে পারেন, তবে সীমাহীন পরিমাণ ইনপুট দিয়ে - যা এই জাতীয় নিদর্শনগুলি সাধারণত বাস্তবে ব্যবহৃত হচ্ছে।
ইরান

3
@ কোডডেবার্সভার আপনি জিজ্ঞাসা করেছেন: "নোটিফাইআল () কে কল করার সময় একই সাথে একাধিক অপেক্ষার থ্রেড (যখন) শর্তটি পরীক্ষা করা হবে .. এবং তাই সম্ভাবনা আছে যে কিছুক্ষণ আগে সন্তুষ্ট হওয়ার আগে, 2 টি থ্রেড ইতিমধ্যে এর বাইরে বেরিয়ে গেছে, কারণ ব্যতিক্রম? না, এটি সম্ভব নয়, যেহেতু একাধিক থ্রেড জেগে উঠবে, তারা একই সাথে কিছুক্ষণ শর্তটি পরীক্ষা করতে পারে না। কোড বিভাগে পুনরায় প্রবেশ করতে এবং কিছুক্ষণ পুনরায় পরীক্ষা করতে পারার আগে তাদের প্রত্যেককে লকটি পুনরায় অর্জনের (তাত্ক্ষণিকভাবে তাত্ক্ষণিকর পরে) পুনরায় অর্জন করতে হবে। অতএব, একবারে এক।
xagyg

4
@ এক্সজিগ সুন্দর উদাহরণ। এটি মূল প্রশ্ন থেকে বিরত রয়েছে; শুধু আলোচনার জন্য অচলাবস্থাটি একটি নকশার সমস্যা ইমো (আমি ভুল হলে আমাকে সংশোধন করুন)। কারন আপনার কাছে একটি লক ভাগ করে রেখেছেন এবং রেখেছেন উভয়ই ভাগ করেছেন। এবং জেভিএম লক এবং ভাইস শ্লোকটি প্রকাশের পরে কল কল করতে যথেষ্ট স্মার্ট নয়। মৃত লকটি ঘটে কারণ পুট আরেকটি পুটকে জাগায়, যা () থাকার কারণে () অপেক্ষা করার জন্য নিজেকে পিছনে ফেলে দেয়। দুটি ক্লাস (এবং দুটি তালা) তৈরি করে কাজ করবে? সুতরাং {সিঙ্কনাইজড (পান) put, পান {(সিনক্রোনাইজড (লাগানো) put রাখুন other অন্য কথায়, পেতে জাগানো কেবলমাত্র রাখা হবে, এবং পুটটি কেবল পেয়ে যাবেন
জে

43

দরকারী পার্থক্য:

  • যদি আপনার সমস্ত অপেক্ষার থ্রেডগুলি বিনিময়যোগ্য হয় (তবে তারা জেগে ওঠার ক্রমটি বিবেচনা করে না) বা আপনার যদি কেবলমাত্র একটি অপেক্ষার থ্রেড থাকে তবে বিজ্ঞপ্তি ব্যবহার করুন । একটি সাধারণ উদাহরণ হ'ল একটি থ্রেড পুল যা একটি সারি থেকে কাজগুলি চালানোর জন্য ব্যবহৃত হয় - যখন কোনও কাজ যুক্ত করা হয়, তখন থ্রেডগুলির মধ্যে একটিকে ঘুম থেকে ওঠার জন্য, পরবর্তী কাজটি কার্যকর করতে এবং ঘুমাতে ফিরে যাওয়ার জন্য অবহিত করা হয়।

  • অপেক্ষার থ্রেডগুলির বিভিন্ন উদ্দেশ্য থাকতে পারে এবং একই সাথে চলতে সক্ষম হতে হবে এমন অন্যান্য ক্ষেত্রে নোটিফএল () ব্যবহার করুন । উদাহরণ একটি শেয়ার্ড রিসোর্সে রক্ষণাবেক্ষণ অপারেশন, যেখানে একাধিক থ্রেড সংস্থান অ্যাক্সেস করার আগে অপারেশনটি সম্পূর্ণ হওয়ার অপেক্ষায় রয়েছে।


19

আমি মনে করি এটি কীভাবে সংস্থানগুলি উত্পন্ন এবং ব্যবহৃত হয় তার উপর নির্ভর করে। যদি 5 টি কাজের বস্তু একবারে উপলভ্য হয় এবং আপনার কাছে 5 টি গ্রাহক বস্তু রয়েছে, তবে বিজ্ঞপ্তি (সমস্ত) ব্যবহার করে সমস্ত থ্রেড জাগ্রত করা বুদ্ধিমানের কাজ হবে যাতে প্রত্যেকে 1 টি কাজের উদ্দেশ্যে প্রক্রিয়া করতে পারে।

আপনার যদি মাত্র একটি কাজের অবজেক্ট উপলব্ধ থাকে তবে সমস্ত ভোক্তা বস্তুকে জাগিয়ে তোলার কী দরকার? উপলভ্য কাজের জন্য প্রথম যাচাই করে নেওয়া এটি পাবে এবং অন্য সমস্ত থ্রেড চেক করবে এবং তাদের কিছুই করার নেই বলে খুঁজে পাবে।

আমি এখানে একটি দুর্দান্ত ব্যাখ্যা পেয়েছি । সংক্ষেপে:

বিজ্ঞপ্তি () পদ্ধতিটি সাধারণত সম্পদ পুলগুলির জন্য ব্যবহৃত হয় , যেখানে "ভোক্তা" বা "শ্রমিক" এমন একটি নির্বিচার সংখ্যক সংস্থান রয়েছে যা সংস্থান গ্রহণ করে, তবে যখন পুলটিতে কোনও সংস্থান যুক্ত করা হয়, কেবলমাত্র অপেক্ষারত ভোক্তা বা শ্রমিকদের মধ্যে একটিই লেনদেন করতে পারে এর সাথে. NotifyAll () পদ্ধতিটি অন্যান্য বেশিরভাগ ক্ষেত্রেই ব্যবহৃত হয়। কঠোরভাবে, এটি এমন শর্তের ওয়েটারদের অবহিত করা প্রয়োজন যা একাধিক ওয়েটারকে এগিয়ে যেতে দেয়। তবে এটি জানা প্রায়শই কঠিন। সুতরাং একটি সাধারণ নিয়ম হিসাবে, যদি আপনার বিজ্ঞপ্তি () ব্যবহারের জন্য কোনও নির্দিষ্ট যুক্তি না থাকে তবে আপনার সম্ভবত নোটিফএল () ব্যবহার করা উচিত , কারণ কোনও নির্দিষ্ট অবজেক্টে থ্রেডগুলি ঠিক কী কারণে অপেক্ষা করবে এবং কেন তা প্রায়শই জানা মুশকিল।


11

নোট করুন যে সম্মতিযুক্ত ইউটিলিটিগুলির সাথে আপনারও পছন্দ থাকতে পারে signal()এবং signalAll()এই পদ্ধতিগুলিকে সেখানে বলা হয়। সুতরাং প্রশ্নটি এমনকি সঙ্গে বৈধ থাকে java.util.concurrent

ডগ আপনাদের দেখাবে তার একটি আকর্ষণীয় বিন্দু বিখ্যাত বই : একটি notify()এবং Thread.interrupt()একই সময়ে ঘটে অবহিত আসলে হারিয়ে পারে। যদি এটি ঘটতে পারে এবং নাটকীয় জড়িত notifyAll()থাকে তবে আপনি ওভারহেডের মূল্য (বেশিরভাগ সময় অনেক বেশি থ্রেড জাগ্রত করে) প্রদান করার পরেও নিরাপদ পছন্দ।


10

সংক্ষিপ্ত সারাংশ:

সর্বদা পছন্দ notifyAll () উপর অবহিত () , যদি না আপনি একটি ব্যাপক সমান্তরাল আবেদন যেখানে থ্রেডের সংখ্যক সব একই জিনিস করে আছে।

ব্যাখ্যা:

অবহিত করুন () [...] একক থ্রেড জাগায়। যেহেতু বিজ্ঞপ্তি () আপনাকে জাগ্রত থ্রেড নির্দিষ্ট করার অনুমতি দেয় না, এটি কেবলমাত্র বৃহত পরিমাণে সমান্তরাল অ্যাপ্লিকেশনগুলিতেই কার্যকর - এটি হ'ল প্রোগ্রামগুলি প্রচুর পরিমাণে থ্রেডযুক্ত, একই রকম কাজ করে। এই জাতীয় অ্যাপ্লিকেশনটিতে, আপনি কোন থ্রেড জাগ্রত হন তা যত্নশীল হন না।

উত্স: https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html

উপরোক্ত বর্ণিত পরিস্থিতিতে notifyAll () এর সাথে notify () এর তুলনা করুন : একটি বৃহত্তর সমান্তরাল অ্যাপ্লিকেশন যেখানে থ্রেডগুলি একই কাজ করছে। যদি আপনি সেই ক্ষেত্রে নোটিফএল () কে কল করেন তবে নোটিফাইএল () প্রচুর পরিমাণে থ্রেডের জাগরণ ( অর্থসূচী) প্ররোচিত করবে, তাদের অনেকগুলি অকারণে (যেহেতু কেবলমাত্র একটি থ্রেডই প্রকৃতপক্ষে অগ্রসর হতে পারে, যেমন থ্রেডটি মঞ্জুর করা হবে অবজেক্টের জন্য অপেক্ষা করুন () , বিজ্ঞপ্তি () , বা বিজ্ঞপ্তি (সমস্ত কল করা হয়েছিল), সুতরাং কম্পিউটিং সংস্থান নষ্ট করে।

সুতরাং, আপনার যদি এমন কোনও অ্যাপ্লিকেশন না থাকে যেখানে বিপুল সংখ্যক থ্রেড একই সাথে একই কাজ করে, বিজ্ঞপ্তি () এর চেয়ে notifyAll () কে পছন্দ করুন । কেন? কারণ, অন্যান্য ব্যবহারকারীরা যেমন এই ফোরামে ইতিমধ্যে উত্তর দিয়েছেন, () অবহিত করুন

একটি একক থ্রেড জাগে যা এই বস্তুর মনিটরের জন্য অপেক্ষা করছে। [...] পছন্দটি নির্বিচারে এবং প্রয়োগের বিবেচনার ভিত্তিতে ঘটে at

উত্স: জাভা এসই 8 এপিআই ( https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#notify-- )

কল্পনা করুন আপনি একটি প্রযোজক ভোক্তা আবেদন যেখানে ভোক্তাদের জন্য প্রস্তুত (অর্থাত আছে অপেক্ষার () ing) গ্রাস, প্রযোজক প্রস্তুত (অর্থাত হয় অপেক্ষার () ing) উত্পাদন করতে এবং আইটেম এর কিউ (উত্পাদিত করা / খাওয়া) খালি। সেক্ষেত্রে , বিজ্ঞপ্তি () কেবলমাত্র গ্রাহক এবং কখনও প্রযোজককে জাগ্রত করতে পারে কারণ জেগে উঠা পছন্দটি ইচ্ছামত হয় । উত্পাদক এবং গ্রাহক যথাক্রমে উত্পাদন এবং গ্রাস করতে প্রস্তুত হলেও উত্পাদক ভোক্তা চক্র কোনও অগ্রগতি করতে পারবে না। পরিবর্তে, কোনও গ্রাহক জেগে উঠেছে (অর্থাত্ অপেক্ষা () স্থিতি রেখে ), কোনও আইটেম সারি থেকে বের করে না কারণ এটি খালি, এবং () এর অন্য গ্রাহককে এগিয়ে যাওয়ার জন্য অবহিত করুন

বিপরীতে, বিজ্ঞপ্তি (সমস্ত) প্রযোজক এবং গ্রাহক উভয়কেই জাগ্রত করে। কে নির্ধারিত হবে তা পছন্দসূচীর উপর নির্ভর করে। অবশ্যই, সময়সূচী বাস্তবায়নের উপর নির্ভর করে, শিডিয়ুলার কেবল গ্রাহকদের সময়সূচী করতে পারে (যেমন আপনি যদি গ্রাহক থ্রেডগুলিকে খুব উচ্চ অগ্রাধিকার অর্পণ করেন)। তবে, এখানে অনুমান করা হয় যে সময়সূচী নির্ধারণের সময়সূচী কেবলমাত্র ভোক্তাদের জেভিএম কেবলমাত্র ভোক্তাদের জাগ্রত করার ঝুঁকির চেয়ে কম কারণ কোনও যুক্তিসঙ্গতভাবে বাস্তবায়িত শিডিয়ুলার কেবল স্বেচ্ছাসেবী সিদ্ধান্ত নেয় না । বরং বেশিরভাগ সময়সূচী বাস্তবায়ন অনাহার প্রতিরোধের জন্য কমপক্ষে কিছু প্রচেষ্টা করে।


9

এখানে একটি উদাহরণ। চালাও এটা. তারপরে অবহিত করুন () অবহিত করার জন্য notifyAll () এর মধ্যে একটি পরিবর্তন করুন এবং দেখুন কী ঘটে।

প্রযোজককনসুমার পরীক্ষামূলক ক্লাস

public class ProducerConsumerExample {

    private static boolean Even = true;
    private static boolean Odd = false;

    public static void main(String[] args) {
        Dropbox dropbox = new Dropbox();
        (new Thread(new Consumer(Even, dropbox))).start();
        (new Thread(new Consumer(Odd, dropbox))).start();
        (new Thread(new Producer(dropbox))).start();
    }
}

ড্রপবক্স ক্লাস

public class Dropbox {

    private int number;
    private boolean empty = true;
    private boolean evenNumber = false;

    public synchronized int take(final boolean even) {
        while (empty || evenNumber != even) {
            try {
                System.out.format("%s is waiting ... %n", even ? "Even" : "Odd");
                wait();
            } catch (InterruptedException e) { }
        }
        System.out.format("%s took %d.%n", even ? "Even" : "Odd", number);
        empty = true;
        notifyAll();

        return number;
    }

    public synchronized void put(int number) {
        while (!empty) {
            try {
                System.out.println("Producer is waiting ...");
                wait();
            } catch (InterruptedException e) { }
        }
        this.number = number;
        evenNumber = number % 2 == 0;
        System.out.format("Producer put %d.%n", number);
        empty = false;
        notifyAll();
    }
}

গ্রাহক শ্রেণি

import java.util.Random;

public class Consumer implements Runnable {

    private final Dropbox dropbox;
    private final boolean even;

    public Consumer(boolean even, Dropbox dropbox) {
        this.even = even;
        this.dropbox = dropbox;
    }

    public void run() {
        Random random = new Random();
        while (true) {
            dropbox.take(even);
            try {
                Thread.sleep(random.nextInt(100));
            } catch (InterruptedException e) { }
        }
    }
}

প্রযোজক শ্রেণি

import java.util.Random;

public class Producer implements Runnable {

    private Dropbox dropbox;

    public Producer(Dropbox dropbox) {
        this.dropbox = dropbox;
    }

    public void run() {
        Random random = new Random();
        while (true) {
            int number = random.nextInt(10);
            try {
                Thread.sleep(random.nextInt(100));
                dropbox.put(number);
            } catch (InterruptedException e) { }
        }
    }
}

8

জোশুয়া ব্লচ থেকে, জাভা গুরু নিজে কার্যকর জাভা দ্বিতীয় সংস্করণে:

"আইটেম 69: অপেক্ষা করুন এবং অবহিত করার জন্য সম্মতিযুক্ত ইউটিলিটিগুলি পছন্দ করুন"।


16
কেন উৎস চেয়ে আরো গুরুত্বপূর্ণ।
পেসারিয়ার

2
@ পেসারিয়র ভাল বলেছেন। আমি পাশাপাশি কারণগুলি খুঁজতে আরও আগ্রহী হতে হবে। একটি সম্ভাব্য কারণ হ'ল অবজেক্ট ক্লাসে ওয়েট এবং অবহিত করা একটি অন্তর্নিহিত শর্ত পরিবর্তনশীলের উপর ভিত্তি করে। সুতরাং প্রমিত উত্পাদক এবং গ্রাহক উদাহরণে ..... প্রযোজক এবং গ্রাহক উভয়ই একই শর্তের জন্য অপেক্ষা করবেন যা তার উত্তরটিতে জাগিগের ব্যাখ্যা অনুসারে একটি অচলাবস্থার দিকে নিয়ে যেতে পারে। ব্যাখ্যা হিসাবে সুতরাং একটি ভাল পদ্ধতির 2 শর্ত ভেরিয়েবল ব্যবহার করা docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/...
রাহুল

6

আমি আশা করি এটি কিছু সন্দেহ দূর করবে।

বিজ্ঞপ্তি () : বিজ্ঞপ্তি () পদ্ধতিটি লকটির জন্য অপেক্ষা করে একটি থ্রেড জাগিয়ে তোলে (প্রথম থ্রেডটিকে lock লকটিতে অপেক্ষা () বলে।

notifyAll () : notifyAll () পদ্ধতিটি লকটির জন্য অপেক্ষা করা সমস্ত থ্রেড জাগ্রত করে; জেভিএম লকটির জন্য অপেক্ষা করা থ্রেডের তালিকা থেকে একটি থ্রেড নির্বাচন করে এবং সেই থ্রেডটি জাগিয়ে তোলে।

লকটির জন্য অপেক্ষা করা একক থ্রেডের ক্ষেত্রে, বিজ্ঞপ্তি () এবং নোটিফাইএল () এর মধ্যে কোনও উল্লেখযোগ্য পার্থক্য নেই। যাইহোক, যখন তালিকার জন্য একাধিক থ্রেড অপেক্ষা করে থাকে, বিজ্ঞপ্তি () এবং বিজ্ঞপ্তি (উভয়) উভয় ক্ষেত্রেই জাগ্রত সঠিক থ্রেডটি JVM এর নিয়ন্ত্রণাধীন থাকে এবং আপনি কোনও নির্দিষ্ট থ্রেড জাগ্রত করতে প্রোগ্রামালিকভাবে নিয়ন্ত্রণ করতে পারবেন না।

প্রথম নজরে, এটি প্রদর্শিত হয় যে কেবল একটি থ্রেড জাগ্রত করার জন্য কেবল বিজ্ঞপ্তি () কে কল করা ভাল ধারণা; এটি সমস্ত থ্রেড জাগ্রত করা অপ্রয়োজনীয় বলে মনে হতে পারে। তবে, বিজ্ঞপ্তি () সহ সমস্যাটি হ'ল জাগানো থ্রেডটি জাগ্রত হওয়ার জন্য উপযুক্ত নাও হতে পারে (থ্রেডটি অন্য কোনও শর্তের জন্য অপেক্ষা করছে, বা শর্তটি এখনও সেই থ্রেডের জন্য সন্তুষ্ট নয়)। যে ক্ষেত্রে , বিজ্ঞাপিত () হারিয়ে যেতে পারে এবং অন্য কোন থ্রেড সম্ভাব্য অচলাবস্থা এক ধরনের নেতৃস্থানীয় (প্রজ্ঞাপন হারিয়ে গেছে এবং সমস্ত অন্যান্য থ্রেড জন্য বিজ্ঞপ্তি-চিরকাল অপেক্ষা করছে) জেগে উঠবে।

এই সমস্যাটি এড়াতে , সর্বদা নোটিফাইআল () কে কল করা ভাল যখন লকটির জন্য অপেক্ষা করা একাধিক থ্রেড থাকে (বা একাধিক শর্তে অপেক্ষা করা হয়)। বিজ্ঞপ্তি (সমস্ত) পদ্ধতিটি সমস্ত থ্রেড জাগিয়ে তোলে তাই এটি খুব কার্যকর নয়। তবে, এই কর্মক্ষমতা হ্রাস বাস্তব বিশ্বের অ্যাপ্লিকেশনগুলিতে নগন্য l


6

একটি থ্রেডের জন্য তিনটি রাষ্ট্র রয়েছে।

  1. ওয়েট - থ্রেডটি কোনও সিপিইউ চক্র ব্যবহার করছে না
  2. অবরুদ্ধ - একটি মনিটর অর্জনের চেষ্টা করে থ্রেডটি ব্লক করা হয়েছে t এটি এখনও সিপিইউ চক্র ব্যবহার করতে পারে
  3. চলমান - থ্রেড চলছে।

এখন, যখন একটি বিজ্ঞপ্তি () ডাকা হয়, জেভিএম একটি থ্রেড নিয়ে তাদের ব্লকড স্টেটে নিয়ে যায় এবং তাই মনিটরের অবজেক্টের জন্য কোনও প্রতিযোগিতা না থাকায় চলমান রাজ্যে চলে যায়।

যখন একটি নোটিফাইআল () কল করা হয়, জেভিএম সমস্ত থ্রেড নিয়ে যায় এবং তাদের সমস্তকে ব্লক স্টেটে নিয়ে যায়। এই সমস্ত থ্রেডগুলি অগ্রাধিকারের ভিত্তিতে অবজেক্টের লকটি পেয়ে যাবে h যে মনিটরটি প্রথমে মনিটরটি অর্জন করতে সক্ষম তা প্রথমে চলমান অবস্থায় যেতে সক্ষম হবে ইত্যাদি and


শুধু দুর্দান্ত ব্যাখ্যা।
রোয়াতিরেক

5

আমি খুব অবাক হয়েছি যে কেউ কুখ্যাত "হারানো ওয়েকআপ" সমস্যার কথা উল্লেখ করেনি (গুগল এটি)।

মূলত:

  1. যদি আপনার একাধিক থ্রেড একই শর্তে অপেক্ষা করে এবং,
  2. একাধিক থ্রেড যা আপনাকে রাজ্য A থেকে রাষ্ট্র বিতে রূপান্তর করতে পারে এবং
  3. একাধিক থ্রেড যা আপনাকে রাজ্য বি থেকে রাজ্যে A তে রূপান্তর করতে পারে (সাধারণত 1 হিসাবে একই থ্রেড) এবং,
  4. রাজ্য A থেকে B এ স্থানান্তরিত করতে 1 তে থ্রেডকে অবহিত করা উচিত।

তারপরে আপনার নোটিফিকএলটি ব্যবহার করা উচিত যদি না আপনার কাছে প্রেরণযোগ্য গ্যারান্টি থাকে যে হারানো জাগানো অসম্ভব।

একটি সাধারণ উদাহরণ একটি সমবর্তী ফিফো কাত যেখানে: একাধিক এনকুইয়ার্স (১ এবং উপরে 3.) আপনার কাতাকে খালি থেকে খালি খালি একাধিক ডিকুইয়ারে স্থানান্তর করতে পারে (উপরে ২.২) শর্তটি অপেক্ষা করতে পারে "সারিটি খালি নয়" খালি -> খালি-খালি শর্তগুলি নাগরিকদের অবহিত করা উচিত

আপনি সহজেই অপারেশনগুলির একটি ইন্টারলিভিং লিখতে পারেন যা খালি সারি থেকে শুরু করে, 2 এনকুইয়ার এবং 2 জন ডেকুয়ার ইন্টারঅ্যাক্ট করে এবং 1 এনকুইয়ার ঘুমিয়ে থাকবে।

ডেডলক সমস্যার সাথে এটি তুলনামূলকভাবে সমস্যা problem


আমার ক্ষমা, xagyg এটিকে বিশদভাবে ব্যাখ্যা করে explains সমস্যার নামটি "হারানো
জাগ্রত

@ অভয় বানসাল: আমি মনে করি আপনি শর্তটি অনুপস্থিত রয়েছেন wa
নিকভি

4

notify()একটি থ্রেড notifyAll()জাগ্রত হবে এবং সমস্ত জাগ্রত হবে। আমি যতদূর জানি কোনও মাঝের মাঠ নেই। তবে notify()আপনার থ্রেডগুলিতে কী করবে তা আপনি যদি নিশ্চিত না হন তবে ব্যবহার করুন notifyAll()। প্রতি মুহুর্তের মতো কাজ করে।


4

উপরের সমস্ত উত্তর সঠিক, যতদূর আমি বলতে পারি, তাই আমি আপনাকে অন্য কিছু বলব। প্রোডাকশন কোডের জন্য আপনার জাভা.ইটিল.কমারেন্টে ক্লাস ব্যবহার করা উচিত। জাভাতে সান্নিধ্যের ক্ষেত্রে তারা আপনার পক্ষে খুব কম কাজ করতে পারে না।


4

notify()আপনাকে এর চেয়ে আরও কার্যকর কোড লিখতে দেয় notifyAll()

নিম্নলিখিত একাধিক সমান্তরাল থ্রেড থেকে সম্পাদিত কোডের অংশটি বিবেচনা করুন:

synchronized(this) {
    while(busy) // a loop is necessary here
        wait();
    busy = true;
}
...
synchronized(this) {
    busy = false;
    notifyAll();
}

এটি ব্যবহার করে আরও দক্ষ করা যায় notify():

synchronized(this) {
    if(busy)   // replaced the loop with a condition which is evaluated only once
        wait();
    busy = true;
}
...
synchronized(this) {
    busy = false;
    notify();
}

ক্ষেত্রে যদি আপনার কাছে প্রচুর পরিমাণে থ্রেড থাকে, বা যদি অপেক্ষা লুপের শর্তটি মূল্যায়নের জন্য ব্যয়বহুল হয় তবে এর notify()চেয়ে তাড়াতাড়ি দ্রুত হবে notifyAll()। উদাহরণস্বরূপ, আপনার যদি 1000 থ্রেড থাকে তবে প্রথমে 999 notifyAll(), তারপরে 997 এবং এর পরে 999 থ্রেড জাগ্রত হবে এবং মূল্যায়ন করা হবে। বিপরীতে, notify()সমাধানের সাথে, কেবল একটি থ্রেড জাগ্রত হবে।

notifyAll()কোন থ্রেড পরবর্তী কাজ করবে তা যখন আপনার চয়ন করতে হবে তখন ব্যবহার করুন :

synchronized(this) {
    while(idx != last+1)  // wait until it's my turn
        wait();
}
...
synchronized(this) {
    last = idx;
    notifyAll();
}

অবশেষে, এটি বোঝা গুরুত্বপূর্ণ যে এর ক্ষেত্রে notifyAll(), synchronizedব্লকগুলির অভ্যন্তরে যে কোডগুলি জাগ্রত হয়েছে সেগুলি একযোগে নয়, ক্রমান্বয়ে কার্যকর করা হবে। ধরা যাক উপরোক্ত উদাহরণটিতে তিনটি থ্রেড অপেক্ষা করছে এবং চতুর্থ থ্রেড কল notifyAll()। তিনটি থ্রেড জাগ্রত হবে তবে কেবলমাত্র একটি কার্যকর করা শুরু করবে এবং whileলুপের অবস্থাটি পরীক্ষা করবে । যদি শর্তটি থাকে তবে trueএটি wait()আবার কল করবে এবং কেবল তখনই দ্বিতীয় থ্রেডটি কার্যকর করা শুরু করবে এবং এর whileলুপ শর্তটি পরীক্ষা করবে ।


4

এখানে একটি সহজ ব্যাখ্যা:

আপনি সঠিক যে আপনি notify () বা notifyAll () ব্যবহার করুন না কেন, তাত্ক্ষণিক ফলাফলটি হ'ল অন্য একটি থ্রেড মনিটরটি অর্জন করবে এবং সম্পাদন শুরু করবে। (ধরে নিই যে কিছু থ্রেড প্রকৃতপক্ষে এই অবজেক্টের জন্য অপেক্ষা করা অবরুদ্ধ ছিল)) অন্যান্য সম্পর্কিত সম্পর্কযুক্ত থ্রেডগুলি সমস্ত উপলব্ধ কোরগুলি ভিজিয়ে দিচ্ছে না)) প্রভাবটি পরে আসে।

ধরুন থ্রেড এ, বি এবং সি এই অবজেক্টটির জন্য অপেক্ষা করছিল এবং থ্রেড এ মনিটর পেয়েছে। পার্থক্যটি ঘটে যা একবার ঘটে ম মনিটর প্রকাশের পরে ঘটে। আপনি যদি বিজ্ঞপ্তি () ব্যবহার করেন তবে বি এবং সি এখনও অপেক্ষায় অবরুদ্ধ রয়েছে (): তারা মনিটরে অপেক্ষা করছে না, তারা বিজ্ঞপ্তির জন্য অপেক্ষা করছে। যখন এ মনিটরটি প্রকাশ করে, বি এবং সি এখনও সেখানে বসে থাকবে, একটি বিজ্ঞপ্তির জন্য অপেক্ষা করবে ()।

আপনি যদি বিজ্ঞপ্তি (সমস্ত) ব্যবহার করেন, তবে বি এবং সি উভয়ই "বিজ্ঞপ্তির অপেক্ষার জন্য অপেক্ষা" অবস্থাটি অতীত করেছে এবং উভয়ই মনিটর অর্জনের জন্য অপেক্ষা করছেন। যখন এ মনিটরটি প্রকাশ করে, বি বা সি হয় তা অর্জন করবে (ধরে নিই যে অন্য কোনও থ্রেড সেই মনিটরের জন্য প্রতিযোগিতা করছে না) এবং সম্পাদন শুরু করে।


খুব স্পষ্ট ব্যাখ্যা। বিজ্ঞপ্তি () এর এই আচরণের ফলাফলের ফলে "মিসড সিগন্যাল" / "মিসড নোটিফিকেশন" হতে পারে যার ফলে অ্যাপ্লিকেশন রাষ্ট্রের অচলাবস্থা / অগ্রগতির কোনও পরিস্থিতি দেখা দেয় না P পি-প্রযোজক, সি-কনজিউমার পি 1, পি 2 এবং সি 2 সি 1 এর জন্য অপেক্ষা করছেন। সি 1 কল বিজ্ঞপ্তি () দেয় এবং এটি প্রযোজকের জন্য তবে সি 2 জেগে উঠতে পারে এবং তাই পি 1 এবং পি 2 উভয়ই বিজ্ঞপ্তিটি মিস করে এবং আরও স্পষ্ট "নোটিফিকেশন" (একটি বিজ্ঞপ্তি () কল) এর জন্য অপেক্ষা করবে।
ব্যবহারকারী 104309

4

এই উত্তরটি দ্বারা গ্রাফিকাল rewriting এবং চমৎকার উত্তর সরলীকৃত ব্যবস্থা xagyg , মন্তব্য সহ Eran

প্রতিটি পণ্য একক গ্রাহকের উদ্দেশ্যে করা হলেও, কেন নোটিফএল ব্যবহার করবেন?

নিম্নরূপে সরলীকৃত প্রযোজক এবং ভোক্তাদের বিবেচনা করুন।

প্রযোজক:

while (!empty) {
   wait() // on full
}
put()
notify()

উপভোক্তা:

while (empty) {
   wait() // on empty
}
take()
notify()

2 উত্পাদক এবং 2 জন ভোক্তা ধরে রাখুন, 1 আকারের একটি বাফার ভাগ করে নিচ্ছেন: নীচের ছবিতে এমন একটি দৃশ্য চিত্রিত করা হয়েছে যা অচলাবস্থার দিকে পরিচালিত করবে , যা সমস্ত থ্রেড নোটিফাইএল ব্যবহার করা থাকলে এড়ানো হবে ।

প্রতিটি বিজ্ঞপ্তি জাগ্রত থ্রেডের সাথে লেবেলযুক্ত।

অবহিত কারণে অচলাবস্থা


3

অনুশীলনে জাভা কনকুরেন্সিতে কী ব্যাখ্যা করা হয়েছে তা আমি উল্লেখ করতে চাই:

প্রথম বক্তব্য, নোটিফাই বা নোটিফাইএল সবই কিনা?

It will be NotifyAll, and reason is that it will save from signall hijacking.

যদি দুটি থ্রেড এ এবং বি একই শর্তের সারির পূর্বাভাস দেয় এবং নোটিফাই বলা হয়, তবে এটি JVM অবধি কোন থ্রেডে JVM অবহিত করবে।

এখন যদি বিজ্ঞপ্তিটি থ্রেড এ এবং জেভিএম বিজ্ঞপ্তিযুক্ত থ্রেড বি এর জন্য বোঝানো হত, তবে থ্রেড বি জেগে উঠবে এবং এই নোটিফিকেশনটি দরকারী নয় তাই এটি আবার অপেক্ষা করবে। এবং থ্রেড এ কখনই এই মিসড সিগন্যাল সম্পর্কে জানতে পারবে না এবং কেউ এর বিজ্ঞপ্তি হাইজ্যাক করেছে।

সুতরাং, নোটিফাইএলকে কল করার ফলে এই সমস্যাটি সমাধান হবে, তবে এটির কার্য সম্পাদন প্রভাব পড়বে কারণ এটি সমস্ত থ্রেডকে বিজ্ঞপ্তি দেবে এবং সমস্ত থ্রেড একই লকের জন্য প্রতিযোগিতা করবে এবং এতে প্রসঙ্গের সুইচ জড়িত থাকবে এবং তাই সিপিইউতে লোড হবে। তবে আমাদের যদি পারফরম্যান্সটি সঠিকভাবে আচরণ করে তবে আমাদের যদি তার আচরণটি সঠিক না হয় তবে পারফরম্যান্সের বিষয়ে যত্ন নেওয়া উচিত performance

স্পষ্টত লকিং লকের কন্ডিশন অবজেক্টটি ব্যবহার করে এই সমস্যা সমাধান করা যেতে পারে, জেডিডি 5 তে সরবরাহ করা হয়েছে, কারণ এটি প্রতিটি শর্তের পূর্বাভাসের জন্য আলাদা অপেক্ষা করে provides এখানে এটি সঠিকভাবে আচরণ করবে এবং কার্য সম্পাদনের সমস্যা থাকবে না কারণ এটি সিগন্যালকে কল করবে এবং নিশ্চিত করবে যে কেবলমাত্র একটি থ্রেড সেই শর্তের জন্য অপেক্ষা করছে


3

notify()- অবজেক্টের ওয়েট সেট থেকে একটি এলোমেলো থ্রেড নির্বাচন করে এবং এটি BLOCKEDরাজ্যে রাখে । অবজেক্টের ওয়েট সেটে বাকি থ্রেডগুলি এখনও WAITINGরাজ্যে রয়েছে।

notifyAll()- অবজেক্টের ওয়েট সেট থেকে সমস্ত থ্রেড BLOCKEDস্থিতিতে সরানো হয় । আপনি ব্যবহার করার পরে notifyAll(), ভাগ করা অবজেক্টের ওয়েট সেটে কোনও থ্রেড বাকি নেই কারণ সেগুলি এখন সমস্ত BLOCKEDঅবস্থায় রয়েছে এবং WAITINGঅবস্থায় নেই।

BLOCKED- লক অধিগ্রহণের জন্য অবরুদ্ধ। WAITING- বিজ্ঞপ্তির অপেক্ষায় (বা যোগদানের জন্য অবরুদ্ধ)।


3

কার্যকর জাভা ব্লগ থেকে নেওয়া :

The notifyAll method should generally be used in preference to notify. 

If notify is used, great care must be taken to ensure liveness.

সুতরাং, আমি যা বুঝি তা হ'ল (পূর্বোক্ত ব্লগ থেকে, গৃহীত উত্তর এবং জাভা ডক্স সম্পর্কে "ইয়ান টিএম" মন্তব্য করেছেন ):

  • বিজ্ঞপ্তি (): জেভিএম এই বস্তুর অপেক্ষার থ্রেডগুলির একটি জাগ্রত করে। থ্রেড নির্বাচন নির্বিচারে নির্বিচারে তৈরি করা হয়। তাই একই থ্রেড বারবার জাগ্রত করা যায়। সুতরাং সিস্টেমের রাষ্ট্র পরিবর্তন হয় কিন্তু সত্যিকারের কোন অগ্রগতি হয় না। এইভাবে একটি লাইভলক তৈরি করা হচ্ছে ।
  • notifyAll (): JVM সমস্ত থ্রেড জাগ্রত করে এবং তারপরে সমস্ত থ্রেড এই বস্তুর লকের জন্য দৌড় দেয়। এখন, সিপিইউ শিডিয়ুলার একটি থ্রেড নির্বাচন করে যা এই বস্তুর লক অর্জন করে। এই নির্বাচন প্রক্রিয়াটি জেভিএম দ্বারা নির্বাচনের চেয়ে অনেক ভাল হবে। এইভাবে, জীবন্ততা নিশ্চিত করা।

2

@ Xagyg পোস্ট করা কোডটি একবার দেখুন।

ধরুন দুটি ভিন্ন থ্রেড দুটি ভিন্ন অবস্থার জন্য অপেক্ষা করছে: প্রথম থ্রেড জন্য অপেক্ষা করছে , আর দ্বিতীয় থ্রেড জন্য অপেক্ষা করছে ।
buf.size() != MAX_SIZEbuf.size() != 0

মনে করুন কোন এক সময় buf.size() 0 এর সমান হয় না । এর notify()পরিবর্তে জেভিএম কল করে notifyAll()এবং প্রথম থ্রেডটি অবহিত করা হয়েছে (দ্বিতীয়টি নয়)।

প্রথম থ্রেড জেগে উঠেছে, চেকগুলি buf.size()যার জন্য ফিরে আসতে পারে MAX_SIZEএবং অপেক্ষা করতে ফিরে যায়। দ্বিতীয় থ্রেড জাগ্রত হয় না, অপেক্ষা করতে থাকে এবং কল করে না get()


1

notify()প্রথম থ্রেড জাগিয়ে তোলে wait()যা একই বস্তুকে ডেকেছিল ।

notifyAll()wait()একই থ্রেডে ডেকে আনা সমস্ত থ্রেডকে জাগায়।

সর্বোচ্চ অগ্রাধিকারের থ্রেডটি প্রথম চলবে।


13
notify()এটির ক্ষেত্রে ঠিক " প্রথম থ্রেড " নয়।
ভেশে গুরুং

6
কোনটি ভিএম দ্বারা নির্বাচিত হবে তা আপনি অনুমান করতে পারবেন না। একমাত্র আল্লাহই জানেন।
সের্গেই শেভচাইক

প্রথম কে হবেন তার কোনও গ্যারান্টি নেই (কোনও ন্যায্যতা নেই)
ইভান ভারোশিলিন

এটি কেবলমাত্র প্রথম থ্রেড জাগ্রত করবে যদি ওএস এটির গ্যারান্টি দেয় এবং সম্ভবত এটি তা না ঘটে। কোন থ্রেড জাগ্রত করতে হবে তা নির্ধারণ করতে এটি সত্যই ওএসকে (এবং এর শিডিয়ুলার) স্থগিত করে।
পল স্টেলিয়ান

1

বিজ্ঞপ্তি কেবলমাত্র একটি থ্রেডকে প্রত্যাশিত করবে যা অপেক্ষার স্থানে রয়েছে, যখন বিজ্ঞপ্তি দেওয়া সমস্ত অপেক্ষার স্থানে সমস্ত থ্রেডকে অবহিত করবে এখন সমস্ত বিজ্ঞপ্তিযুক্ত থ্রেড এবং সমস্ত অবরুদ্ধ থ্রেড লকের জন্য যোগ্য, যার মধ্যে কেবল একজনই লক পাবেন এবং অন্য সমস্ত (যাঁরা পূর্বে অপেক্ষমান অবস্থায় ছিলেন) অবরুদ্ধ অবস্থায় থাকবেন।


1

উপরে বর্ণিত সর্বোত্তম বিশদ বিবরণের সংক্ষিপ্তসার হিসাবে এবং আমি যে সহজ উপায়ে চিন্তা করতে পারি, এটি জেভিএম অন্তর্নির্মিত মনিটরের সীমাবদ্ধতার কারণে, যা 1) পুরো সিঙ্ক্রোনাইজেশন ইউনিটে অর্জিত (ব্লক বা অবজেক্ট) এবং 2) নির্দিষ্ট শর্তটি অপেক্ষা করা / সম্পর্কে জানানো / সম্পর্কে বৈষম্য করে না।

এর অর্থ হ'ল যদি একাধিক থ্রেড বিভিন্ন শর্তে অপেক্ষা করে এবং বিজ্ঞপ্তি () ব্যবহার করা হয়, তবে নির্বাচিত থ্রেডটি নতুনভাবে সম্পন্ন হওয়া শর্তে অগ্রগতি করতে পারে না - যার ফলে থ্রেডটি (এবং বর্তমানে এখনও অপেক্ষমান থ্রেড যা সক্ষম হবে) শর্ত পূরণ করার জন্য, ইত্যাদি ..) অগ্রগতি করতে সক্ষম না হতে এবং অবশেষে অনাহার বা প্রোগ্রাম হ্যাঙ্গআপ।

বিপরীতে, বিজ্ঞপ্তি () সমস্ত অপেক্ষার থ্রেডকে অবশেষে লকটি পুনরায় অর্জন করতে এবং তাদের নিজ নিজ অবস্থার জন্য পরীক্ষা করতে সক্ষম করে, ফলস্বরূপ অগ্রগতি হওয়ার সুযোগ দেয়।

সুতরাং বিজ্ঞপ্তি () কেবলমাত্র নিরাপদে ব্যবহার করা যেতে পারে যদি কোনও অপেক্ষাকৃত থ্রেড অগ্রগতি করার অনুমতি দেওয়ার নিশ্চয়তা দেওয়া হয় যদি এটি নির্বাচন করা হয়, যা সাধারণভাবে সন্তুষ্ট হয় যখন একই মনিটরের মধ্যে সমস্ত থ্রেড কেবল একটি এবং একই শর্তের জন্য পরীক্ষা করে থাকে - মোটামুটি বিরল বাস্তব বিশ্বের অ্যাপ্লিকেশন ক্ষেত্রে।


0

যখন আপনি "অবজেক্ট" এর অপেক্ষার () অবজেক্টটি কল করুন (অবজেক্ট লকটি অধিগ্রহণের প্রত্যাশায়) কল করবেন তখন ইন্টার্ন এটি সেই বস্তুটির লকটি মুক্তি দেবে এবং অন্যান্য থ্রেডগুলিকে এই "অবজেক্ট" এ লক রাখতে সহায়তা করবে, এই পরিস্থিতিতে সেখানে উপস্থিত থাকবে "রিসোর্স / অবজেক্ট" এর জন্য অপেক্ষা করা 1 টিরও বেশি থ্রেড (অন্যান্য থ্রেডগুলি বিবেচনা করে একই উপরের অবজেক্টের জন্য অপেক্ষাও জারি করেছে এবং নীচে এমন একটি থ্রেড থাকবে যা সংস্থান / বস্তু পূরণ করে এবং বিজ্ঞপ্তি / বিজ্ঞপ্তি সমস্ত অনুরোধ করে)।

এখানে যখন আপনি একই অবজেক্টের বিজ্ঞপ্তিটি প্রকাশ করেন (প্রক্রিয়া / কোডের একই / অন্য দিক থেকে), এটি একটি অবরুদ্ধ এবং অপেক্ষার একক থ্রেড প্রকাশ করবে (সমস্ত অপেক্ষার থ্রেড নয় - প্রকাশিত থ্রেডটি জেভিএম থ্রেড দ্বারা বাছাই করা হবে) সময়সূচী এবং অবজেক্টে সমস্ত লক প্রাপ্তি প্রক্রিয়া নিয়মিত হিসাবে একই)।

যদি আপনার কাছে কেবল একটি থ্রেড থাকে যা এই অবজেক্টটিতে ভাগ করে নেবে / কাজ করবে, তবে আপনার অপেক্ষা-বিজ্ঞপ্তি প্রয়োগের ক্ষেত্রে বিজ্ঞপ্তি () পদ্ধতিটি একা ব্যবহার করা ঠিক।

যদি আপনি এমন পরিস্থিতিতে থাকেন যেখানে একাধিক থ্রেড আপনার ব্যবসায়িক যুক্তির উপর ভিত্তি করে রিসোর্স / অবজেক্টে পড়ে এবং আপনার লেখায় থাকে তবে আপনাকে অবশ্যই বিজ্ঞপ্তি দেওয়া উচিত ()

এখন আমি দেখছি যে আমরা যখন কোনও বস্তুর উপর বিজ্ঞপ্তি () প্রকাশ করি তখন jvm ঠিক কীভাবে অপেক্ষার থ্রেড সনাক্ত এবং ভেঙে দিচ্ছে ...


0

উপরোক্ত কয়েকটি শক্ত উত্তর থাকা সত্ত্বেও আমি যে বিভ্রান্তি ও ভুল ধারণা পড়েছি তা দেখে আমি অবাক হয়েছি। এটি সম্ভবত এই ধারণাটি প্রমাণ করে যে নিজের ভাঙা সমবর্তী কোডটি লেখার চেষ্টা করার পরিবর্তে যতটা সম্ভব java.util.concurrent ব্যবহার করা উচিত। প্রশ্নের পিছনে: সংক্ষেপে বলতে গেলে, আজকের সবচেয়ে ভাল অনুশীলন হ'ল ওয়েকআপ সমস্যার কারণে সমস্ত পরিস্থিতিতে AVOID বিজ্ঞপ্তি ()। যে কেউ এটি বুঝতে পারে না তাকে মিশন সমালোচনামূলক সম্মতি কোড লেখার অনুমতি দেওয়া উচিত নয়। যদি আপনি হরিডিং সমস্যা সম্পর্কে উদ্বিগ্ন হন তবে একবারে একটি থ্রেড জাগ্রত করার একটি নিরাপদ উপায় হ'ল: 1. অপেক্ষার থ্রেডগুলির জন্য একটি সুস্পষ্ট অপেক্ষার সারি তৈরি করুন; ২. সারিতে থাকা প্রতিটি সুতোর পূর্বসূরীর জন্য অপেক্ষা করুন; ৩. প্রতিটি থ্রেড কল নোটিফাইআল () সম্পন্ন হয়ে গেলে। অথবা আপনি জাভা.ইটি.এল.কন্ট্রন্ট ব্যবহার করতে পারেন। *,


আমার অভিজ্ঞতায় অপেক্ষা / বিজ্ঞপ্তির ব্যবহার প্রায়শই সারি পদ্ধতিতে ব্যবহৃত হয় যেখানে কোনও থ্রেড ( Runnableবাস্তবায়ন) একটি সারির বিষয়বস্তু প্রক্রিয়াকরণ করে। wait()তারপর ব্যবহার করা যখনই সারি খালি হয়। এবং notify()তথ্য যুক্ত করা হয় যখন ডাকা হয়। -> এই ক্ষেত্রে কেবলমাত্র 1 টি থ্রেড রয়েছে যা কখনও কল করে wait(), তবে notifyAll()যদি আপনি জানেন যে কেবলমাত্র 1 টি অপেক্ষার থ্রেড রয়েছে তবে এটি ব্যবহার করতে কিছুটা নির্বোধ দেখাচ্ছে না।
বিভিডিবি

-2

এখানে জাগ্রত করা এখানে খুব বেশি গুরুত্ব দেয় না। বিজ্ঞপ্তি এবং বিজ্ঞপ্তি অপেক্ষা করুন, এই সমস্ত বস্তুর মনিটরের মালিক হওয়ার পরে রাখা হয়েছে। যদি কোনও থ্রেড অপেক্ষার পর্যায়ে থাকে এবং বিজ্ঞপ্তি বলা হয়, এই থ্রেডটি লকটি গ্রহণ করবে এবং সেই বিন্দুতে অন্য কোনও থ্রেড সেই লকটি নিতে পারবে না। সুতরাং একযোগে অ্যাক্সেস মোটেও নিতে পারে না। যতদূর আমি জানি অবধি বিজ্ঞপ্তি এবং বিজ্ঞপ্তি দেওয়ার জন্য যে কোনও কল কেবলমাত্র বস্তুর লক নেওয়ার পরেই করা যাবে। আমি ভুল হলে আমাকে সংশোধন করুন।

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