CodeGym /جاوا بلاگ /Random-SD /سلسلي جو انتظام. volatile keyword and the yield() طريقو
John Squirrels
سطح
San Francisco

سلسلي جو انتظام. volatile keyword and the yield() طريقو

گروپ ۾ شايع ٿيل
سلام اسان ملٽي ٿريڊنگ جو مطالعو جاري رکون ٿا. اڄ اسان کي معلوم ٿيندو volatileلفظ ۽ yield()طريقو. اچو ته اندر وڃون :)

غير مستحڪم لفظ

جڏهن multithreaded ايپليڪيشنون ٺاهڻ، اسان کي ٻه سنگين مسئلن ۾ هلائي سگهون ٿا. پهريون، جڏهن هڪ ملٽي ٿريڊ ايپليڪيشن هلندي آهي، ته مختلف ٿريڊس ڪيش ڪري سگھن ٿيون متغيرن جي قدرن کي (اسان اڳي ئي ان بابت سبق ۾ ڳالهايو آهي 'استعمال volatile' ). توهان کي اها صورتحال ٿي سگهي ٿي جتي هڪ ٿريڊ هڪ متغير جي قيمت کي تبديل ڪري ٿو، پر هڪ ٻئي ٿريڊ ۾ تبديلي نظر نه ايندي آهي، ڇاڪاڻ ته اهو متغير جي ڪيش ڪيل ڪاپي سان ڪم ڪري رهيو آهي. قدرتي طور، نتيجا سنجيده ٿي سگهي ٿو. فرض ڪريو ته اهو صرف ڪو پراڻو متغير نه آهي، بلڪه توهان جي بئنڪ اڪائونٽ بيلنس، جيڪو اوچتو بي ترتيبيءَ سان مٿي ۽ هيٺ ڪرڻ شروع ڪري ٿو :) اهو مزو نٿو لڳي، صحيح؟ ٻيو، جاوا ۾، سڀني ابتدائي قسمن کي پڙهڻ ۽ لکڻ لاء آپريشن، سواء long۽ double، ايٽمي آهن. مثال طور، جيڪڏهن توهان intهڪ ٿريڊ تي هڪ متغير جي قيمت کي تبديل ڪريو ٿا، ۽ ٻئي ٿريڊ تي توهان متغير جي قيمت کي پڙهو ٿا، توهان کي يا ته ان جي پراڻي قيمت يا نئين قيمت حاصل ٿيندي، يعني اها قيمت جيڪا تبديلي جي نتيجي ۾ آئي. سلسلي 1 ۾. ڪو به 'وچولي قدر' نه آهي. longبهرحال، اهو s ۽ doubles سان ڪم نٿو ڪري . ڇو؟ ڪراس پليٽ فارم سپورٽ جي ڪري. شروعاتي سطحن تي ياد رکو ته اسان چيو ته جاوا جو رهنمائي وارو اصول آهي 'هڪ ڀيرو لکو، ڪٿي به هلو'؟ يعني ڪراس پليٽ فارم سپورٽ. ٻين لفظن ۾، جاوا ايپليڪيشن سڀني قسمن جي مختلف پليٽ فارمن تي هلندو آهي. مثال طور، ونڊوز آپريٽنگ سسٽم تي، Linux يا MacOS جا مختلف ورجن. اهو انهن سڀني تي بغير ڪنهن رڪاوٽ جي هلندو. هڪ 64 بٽ ۾ وزن، long۽ doubleجاوا ۾ 'سڀ کان ڳري' پرائمري آهن. ۽ ڪجهه 32-bit پليٽ فارم صرف 64-bit متغير جي ايٽمي پڙهڻ ۽ لکڻ تي عمل نه ڪندا آهن. اهڙا متغير پڙهيا ۽ لکيا ويندا آهن ٻن عملن ۾. پهرين، پهرين 32 بٽ متغير ڏانهن لکيل آهن، ۽ پوء ٻيا 32 بٽ لکيل آهن. نتيجي طور، هڪ مسئلو پيدا ٿي سگهي ٿو. ھڪڙو ٿريڊ ڪجھ 64-bit قدر ھڪڙي Xمتغير ڏانھن لکندو آھي ۽ ائين ٻن عملن ۾ ڪندو آھي. ساڳئي وقت، هڪ سيڪنڊ ٿريڊ ڪوشش ڪري ٿو ته متغير جي قدر پڙهڻ ۽ ائين ڪري ٿو انهن ٻن عملن جي وچ ۾ - جڏهن ته پهرين 32 بٽ لکيا ويا آهن، پر ٻئي 32 بٽ نه آهن. نتيجي طور، اهو هڪ وچولي، غلط قدر پڙهي ٿو، ۽ اسان وٽ هڪ بگ آهي. مثال طور، جيڪڏهن اهڙي پليٽ فارم تي اسان نمبر لکڻ جي ڪوشش ڪريون ٿا 9223372036854775809 تي هڪ ويريبل، اهو 64 بٽس تي قبضو ڪندو. بائنري فارم ۾، اهو هن طرح نظر اچي ٿو: 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 . پهرين تي، اهو پهريون 32 بٽس ( 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 . ۽ ٻيو ٿريڊ انهن عملن جي وچ ۾ ويڙهجي سگهي ٿو، متغير جي وچولي قدر (100000000000000000000000000000000000000000000000000000000000000000000000000000)، جيڪي پهريان 32 بٽ آهن جيڪي اڳ ۾ ئي لکيا ويا آهن. ڊيسيمل سسٽم ۾، هي انگ 2,147,483,648 آهي. ٻين لفظن ۾، اسان صرف نمبر 9223372036854775809 کي هڪ متغير ڏانهن لکڻ چاهيون ٿا، پر حقيقت اها آهي ته اهو آپريشن ڪجهه پليٽ فارمن تي ايٽمي نه آهي، اسان وٽ برائي نمبر 2,147,483,648 آهي، جيڪو هاڻي کان ٻاهر آيو آهي ۽ اڻڄاتل اثر ٿيندو. پروگرام. ٻئي ٿريڊ ۾ لکڻ جي مڪمل ٿيڻ کان اڳ ئي variable جي قيمت پڙهي، يعني ٿريڊ پهرين 32 بِٽ ڏٺي، پر ٻئي 32 بِٽ نه ڏٺي. يقينن، اهي مسئلا ڪالهه پيدا نه ٿيا. جاوا انهن کي هڪ واحد لفظ سان حل ڪري ٿو: volatile. جيڪڏهن اسان volatileلفظ استعمال ڪندا آهيون جڏهن اسان جي پروگرام ۾ ڪجهه متغير جو اعلان ڪندا آهيون…

public class Main {

   public volatile long x = 2222222222222222222L;

   public static void main(String[] args) {

   }
}
... مطلب ته:
  1. اهو هميشه ايٽمي طور تي پڙهيو ۽ لکيو ويندو. جيتوڻيڪ اهو هڪ 64-bit doubleيا long.
  2. جاوا مشين ان کي ڪيش نه ڪندي. تنهن ڪري توهان وٽ اهڙي صورتحال نه هوندي جتي 10 موضوع پنهنجن مقامي ڪاپي سان ڪم ڪري رهيا آهن.
اهڙيء طرح، ٻه تمام سنجيده مسئلا صرف هڪ لفظ سان حل ڪيا ويا آهن :)

