স্পষ্টতই, 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।