وہ مسائل جو ملٹی تھریڈنگ جاوا میں حل کرتی ہیں۔
بنیادی طور پر، جاوا ملٹی تھریڈنگ دو اہم مسائل کو حل کرنے کے لیے ایجاد کی گئی تھی۔-
ایک ہی وقت میں متعدد اعمال انجام دیں۔
مندرجہ بالا مثال میں، مختلف دھاگوں (یعنی خاندان کے افراد) نے متوازی طور پر کئی اعمال انجام دیے: برتن دھوئے، دکان پر گئے، چیزیں جوڑیں۔
ایک اور "پروگرامر" کی مثال دی جا سکتی ہے۔ تصور کریں کہ آپ کے پاس یوزر انٹرفیس والا پروگرام ہے۔ جب جاری رکھیں بٹن پر کلک کیا جاتا ہے، تو پروگرام کے اندر کچھ حسابات ہونے چاہئیں، اور صارف کو درج ذیل انٹرفیس اسکرین نظر آنی چاہیے۔ اگر یہ کارروائیاں ترتیب وار کی جاتی ہیں، تو "جاری رکھیں" کے بٹن پر کلک کرنے کے بعد، پروگرام آسانی سے منجمد ہو جائے گا۔ صارف ایک ہی اسکرین کو "جاری رکھیں" کے بٹن کے ساتھ دیکھے گا جب تک کہ تمام اندرونی حسابات مکمل نہیں ہو جاتے اور پروگرام اس حصے تک پہنچ جاتا ہے جہاں انٹرفیس تیار ہونا شروع ہو جاتا ہے۔
ٹھیک ہے، چلو چند منٹ انتظار کریں!
ہم اپنے پروگرام کو بھی دوبارہ بنا سکتے ہیں، یا جیسا کہ پروگرامرز کہتے ہیں، "متوازی بنائیں۔" ضروری حسابات ایک تھریڈ میں اور دوسرے میں انٹرفیس رینڈرنگ کرنے دیں۔ زیادہ تر کمپیوٹرز کے پاس اس کے لیے کافی وسائل ہوتے ہیں۔ اس صورت میں، پروگرام "احمقانہ" نہیں ہوگا، اور صارف سکون سے انٹرفیس اسکرینوں کے درمیان اس بات کی فکر کیے بغیر کہ اندر کیا ہو رہا ہے۔ یہ مداخلت نہیں کرتا :)
-
حسابات کو تیز کریں۔
یہاں سب کچھ بہت آسان ہے۔ اگر ہمارے پروسیسر میں کئی کور ہیں، اور زیادہ تر پروسیسرز اب ملٹی کور ہیں، تو ہمارے کاموں کی فہرست کو متوازی طور پر کئی کور کے ذریعے حل کیا جا سکتا ہے۔ ظاہر ہے، اگر ہمیں 1000 مسائل کو حل کرنے کی ضرورت ہے اور ان میں سے ہر ایک کو ایک سیکنڈ میں حل کیا جاتا ہے، تو ایک کور 1000 سیکنڈ میں، دو کور 500 سیکنڈ میں، تین صرف 333 سیکنڈ میں، وغیرہ۔
Thread
۔ یعنی 10 تھریڈز بنانے اور چلانے کے لیے آپ کو اس کلاس کی 10 اشیاء کی ضرورت ہوگی۔ آئیے سب سے آسان مثال لکھتے ہیں:
public class MyFirstThread extends Thread {
@Override
public void run() {
System.out.println("I'm Thread! My name is " + getName());
}
}
تھریڈز بنانے اور لانچ کرنے کے لیے، ہمیں ایک کلاس بنانے اور اسے وراثت سے حاصل کرنے کی ضرورت ہے java.lang
۔ Thread
اور اس میں طریقہ کو اوور رائیڈ کریں run()
۔ آخری بہت اہم ہے۔ یہ اس طریقہ کار میں ہے کہ run()
ہم وہ منطق تجویز کرتے ہیں جس پر ہمارے تھریڈ کو عمل کرنا چاہیے۔ اب، اگر ہم ایک مثال بناتے ہیں MyFirstThread
اور اسے چلاتے ہیں، تو طریقہ run()
کنسول پر اپنے نام کے ساتھ ایک لائن پرنٹ کرے گا: طریقہ getName()
دھاگے کا "سسٹم" نام پرنٹ کرتا ہے، جو خود بخود تفویض ہو جاتا ہے۔ اگرچہ، اصل میں، کیوں "اگر"؟ آئیے بنائیں اور جانچیں!
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
MyFirstThread thread = new MyFirstThread();
thread.start();
}
}
}
کنسول آؤٹ پٹ: میں تھریڈ ہوں! میرا نام تھریڈ 2 ہے میں تھریڈ ہوں! میرا نام تھریڈ ہے-1 میں تھریڈ ہوں! میرا نام تھریڈ ہے-0 میں تھریڈ ہوں! میرا نام تھریڈ 3 ہے میں تھریڈ ہوں! میرا نام تھریڈ 6 ہے میں تھریڈ ہوں! میرا نام تھریڈ 7 ہے میں تھریڈ ہوں! میرا نام تھریڈ 4 ہے میں تھریڈ ہوں! میرا نام تھریڈ 5 ہے میں تھریڈ ہوں! میرا نام تھریڈ 9 ہے میں تھریڈ ہوں! میرا نام ہے Thread-8 ہم 10 دھاگے (آبجیکٹ) بناتے ہیں MyFirstThread
جو ان سے وراثت میں آتے ہیں Thread
اور آبجیکٹ کے طریقہ کو کال کرکے لانچ کرتے ہیں start()
۔ کسی میتھڈ کو کال کرنے کے بعد start()
اس کا طریقہ کام کرنا شروع کر دیتا ہے run()
اور اس میں جو منطق لکھی تھی اس پر عمل ہوتا ہے۔ براہ کرم نوٹ کریں: دھاگے کے نام ترتیب میں نہیں ہیں۔ یہ بہت عجیب بات ہے، ان کو بدلے میں پھانسی کیوں نہیں دی گئی: , Thread-0
اور اسی طرح؟ یہ بالکل اس کی ایک مثال ہے جب معیاری، "ترتیباتی" سوچ کام نہیں کرے گی۔ حقیقت یہ ہے کہ اس معاملے میں ہم صرف 10 تھریڈز بنانے اور لانچ کرنے کے لیے کمانڈ جاری کرتے ہیں۔ انہیں کس ترتیب میں لانچ کیا جانا چاہئے اس کا فیصلہ تھریڈ شیڈیولر کرتا ہے: آپریٹنگ سسٹم کے اندر ایک خاص طریقہ کار۔ یہ کس طرح ترتیب دیا گیا ہے اور یہ کس اصول پر فیصلے کرتا ہے یہ ایک بہت پیچیدہ موضوع ہے، اور ہم اب اس میں غوطہ نہیں لگائیں گے۔ یاد رکھنے کی اہم بات یہ ہے کہ پروگرامر تھریڈ پر عمل درآمد کی ترتیب کو کنٹرول نہیں کر سکتا۔ صورت حال کی سنگینی کا احساس کرنے کے لیے، اوپر دی گئی مثال سے ایک دو بار مزید طریقہ کو چلانے کی کوشش کریں۔ دوسرا کنسول آؤٹ پٹ: میں تھریڈ ہوں! میرا نام تھریڈ ہے-0 میں تھریڈ ہوں! میرا نام تھریڈ 4 ہے میں تھریڈ ہوں! میرا نام تھریڈ 3 ہے میں تھریڈ ہوں! میرا نام تھریڈ 2 ہے میں تھریڈ ہوں! میرا نام تھریڈ ہے-1 میں تھریڈ ہوں! میرا نام تھریڈ 5 ہے میں تھریڈ ہوں! میرا نام تھریڈ 6 ہے میں تھریڈ ہوں! میرا نام تھریڈ 8 ہے میں تھریڈ ہوں! میرا نام تھریڈ 9 ہے میں تھریڈ ہوں! میرا نام تھریڈ 7 ہے تھرڈ کنسول آؤٹ پٹ: میں تھریڈ ہوں! میرا نام تھریڈ ہے-0 میں تھریڈ ہوں! میرا نام تھریڈ 3 ہے میں تھریڈ ہوں! میرا نام تھریڈ ہے-1 میں تھریڈ ہوں! میرا نام تھریڈ 2 ہے میں تھریڈ ہوں! میرا نام تھریڈ 6 ہے میں تھریڈ ہوں! میرا نام تھریڈ 4 ہے میں تھریڈ ہوں! میرا نام تھریڈ 9 ہے میں تھریڈ ہوں! میرا نام تھریڈ 5 ہے میں تھریڈ ہوں! میرا نام تھریڈ 7 ہے میں تھریڈ ہوں! میرا نام Thread-8 ہے۔Thread-1
Thread-2
main()
ملٹی تھریڈنگ سے پیدا ہونے والے مسائل
کتابوں کے ساتھ مثال میں، آپ نے دیکھا کہ ملٹی تھریڈنگ کافی اہم مسائل کو حل کرتی ہے، اور اس کا استعمال ہمارے پروگراموں کے کام کو تیز کرتا ہے۔ بہت سے معاملات میں - کئی بار. لیکن یہ کچھ بھی نہیں ہے کہ ملٹی تھریڈنگ کو ایک پیچیدہ موضوع سمجھا جاتا ہے۔ سب کے بعد، اگر غلط طریقے سے استعمال کیا جاتا ہے، تو یہ ان کو حل کرنے کے بجائے مسائل پیدا کرتا ہے. جب میں کہتا ہوں کہ "مسائل پیدا کریں"، تو میرا مطلب کچھ خلاصہ نہیں ہے۔ دو مخصوص مسائل ہیں جو ملٹی تھریڈنگ کا سبب بن سکتے ہیں: تعطل اور ریس کی حالت۔ تعطل ایک ایسی صورتحال ہے جس میں متعدد دھاگے ایک دوسرے کے زیر قبضہ وسائل کا انتظار کر رہے ہیں، اور ان میں سے کوئی بھی عملدرآمد جاری نہیں رکھ سکتا۔ ہم مستقبل کے لیکچرز میں اس کے بارے میں مزید بات کریں گے، لیکن ابھی کے لیے یہ مثال کافی ہوگی: تصور کریں کہ تھریڈ-1 کسی آبجیکٹ-1 کے ساتھ کام کر رہا ہے، اور تھریڈ-2 آبجیکٹ-2 کے ساتھ کام کر رہا ہے۔ پروگرام اس طرح لکھا ہے:- تھریڈ-1 آبجیکٹ-1 کے ساتھ کام کرنا بند کر دے گا اور جیسے ہی تھریڈ-2 آبجیکٹ 2 کے ساتھ کام کرنا بند کر دے گا اور آبجیکٹ-1 پر سوئچ کر دے گا۔
- تھریڈ-2 آبجیکٹ-2 کے ساتھ کام کرنا بند کر دے گا اور جیسے ہی تھریڈ-1 آبجیکٹ 1 کے ساتھ کام کرنا بند کر دے گا اور آبجیکٹ-2 پر سوئچ کر دے گا۔
public class MyFirstThread extends Thread {
@Override
public void run() {
System.out.println("Выполнен поток " + getName());
}
}
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
MyFirstThread thread = new MyFirstThread();
thread.start();
}
}
}
اب تصور کریں کہ یہ پروگرام ایک روبوٹ کے آپریشن کا ذمہ دار ہے جو کھانا تیار کرتا ہے! تھریڈ-0 انڈوں کو ریفریجریٹر سے باہر لے جاتا ہے۔ سٹریم 1 چولہے پر موڑ دیتا ہے۔ Stream-2 ایک کڑاہی نکال کر چولہے پر رکھتا ہے۔ سٹریم 3 چولہے پر آگ جلاتی ہے۔ سٹریم 4 پین میں تیل ڈالتا ہے۔ سٹریم 5 انڈوں کو توڑ کر فرائنگ پین میں ڈال دیتی ہے۔ سٹریم 6 گولے کو کوڑے دان میں پھینک دیتا ہے۔ Stream-7 تیار شدہ سکیمبلڈ انڈوں کو گرمی سے ہٹاتا ہے۔ Potok-8 ایک پلیٹ میں سکیمبلڈ انڈے رکھتا ہے۔ Stream-9 برتن دھوتا ہے۔ ہمارے پروگرام کے نتائج دیکھیں: Thread-0 executed Thread-2 thread executed Thread-1 thread executed Thread-4 thread executed Thread-9 thread executed Thread-5 thread executed Thread-8 thread executed Thread-7 thread executed Thread-7 دھاگے کو پھانسی دی گئی -3 تھریڈ-6 تھریڈ کو پھانسی دی گئی۔ کیا اسکرپٹ تفریحی ہے؟ :) اور یہ سب اس لیے کہ ہمارے پروگرام کے آپریشن کا انحصار اس ترتیب پر ہے جس میں تھریڈز کو عمل میں لایا جاتا ہے۔ ترتیب کی معمولی سی خلاف ورزی پر، ہمارا باورچی خانہ جہنم میں بدل جاتا ہے، اور ایک پاگل روبوٹ اس کے آس پاس کی ہر چیز کو تباہ کر دیتا ہے۔ ملٹی تھریڈ پروگرامنگ میں یہ بھی ایک عام مسئلہ ہے جس کے بارے میں آپ ایک سے زیادہ بار سنیں گے۔ لیکچر کے اختتام پر، میں آپ کو ملٹی تھریڈنگ پر ایک کتاب تجویز کرنا چاہوں گا۔
GO TO FULL VERSION