JavaRush /جاوا بلاگ /Random-UR /بہاؤ کا انتظام۔ غیر مستحکم مطلوبہ الفاظ اور yield() طریقہ...

بہاؤ کا انتظام۔ غیر مستحکم مطلوبہ الفاظ اور yield() طریقہ

گروپ میں شائع ہوا۔
ہیلو! ہم ملٹی تھریڈنگ کا مطالعہ جاری رکھتے ہیں، اور آج ہم ایک نئے کلیدی لفظ - volatile اور yield() طریقہ سے واقف ہوں گے۔ آئیے جانتے ہیں کہ یہ کیا ہے :)

مطلوبہ الفاظ غیر مستحکم

ملٹی تھریڈ ایپلی کیشنز بناتے وقت، ہمیں دو سنگین مسائل کا سامنا کرنا پڑ سکتا ہے۔ سب سے پہلے، ایک ملٹی تھریڈ ایپلی کیشن کے آپریشن کے دوران، مختلف تھریڈز متغیرات کی قدروں کو کیش کر سکتے ہیں (ہم اس بارے میں مزید بات لیکچر "استعمال کرتے ہوئے" میں کریں گے )۔ یہ ممکن ہے کہ ایک تھریڈ نے متغیر کی قدر کو تبدیل کیا ہو، لیکن دوسرے نے یہ تبدیلی نہیں دیکھی کیونکہ وہ متغیر کی اپنی کیش شدہ کاپی کے ساتھ کام کر رہا تھا۔ قدرتی طور پر، نتائج سنگین ہو سکتے ہیں. تصور کریں کہ یہ صرف کسی قسم کا "متغیر" نہیں ہے، بلکہ، مثال کے طور پر، آپ کے بینک کارڈ کا بیلنس، جو اچانک تصادفی طور پر آگے پیچھے کودنا شروع ہو گیا :) بہت خوشگوار نہیں، ٹھیک ہے؟ دوم، جاوا میں، تمام اقسام کے شعبوں پر پڑھنے اور لکھنے کی کارروائیاں سوائے longاور doubleجوہری ہیں۔ جوہری کیا ہے؟ ٹھیک ہے، مثال کے طور پر، اگر آپ ایک تھریڈ میں ایک متغیر کی قدر کو تبدیل کرتے ہیں int، اور دوسرے تھریڈ میں آپ اس متغیر کی قدر کو پڑھتے ہیں، تو آپ کو یا تو اس کی پرانی ویلیو ملے گی یا پھر نئی۔ تھریڈ 1. وہاں کوئی "انٹرمیڈیٹ آپشنز" ظاہر نہیں ہوگا شاید۔ تاہم، یہ longاور کے ساتھ doubleکام نہیں کرتا ہے ۔ کیوں؟ کیونکہ یہ کراس پلیٹ فارم ہے۔ کیا آپ کو یاد ہے کہ ہم نے پہلی سطح پر کیسے کہا تھا کہ جاوا اصول "ایک بار لکھا جاتا ہے، ہر جگہ کام کرتا ہے"؟ یہ کراس پلیٹ فارم ہے۔ یعنی جاوا ایپلی کیشن بالکل مختلف پلیٹ فارمز پر چلتی ہے۔ مثال کے طور پر، ونڈوز آپریٹنگ سسٹم پر، لینکس یا میک او ایس کے مختلف ورژنز، اور ہر جگہ یہ ایپلیکیشن مستحکم طور پر کام کرے گی۔ longاور double- جاوا میں سب سے زیادہ "بھاری" قدیم: ان کا وزن 64 بٹس ہے۔ اور کچھ 32 بٹ پلیٹ فارم صرف 64 بٹ متغیرات کو پڑھنے اور لکھنے کی جوہری صلاحیت کو نافذ نہیں کرتے ہیں۔ اس طرح کے متغیرات کو دو آپریشنز میں پڑھا اور لکھا جاتا ہے۔ پہلے، پہلے 32 بٹس کو متغیر میں لکھا جاتا ہے، پھر دوسرے 32۔ اس کے مطابق، ان صورتوں میں ایک مسئلہ پیدا ہو سکتا ہے۔ ایک تھریڈ متغیر پر کچھ 64 بٹ ویلیو لکھتا ہے۔Х، اور وہ اسے "دو قدموں میں" کرتا ہے۔ ایک ہی وقت میں، دوسرا تھریڈ اس متغیر کی قدر کو پڑھنے کی کوشش کرتا ہے، اور یہ بالکل درمیان میں کرتا ہے، جب پہلے 32 بٹس پہلے ہی لکھے جا چکے ہیں، لیکن دوسرے ابھی تک نہیں لکھے گئے ہیں۔ نتیجے کے طور پر، یہ ایک انٹرمیڈیٹ، غلط قدر پڑھتا ہے، اور ایک غلطی ہوتی ہے۔ مثال کے طور پر، اگر ایسے پلیٹ فارم پر ہم کسی متغیر پر نمبر لکھنے کی کوشش کریں - 9223372036854775809 - یہ 64 بٹس پر قبضہ کرے گا۔ بائنری شکل میں یہ اس طرح نظر آئے گا: 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 پہلا تھریڈ اس نمبر کو متغیر پر لکھنا شروع کرے گا، اور پہلے 000000002 لکھے گا۔ 000000000000 00000 اور پھر دوسرا 32: 000000000000000000000000000000000000000000000000000000000000000000000000000000001 اور دوسرا دھاگہ اس خلا میں پھیر سکتا ہے اور متغیر کی انٹرمیڈیٹ ویلیو پڑھیں - 10000000000000000000000000000000000000، پہلے 32 بٹس جو پہلے ہی لکھے جا چکے ہیں۔ اعشاریہ نظام میں، یہ نمبر 2147483648 کے برابر ہے۔ یعنی، ہم صرف نمبر 9223372036854775809 کو متغیر میں لکھنا چاہتے تھے، لیکن اس حقیقت کی وجہ سے کہ کچھ پلیٹ فارمز پر یہ آپریشن ایٹم نہیں ہے، ہمیں "بائیں" نمبر 2147483648 ملا۔ جس کی ہمیں کہیں سے ضرورت نہیں ہے۔ اور یہ معلوم نہیں ہے کہ اس سے پروگرام کے آپریشن پر کیا اثر پڑے گا۔ دوسرا تھریڈ آخر میں لکھنے سے پہلے صرف متغیر کی قدر کو پڑھتا ہے، یعنی اس نے پہلے 32 بٹس دیکھے، لیکن دوسرے 32 بٹس کو نہیں۔ یہ مسائل، یقیناً، کل پیدا نہیں ہوئے تھے، اور جاوا میں وہ صرف ایک کلیدی لفظ - volatile کے استعمال سے حل ہوتے ہیں ۔ اگر ہم اپنے پروگرام میں لفظ volatile کے ساتھ کچھ متغیر کا اعلان کرتے ہیں...
public class Main {

   public volatile long x = 2222222222222222222L;

   public static void main(String[] args) {

   }
}
…اس کا مطلب ہے کہ:
  1. یہ ہمیشہ جوہری طور پر پڑھا اور لکھا جائے گا۔ یہاں تک کہ اگر یہ 64 بٹ doubleیا long.
  2. جاوا مشین اسے کیش نہیں کرے گی۔ لہذا جب 10 تھریڈز اپنی مقامی کاپیوں کے ساتھ کام کرتے ہیں تو اس صورت حال کو خارج کر دیا جاتا ہے۔
اس طرح ایک لفظ میں دو بہت سنگین مسائل حل ہو جاتے ہیں :)

yield() طریقہ

ہم پہلے ہی کلاس کے بہت سے طریقوں کو دیکھ چکے ہیں Thread، لیکن ایک اہم طریقہ ہے جو آپ کے لیے نیا ہوگا۔ یہ yield() طریقہ ہے ۔ انگریزی سے ترجمہ "give in." اور یہ بالکل وہی ہے جو طریقہ کرتا ہے! بہاؤ کا انتظام۔  غیر مستحکم مطلوبہ الفاظ اور پیداوار () طریقہ - 2جب ہم دھاگے پر پیداوار کا طریقہ کہتے ہیں، تو یہ درحقیقت دوسرے دھاگوں سے کہتا ہے: "ٹھیک ہے، دوستو، مجھے کوئی خاص جلدی نہیں ہے، لہذا اگر آپ میں سے کسی کے لیے CPU کا وقت حاصل کرنا ضروری ہے، تو اسے لے لو، میں ہوں فوری نہیں ہے۔" یہ کیسے کام کرتا ہے اس کی ایک سادہ مثال یہ ہے:
public class ThreadExample extends Thread {