پيداوار () جو طريقو

اسان اڳ ۾ ئي Threadڪلاس جي ڪيترن ئي طريقن جو جائزو ورتو آهي، پر هڪ اهم آهي جيڪو توهان لاءِ نئون هوندو. اهو yield()طريقو آهي . ۽ اهو ئي ڪري ٿو جيڪو ان جي نالي جو مطلب آهي! سلسلي جو انتظام.  volatile keyword and the yield() طريقو - 2جڏهن اسان yieldهڪ سلسلي تي طريقي کي سڏيندا آهيون، اهو اصل ۾ ٻين موضوعن سان ڳالهائيندو آهي: 'اي، دوستو. مون کي ڪٿي به وڃڻ لاءِ ڪا خاص تڪڙ نه آهي، تنهن ڪري جيڪڏهن اهو ضروري آهي ته توهان مان ڪنهن لاءِ پروسيسر وقت حاصل ڪرڻ، ان کي وٺو - مان انتظار ڪري سگهان ٿو. هتي هڪ سادي مثال آهي ته اهو ڪيئن ڪم ڪري ٿو:

public class ThreadExample extends Thread {

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

   public void run() {

       System.out.println(Thread.currentThread().getName() + " yields its place 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, and Thread-2. Thread-0پهرين شروع ٿئي ٿو ۽ فوري طور تي ٻين کي حاصل ڪري ٿو. پوء Thread-1شروع ٿئي ٿو ۽ پڻ حاصل ڪري ٿو. پوءِ Thread-2شروع ٿئي ٿو، جيڪو پڻ حاصل ڪري ٿو. اسان وٽ وڌيڪ ڪو به موضوع نه آهي، ۽ Thread-2ان جي آخري جاء تي حاصل ڪرڻ کان پوء، ٿريڊ شيڊولر چوي ٿو، 'هم، هتي وڌيڪ نوان موضوع نه آهن. اسان وٽ ڪير آهي قطار ۾؟ ان کان اڳ ان جو مقام ڪير ڏنو Thread-2؟ لڳي ٿو ته هو Thread-1. ٺيڪ آهي، ان جو مطلب آهي ته اسان ان کي هلڻ ڏينداسين. Thread-1پنهنجو ڪم مڪمل ڪري ٿو ۽ پوءِ ٿريڊ شيڊيولر پنهنجو ڪوآرڊينيشن جاري رکي ٿو: 'ٺيڪ آهي، Thread-1ختم ٿي ويو. ڇا اسان جي قطار ۾ ڪو ٻيو آهي؟'. ٿريڊ-0 قطار ۾ آهي: ان جي جاءِ اڳي ئي حاصل ڪئي Thread-1. اهو هاڻي پنهنجو موڙ حاصل ڪري ٿو ۽ مڪمل ٿيڻ تي هلندو آهي. پوءِ شيڊيولر ٿريڊز کي همٿائڻ ختم ڪري ٿو: 'ٺيڪ آهي، Thread-2توهان ٻين موضوعن تي حاصل ڪيو، ۽ اهي سڀ هاڻي ٿي ويا آهن. توهان حاصل ڪرڻ وارا آخري هئا، تنهنڪري هاڻي توهان جي باري آهي. ان کان پوء Thread-2مڪمل ٿيڻ تي هلندو آهي. ڪنسول آئوٽ پٽ هن طرح نظر ايندو: Thread-0 پنهنجي جاءِ ڏئي ٿو ٻين کي Thread-1 yields ان جي جاءِ ٻين کي Thread-2 yields ان جي جاءِ ٻين ڏانهن Thread-1 ختم ٿي چڪو آهي. Thread-0 تي عملدرآمد ختم ٿي چڪو آهي. Thread-2 تي عملدرآمد ختم ٿي چڪو آهي. يقينن، ٿريڊ شيڊيولر شايد موضوعن کي مختلف ترتيب سان شروع ڪري سگھي ٿو (مثال طور، 0-1-2 جي بدران 2-1-0)، پر اصول ساڳيو رهي ٿو.

ٿئي ٿو- ضابطن کان اڳ

آخري شيء جنهن تي اسان اڄ رابطو ڪنداسين اهو تصور آهي ' اڳ ۾ ٿئي ٿو '. جئين توهان اڳ ۾ ئي ڄاڻو ٿا، جاوا ۾ ٿريڊ شيڊولر انهن ڪمن کي انجام ڏيڻ لاءِ ٿريڊز کي وقت ۽ وسيلا مختص ڪرڻ ۾ شامل ڪم جو وڏو حصو انجام ڏئي ٿو. توهان پڻ بار بار ڏٺو آهي ته ڪيئن موضوعن تي عمل ڪيو وڃي ٿو بي ترتيب ترتيب جنهن جي اڳڪٿي ڪرڻ عام طور تي ناممڪن آهي. ۽ عام طور تي، 'ترتيباتي' پروگرامنگ کان پوءِ جيڪو اسان اڳ ڪيو هو، ملٽي ٿريڊ پروگرامنگ ڪجهه بي ترتيب وانگر نظر اچي ٿي. توهان اڳ ۾ ئي يقين ڪيو آهي ته توهان ڪيترن ئي طريقن جي ميزباني کي استعمال ڪري سگهو ٿا هڪ گھڻائي واري پروگرام جي وهڪري کي ڪنٽرول ڪرڻ لاء. پر جاوا ۾ ملٽي ٿريڊنگ ۾ ھڪڙو وڌيڪ ستون آھي - 4 ' ٿيڻ کان اڳ ' ضابطا. انهن ضابطن کي سمجهڻ بلڪل سادو آهي. تصور ڪريو ته اسان وٽ ٻه سلسلا آهن - A۽ B. انهن سلسلي مان هر هڪ آپريشن ڪري سگهي ٿو 1۽ 2. هر قاعدي ۾، جڏهن اسان چئون ٿا ' A ٿئي ٿو-B کان اڳA '، اسان جو مطلب اهو آهي ته آپريشن کان اڳ ٿريڊ ۾ ڪيل سموريون تبديليون 1۽ ان آپريشن جي نتيجي ۾ ٿيندڙ تبديليون ٿريڊ ۾ نظر اينديون آهن Bجڏهن آپريشن 2ڪيو ويندو آهي ۽ ان کان پوءِ. هر قاعدو ضمانت ڏئي ٿو ته جڏهن توهان هڪ ملٽي ٿريڊ پروگرام لکندا آهيو، ڪجهه واقعا ٻين کان 100 سيڪڙو اڳ واقع ٿيندا، ۽ اهو ته آپريشن جي سلسلي ۾ هميشه انهن تبديلين کان آگاهه هوندو جيڪي ٿريڊ 2آپريشن دوران ڪيون . اچو ته انهن جو جائزو وٺون. BA1

ضابطو 1.

هڪ ميوٽڪس جاري ڪرڻ کان اڳ ٿئي ٿو ساڳئي مانيٽر ٻئي سلسلي طرفان حاصل ڪيو وڃي. منهنجو خيال آهي ته توهان هتي سڀ ڪجهه سمجهي رهيا آهيو. جيڪڏهن ڪنهن شئي يا ڪلاس جو ميوٽڪس هڪ ٿريڊ ذريعي حاصل ڪيو وڃي، مثال طور، thread ذريعي A، ٻيو ڌاڳو (thread B) ان کي ساڳئي وقت حاصل نٿو ڪري سگهي. اهو انتظار ڪرڻ گهرجي جيستائين ميوٽڪس جاري ڪيو وڃي.

ضابطو 2.

طريقو اڳ ۾ ٿيندوThread.start() آهي . ٻيهر، هتي ڪجھ به ڏکيو ناهي. توھان اڳ ۾ ئي ڄاڻو ٿا ته طريقي جي اندر ڪوڊ کي هلائڻ شروع ڪرڻ لاء ، توھان کي سڏڻ گھرجي ٿريڊ تي طريقو. خاص طور تي، شروعات جو طريقو، نه خود طريقو! اهو قاعدو يقيني بڻائي ٿو ته سڀني متغيرن جا قدر جيڪي اڳ ۾ مقرر ڪيا ويا آهن، هڪ ڀيرو شروع ٿيندي طريقي جي اندر نظر اينديون . Thread.run()run()start()run()Thread.start()run()

ضابطو 3.

run()طريقي جي پڇاڙي طريقي جي واپسي کان اڳ ٿيندي آهيjoin() . اچو ته اسان جي ٻن موضوعن ڏانهن موٽون: A۽ B. اسان ان join()طريقي کي سڏيندا آهيون ته جيئن ٿريڊ ان جي ڪم ڪرڻ کان اڳ Bٿريڊ جي مڪمل ٿيڻ جو انتظار ڪرڻ جي ضمانت آهي . Aهن جو مطلب آهي ته A اعتراض جو run()طريقو تمام آخر تائين هلائڻ جي ضمانت آهي. ۽ ڊيٽا ۾ سڀ تبديليون جيڪي run()ٿريڊ جي طريقي ۾ ٿينديون Aآهن، سو سيڪڙو ضمانت آهي ته ٿريڊ ۾ نظر اينديون Bهڪ دفعو اهو مڪمل ٿيڻ کان پوءِ ٿريڊ Aجي ڪم جي مڪمل ٿيڻ جي انتظار ۾ ته جيئن اهو پنهنجو ڪم شروع ڪري سگهي.

ضابطو 4.

هڪ volatileمتغير ڏانهن لکڻ ان ساڳئي متغير مان پڙهڻ کان اڳ ٿئي ٿو . جڏهن اسان volatileلفظ استعمال ڪندا آهيون، اسان اصل ۾ هميشه موجوده قيمت حاصل ڪندا آهيون. جيتوڻيڪ هڪ longيا سان double(اسان اڳ ۾ ئي مسئلن بابت ڳالهايو جيڪي هتي ٿي سگهن ٿيون). جيئن توهان اڳ ۾ ئي سمجهي چڪا آهيو، ڪجهه موضوعن تي ڪيل تبديليون هميشه ٻين موضوعن تي نظر نه اينديون آهن. پر، يقينا، اتي تمام گهڻيون حالتون آهن جتي اهڙي رويي اسان کي مناسب ناهي. فرض ڪريو ته اسان ٿريڊ تي هڪ متغير جي قيمت مقرر ڪريون ٿا A:

int z;.

z = 555;
جيڪڏهن اسان جي سلسلي کي ڪنسول تي متغير Bجي قيمت ڏيکارڻ گهرجي ، اهو آساني سان 0 ڏيکاري سگهي ٿو، ڇاڪاڻ ته اهو مقرر ڪيل قيمت بابت نه ڄاڻندو آهي. zپر ضابطو 4 ضمانت ڏئي ٿو ته جيڪڏهن اسان zمتغير کي اعلان ڪريون ٿا volatile، پوء هڪ ٿريڊ تي ان جي قيمت ۾ تبديليون هميشه ٻئي ٿريڊ تي نظر اينديون. جيڪڏهن اسان لفظ کي volatileاڳئين ڪوڊ ۾ شامل ڪيو ...

volatile int z;.

z = 555;
...پوءِ اسان ان صورتحال کي روڪيون ٿا جتي ٿريڊ B0 ڏيکاري سگھي ٿي. volatileمتغيرن تي لکڻ انھن مان پڙھڻ کان اڳ ٿئي ٿو.
تبصرا
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION