দ্য

"হাই, অ্যামিগো!"

"আমি অপেক্ষা-বিজ্ঞপ্তি সম্পর্কে আপনার সাথে গভীরভাবে ডুব দিতে চাই। অপেক্ষা-বিজ্ঞপ্তি পদ্ধতিগুলি থ্রেডগুলিকে ইন্টারঅ্যাক্ট করার জন্য একটি সুবিধাজনক প্রক্রিয়া প্রদান করে। এগুলি থ্রেড ইন্টারঅ্যাকশনের জন্য জটিল উচ্চ-স্তরের মেকানিজম তৈরি করতেও ব্যবহার করা যেতে পারে।"

"আমি একটি ছোট উদাহরণ দিয়ে শুরু করব। ধরুন আমাদের একটি সার্ভারের জন্য একটি প্রোগ্রাম আছে যা অবশ্যই একটি ওয়েবসাইটের মাধ্যমে ব্যবহারকারীদের দ্বারা তৈরি বিভিন্ন কাজ সম্পাদন করতে হবে। ব্যবহারকারীরা বিভিন্ন সময়ে বিভিন্ন কাজ যোগ করতে পারে। কাজগুলি সম্পদ-নিবিড়, কিন্তু আমাদের সার্ভারের 8 -কোর প্রসেসর মোকাবেলা করতে পারে। সার্ভারে আমরা কীভাবে কাজগুলি সম্পাদন করব?"

"প্রথম, আমরা কর্মী থ্রেডগুলির একটি গ্রুপ তৈরি করব, যতগুলি প্রসেসর কোর আছে। প্রতিটি থ্রেড তার নিজস্ব কোরে চলতে সক্ষম হবে: থ্রেডগুলি একে অপরের সাথে হস্তক্ষেপ করবে না, এবং প্রসেসর কোরগুলি হবে না অলস বসে থাকো।"

"দ্বিতীয়, আমরা একটি সারি অবজেক্ট তৈরি করব যেখানে ব্যবহারকারীদের কাজ যোগ করা হবে। বিভিন্ন ধরনের কাজ বিভিন্ন অবজেক্টের সাথে সঙ্গতিপূর্ণ হবে, কিন্তু সেগুলি চালানো যায় এমন ইন্টারফেস বাস্তবায়ন করবে।"

"আপনি কি আমাকে একটি টাস্ক অবজেক্টের উদাহরণ দিতে পারেন?"

"এটা দেখ:"

একটি শ্রেণী যা n ফ্যাক্টরিয়াল গণনা করে যখন রান() পদ্ধতি বলা হয়
class Factorial implements Runnable
{
 public int n = 0;
 public long result = 1;

 public Factorial (int n)
 {
  this.n = n;
 }

 public void run()
 {
  for (int i = 2; i <= n; i++)
   result *= i;
 }
}

"এ পর্যন্ত সব ঠিকই."

"দারুণ। তাহলে আসুন একটি সারির বস্তু দেখতে কেমন হওয়া উচিত তা পরীক্ষা করা যাক। আপনি এটি সম্পর্কে আমাকে কী বলতে পারেন?"

"এটি অবশ্যই থ্রেড-নিরাপদ হতে হবে। এটি একটি থ্রেড দ্বারা টাস্ক অবজেক্টের সাথে লোড করা হয় যা ব্যবহারকারীদের কাছ থেকে সেগুলি গ্রহণ করে, এবং তারপরে কর্মী থ্রেড দ্বারা কাজগুলি নেওয়া হয়।"

"হ্যাঁ। এবং যদি আমাদের কিছু সময়ের জন্য কাজ ফুরিয়ে যায়?"

"তাহলে কর্মী থ্রেডগুলি আরও বেশি না হওয়া পর্যন্ত অপেক্ষা করা উচিত।"

"এটা ঠিক। এখন কল্পনা করুন যে এই সব একটি একক সারিতে তৈরি করা যেতে পারে। এটি পরীক্ষা করে দেখুন:"

