"হ্যালো, অ্যামিগো! আপনার মনে আছে যে অনেকগুলি থ্রেড একসাথে একটি শেয়ার্ড রিসোর্স অ্যাক্সেস করার চেষ্টা করলে যে সমস্যাগুলি দেখা দেয় সে সম্পর্কে এলি আপনাকে বলেছিল, হ্যাঁ?"

"হ্যাঁ."

"বিষয়টি হল, এটি সব নয়। আরেকটি ছোট সমস্যা আছে।"

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

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

এখানেই সমস্যা দেখা দেয়। একটি থ্রেড একটি পরিবর্তনশীল পরিবর্তন করে , যেমন উপরের উদাহরণে isCancel বা isInterrupted, কিন্তু একটি দ্বিতীয় থ্রেড «এই পরিবর্তনটি দেখতে পায় না , কারণ এটি দ্রুত স্মৃতিতে ঘটেছে। এই থ্রেড একে অপরের ক্যাশে অ্যাক্সেস নেই যে একটি ফলাফল. (একটি প্রসেসরে প্রায়শই বেশ কয়েকটি স্বাধীন কোর থাকে এবং থ্রেডগুলি শারীরিকভাবে বিভিন্ন কোরে চলতে পারে।)

আসুন গতকালের উদাহরণটি স্মরণ করি:

কোড বর্ণনা
class Clock implements Runnable
{
private boolean isCancel = false;

public void cancel()
{
this.isCancel = true;
}

public void run()
{
while (!this.isCancel)
{
Thread.sleep(1000);
System.out.println("Tick");
}
}
}
থ্রেড "জানে না" যে অন্যান্য থ্রেড বিদ্যমান.

রান পদ্ধতিতে, isCancel ভেরিয়েবলটিকে চাইল্ড থ্রেডের ক্যাশে রাখা হয় যখন এটি প্রথমবার ব্যবহার করা হয়। এই অপারেশনটি নিম্নলিখিত কোডের সমতুল্য:

public void run()
{
boolean isCancelCached = this.isCancel;
while (!isCancelCached)
{
Thread.sleep(1000);
System.out.println("Tick");
}
}

অন্য থ্রেড থেকে বাতিল পদ্ধতিতে কল করলে স্বাভাবিক (ধীর) মেমরিতে isCancel- এর মান পরিবর্তন হবে , কিন্তু অন্যান্য থ্রেডের ক্যাশে নয়।

public static void main(String[] args)
{
Clock clock = new Clock();
Thread clockThread = new Thread(clock);
clockThread.start();

Thread.sleep(10000);
clock.cancel();
}

"ওহ! এবং তারা কি এর জন্যও একটি সুন্দর সমাধান নিয়ে এসেছে, যেমন  সিঙ্ক্রোনাইজডের মতো ?"

"আপনি এটা বিশ্বাস করবেন না!"

প্রথম চিন্তা ছিল ক্যাশে নিষ্ক্রিয় করা, কিন্তু এর ফলে প্রোগ্রামগুলি কয়েকগুণ ধীর গতিতে চলে। তারপর একটি ভিন্ন সমাধান আবির্ভূত হয়।

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

এখানে আমাদের সমাধানটি কীভাবে ঠিক করা যায় তাই সবকিছু ঠিকঠাক কাজ করে:

কোড বর্ণনা
class Clock implements Runnable
{
private volatile boolean isCancel = false;

public void cancel()
{
this.isCancel = true;
}

public void run()
{
while (!this.isCancel)
{
Thread.sleep(1000);
System.out.println("Tick");
}
}
}
উদ্বায়ী সংশোধক একটি ভেরিয়েবলকে সর্বদা সমস্ত থ্রেড দ্বারা ভাগ করা সাধারণ মেমরি থেকে পড়া এবং লেখার কারণ করে।
public static void main(String[] args)
{
Clock clock = new Clock();
Thread clockThread = new Thread(clock);
clockThread.start();

Thread.sleep(10000);
clock.cancel();
}

"এটাই?"

"এটাই। সহজ এবং সুন্দর।"