   public ThreadExample() {
       this.start();
   }

   public void run() {

       System.out.println(Thread.currentThread().getName() + "give way to others");
       Thread.yield();
       System.out.println(Thread.currentThread().getName() + " has finished executing.");
   }

   public static void main(String[] args) {
       new ThreadExample();
       new ThreadExample();
       new ThreadExample();
   }
}
ہم ترتیب وار تین تھریڈز بناتے اور لانچ کرتے ہیں - Thread-0, Thread-1اور Thread-2. Thread-0سب سے پہلے شروع ہوتا ہے اور فوری طور پر دوسروں کو راستہ دیتا ہے. اس کے بعد یہ شروع ہوتا ہے Thread-1، اور راستہ بھی دیتا ہے۔ اس کے بعد، یہ شروع ہوتا ہے Thread-2، جو بھی کمتر ہے. ہمارے پاس مزید کوئی دھاگہ نہیں ہے، اور Thread-2آخری والے نے اپنی جگہ چھوڑنے کے بعد، دھاگے کا شیڈیولر نظر آتا ہے: "تو، اب مزید نئے تھریڈز نہیں ہیں، ہمارے پاس قطار میں کون ہے؟ اس سے پہلے اپنی جگہ چھوڑنے والا آخری کون تھا Thread-2؟ مجھے لگتا ہے کہ یہ تھا Thread-1؟ ٹھیک ہے، اسے ہونے دو۔" Thread-1آخر تک اپنا کام کرتا ہے، جس کے بعد تھریڈ شیڈیولر کوآرڈینیٹ کرنا جاری رکھتا ہے: "ٹھیک ہے، تھریڈ-1 مکمل ہو گیا ہے۔ کیا ہمارے پاس لائن میں کوئی اور ہے؟" قطار میں تھریڈ-0 ہے: اس نے تھریڈ-1 سے پہلے اپنی جگہ چھوڑ دی۔ اب معاملہ اس کے پاس آ گیا ہے، اور اسے انجام تک پہنچایا جا رہا ہے۔ جس کے بعد شیڈیولر تھریڈز کو کوآرڈینیشن مکمل کرتا ہے: "ٹھیک ہے، تھریڈ-2، آپ نے دوسرے تھریڈز کو راستہ دیا، وہ سب پہلے ہی کام کر چکے ہیں۔ آپ راستہ دینے والے آخری تھے، اس لیے اب آپ کی باری ہے۔‘‘ اس کے بعد تھریڈ-2 تکمیل کی طرف دوڑتا ہے۔ کنسول آؤٹ پٹ اس طرح نظر آئے گا: Thread-0 دوسروں کو راستہ دیتا ہے Thread-1 دوسروں کو راستہ دیتا ہے Thread-2 دوسروں کو راستہ دیتا ہے Thread-1 نے عملدرآمد مکمل کر لیا ہے۔ Thread-0 پر عملدرآمد ختم ہو گیا ہے۔ Thread-2 پر عملدرآمد ختم ہو گیا ہے۔ تھریڈ شیڈیولر، بلاشبہ، تھریڈز کو مختلف ترتیب میں چلا سکتا ہے (مثال کے طور پر، 0-1-2 کی بجائے 2-1-0)، لیکن اصول ایک ہی ہے۔