একটি টাস্ক সারি. যদি কোনও কাজ না থাকে, তবে থ্রেডটি ঘুমিয়ে পড়ে এবং একটি উপস্থিত হওয়ার জন্য অপেক্ষা করে:
public class JobQueue
{
 ArrayList jobs = new ArrayList();

 public synchronized void put(Runnable job)
 {
  jobs.add(job);
  this.notifyAll();
 }

 public synchronized Runnable getJob()
 {
  while (jobs.size() == 0)
   this.wait();

  return jobs.remove(0);
 }
}

"আমাদের কাছে একটি getJob পদ্ধতি রয়েছে যা কার্য তালিকাটি খালি কিনা তা পরীক্ষা করে। থ্রেডটি তারপরে ঘুমে যায় (অপেক্ষা করে) যতক্ষণ না তালিকায় কিছু উপস্থিত হয়।"

"এছাড়াও পুট মেথড আছে , যা আপনাকে তালিকায় একটি নতুন টাস্ক যোগ করতে দেয়। একটি নতুন টাস্ক যোগ করার সাথে সাথেই notifyAll মেথডকে কল করা হয়। এই মেথডটি কল করলে সেই সমস্ত কর্মী থ্রেডকে জাগিয়ে দেয় যেগুলো getJob মেথডের ভিতরে ঘুমিয়ে পড়েছিল।"

"আপনি কি আবার মনে করতে পারেন কিভাবে অপেক্ষা এবং বিজ্ঞপ্তি পদ্ধতি কাজ করে?"

"অপেক্ষার পদ্ধতিটি শুধুমাত্র একটি মিউটেক্স অবজেক্টে একটি সিঙ্ক্রোনাইজড ব্লকের ভিতরে বলা হয়। আমাদের ক্ষেত্রে: এটি। তাছাড়া, দুটি জিনিস ঘটে:

1) থ্রেড ঘুমিয়ে পড়ে।

2) থ্রেডটি সাময়িকভাবে মিউটেক্স ছেড়ে দেয় (এটি জেগে ওঠা পর্যন্ত)।

"এর পরে, অন্যান্য থ্রেডগুলি সিঙ্ক্রোনাইজড ব্লকে প্রবেশ করতে পারে এবং একই মিউটেক্স অর্জন করতে পারে।"

" notifyAll পদ্ধতিটি শুধুমাত্র একটি mutex অবজেক্টের সিঙ্ক্রোনাইজড ব্লকের মধ্যেও কল করা যেতে পারে। আমাদের ক্ষেত্রে: এটি। তাছাড়া, দুটি জিনিস ঘটে:"

1) এই মিউটেক্স বস্তুর জন্য অপেক্ষা করা সমস্ত থ্রেড জাগ্রত হয়।

2) একবার বর্তমান থ্রেড সিঙ্ক্রোনাইজড ব্লক থেকে বেরিয়ে গেলে, জাগ্রত থ্রেডগুলির মধ্যে একটি মিউটেক্স অর্জন করে এবং তার কাজ চালিয়ে যায়। যখন এটি মিউটেক্স রিলিজ করে, তখন আরেকটি জাগ্রত থ্রেড মিউটেক্স ইত্যাদি অর্জন করে।

"এটি একটি বাসের মতোই। আপনি প্রবেশ করেন এবং আপনার ভাড়া দিতে চান, কিন্তু কোন ড্রাইভার নেই। তাই আপনি "ঘুমিয়ে পড়েন"। অবশেষে, বাসটি ভর্তি হয়ে যায়, কিন্তু এখনও ভাড়া দেওয়ার মতো কেউ নেই। তারপর ড্রাইভার এসে বলে, "ভাড়া, প্লিজ"। আর এটাই শুরু..."

"আকর্ষণীয় তুলনা। কিন্তু বাস কি?"

"জুলিও এটি ব্যাখ্যা করেছেন। 21 শতকে এই অদ্ভুত জিনিসগুলি ব্যবহার করা হয়েছিল।"