ہوتا ہے - قواعد سے پہلے

آخری چیز جس پر ہم آج چھوئیں گے وہ ہے " پہلے ہوتا ہے " کے اصول۔ جیسا کہ آپ پہلے ہی جانتے ہیں، جاوا میں، تھریڈز کو ان کے کام مکمل کرنے کے لیے وقت اور وسائل مختص کرنے کا زیادہ تر کام تھریڈ شیڈیولر کرتا ہے۔ اس کے علاوہ، آپ نے ایک سے زیادہ بار دیکھا ہے کہ کس طرح دھاگوں کو من مانی ترتیب سے چلایا جاتا ہے، اور اکثر اس کی پیشین گوئی کرنا ناممکن ہوتا ہے۔ اور عام طور پر، "تسلسل" پروگرامنگ کے بعد جو ہم نے پہلے کیا تھا، ملٹی تھریڈنگ ایک بے ترتیب چیز کی طرح دکھائی دیتی ہے۔ جیسا کہ آپ پہلے ہی دیکھ چکے ہیں، ایک ملٹی تھریڈ پروگرام کی پیشرفت کو طریقوں کے پورے سیٹ کا استعمال کرتے ہوئے کنٹرول کیا جا سکتا ہے۔ لیکن اس کے علاوہ، جاوا ملٹی تھریڈنگ میں ایک اور "استحکام کا جزیرہ" ہے - 4 قواعد جنہیں " پیش سے پہلے " کہا جاتا ہے۔ انگریزی سے لفظی طور پر اس کا ترجمہ "پہلے ہوتا ہے"، یا "پہلے ہوتا ہے" کے طور پر کیا جاتا ہے۔ ان اصولوں کا مطلب سمجھنا بہت آسان ہے۔ تصور کریں کہ ہمارے پاس دو دھاگے ہیں - Aاور B. ان تھریڈز میں سے ہر ایک آپریشن کر سکتا ہے 1اور 2. اور جب ہر ایک اصول میں ہم کہتے ہیں کہ " A ہوتا ہے - B سے پہلے "، تو اس کا مطلب ہے کہ Aآپریشن سے پہلے تھریڈ کے ذریعے کی گئی تمام تبدیلیاں 1اور اس آپریشن میں شامل تبدیلیاں Bآپریشن کے وقت تھریڈ پر نظر آتی ہیں 2اور آپریشن کے بعد. ان اصولوں میں سے ہر ایک اس بات کو یقینی بناتا ہے کہ جب ایک ملٹی تھریڈڈ پروگرام لکھتے ہیں، تو کچھ واقعات 100% وقت سے پہلے دوسروں کے سامنے ہوں گے، اور یہ کہ Bآپریشن کے وقت تھریڈ کو آپریشن کے دوران ہونے والی 2تبدیلیوں سے ہمیشہ آگاہ رکھا جائے گا۔ . آئیے ان کو دیکھتے ہیں۔ А1

اصول 1۔

ایک mutex کو جاری کرنا اس سے پہلے ہوتا ہے اس سے پہلے کہ دوسرا تھریڈ ایک ہی مانیٹر حاصل کرے۔ ٹھیک ہے، یہاں سب کچھ واضح لگتا ہے. اگر کسی چیز یا کلاس کا mutex ایک دھاگے سے حاصل کیا جاتا ہے، مثال کے طور پر، ایک دھاگہ А، دوسرا دھاگہ (دھاگہ B) اسے ایک ہی وقت میں حاصل نہیں کر سکتا۔ آپ کو mutex کے جاری ہونے تک انتظار کرنے کی ضرورت ہے۔

اصول 2۔

طریقہ Thread.start() سے پہلے ہوتا ہے Thread.run() ۔ کچھ بھی پیچیدہ نہیں۔ آپ پہلے ہی جانتے ہیں: طریقہ کار کے اندر موجود کوڈ پر عمل درآمد شروع کرنے کے لیے run()، آپ کو تھریڈ پر موجود طریقہ کو کال کرنے کی ضرورت ہے start()۔ یہ اس کا ہے، اور طریقہ خود نہیں ہے run()! یہ قاعدہ اس بات کو یقینی بناتا ہے کہ Thread.start()عمل درآمد سے پہلے متعین کردہ تمام متغیرات کی قدریں اس طریقہ کے اندر نظر آئیں گی جس پر عمل کرنا شروع ہوا تھا run()۔

قاعدہ 3۔

طریقہ کی تکمیل طریقہ سے باہر نکلنے run() سے پہلے ہوتی ہےjoin() ۔ آئیے اپنے دو سلسلے کی طرف لوٹتے ہیں - Аاور B. ہم طریقہ کو join()اس طرح کہتے ہیں کہ تھریڈ کو اپنا کام کرنے سے پہلے Bمکمل ہونے تک انتظار کرنا چاہیے ۔ Aاس کا مطلب یہ ہے کہ آبجیکٹ A کا طریقہ run()یقینی طور پر آخر تک چلے گا۔ اور ڈیٹا میں ہونے والی تمام تبدیلیاں جو run()تھریڈ کے طریقہ کار میں ہوتی ہیں Aوہ تھریڈ میں مکمل طور پر نظر آئیں گی Bجب یہ مکمل ہونے کا انتظار کرے گا Aاور خود کام کرنا شروع کر دے گا۔

قاعدہ 4۔

متغیر متغیر پر لکھنا اسی متغیر سے پڑھنے سے پہلے ہوتا ہے ۔ غیر مستحکم کلیدی لفظ استعمال کرنے سے، ہم درحقیقت ہمیشہ موجودہ قدر حاصل کریں گے۔ longیہاں تک کہ اور کے معاملے میں double، جن مسائل کے ساتھ پہلے بات کی گئی تھی۔ جیسا کہ آپ پہلے ہی سمجھ چکے ہیں، کچھ تھریڈز میں کی گئی تبدیلیاں ہمیشہ دوسرے تھریڈز پر نظر نہیں آتیں۔ لیکن، یقینا، اکثر ایسے حالات ہوتے ہیں جب اس طرح کے پروگرام کا رویہ ہمارے موافق نہیں ہوتا ہے۔ ہم کہتے ہیں کہ ہم نے تھریڈ میں متغیر کو ایک قدر تفویض کی ہے A۔
int z;.

z= 555;
اگر ہمارا تھریڈ Bکسی متغیر کی ویلیو کو zکنسول پر پرنٹ کرنا تھا تو یہ آسانی سے 0 پرنٹ کر سکتا ہے کیونکہ اسے اس کی تفویض کردہ ویلیو کے بارے میں نہیں معلوم۔ لہذا، قاعدہ 4 ہمیں ضمانت دیتا ہے: اگر آپ کسی متغیر کو zغیر مستحکم قرار دیتے ہیں، تو ایک تھریڈ میں اس کی اقدار میں تبدیلیاں ہمیشہ دوسرے تھریڈ میں نظر آئیں گی۔ اگر ہم پچھلے کوڈ میں volatile کا لفظ شامل کرتے ہیں...
volatile int z;.

z= 555;
... وہ صورتحال جس میں اسٹریم Bکنسول میں 0 آؤٹ پٹ کرے گا اسے خارج کر دیا گیا ہے۔ غیر مستحکم متغیرات کو لکھنا ان سے پڑھنے سے پہلے ہوتا ہے۔
تبصرے
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION