ملٹی تھریڈنگ کے ذریعے مسائل حل ہوتے ہیں۔
ملٹی تھریڈنگ دراصل دو اہم مقاصد کے حصول کے لیے ایجاد کی گئی تھی۔-
ایک ہی وقت میں کئی چیزیں کریں۔
مندرجہ بالا مثال میں، مختلف تھریڈز (خاندان کے ارکان) نے متوازی طور پر کئی اعمال انجام دیے: انہوں نے برتن دھوئے، دکان پر گئے، اور چیزیں پیک کیں۔
ہم پروگرامنگ سے زیادہ قریب سے متعلق ایک مثال پیش کر سکتے ہیں۔ فرض کریں کہ آپ کے پاس یوزر انٹرفیس والا پروگرام ہے۔ جب آپ پروگرام میں 'جاری رکھیں' پر کلک کرتے ہیں، تو کچھ حساب کتاب ہونا چاہیے اور صارف کو درج ذیل اسکرین نظر آنی چاہیے۔ اگر یہ کارروائیاں ترتیب وار انجام دی جائیں، تو صارف کے 'جاری رکھیں' کے بٹن پر کلک کرنے کے بعد ہی پروگرام لٹک جائے گا۔ صارف اس وقت تک 'جاری رکھیں' بٹن اسکرین کے ساتھ اسکرین کو دیکھے گا جب تک کہ پروگرام تمام اندرونی حسابات کو انجام نہیں دیتا اور اس حصے تک نہیں پہنچ جاتا جہاں صارف کا انٹرفیس ریفریش ہوتا ہے۔
ٹھیک ہے، مجھے لگتا ہے کہ ہم چند منٹ انتظار کریں گے!
یا ہم اپنے پروگرام کو دوبارہ کام کر سکتے ہیں، یا جیسا کہ پروگرامرز کہتے ہیں، اسے 'متوازی' بنا سکتے ہیں۔ آئیے ایک تھریڈ پر اپنا حساب لگاتے ہیں اور دوسرے پر یوزر انٹرفیس کھینچتے ہیں۔ زیادہ تر کمپیوٹرز کے پاس ایسا کرنے کے لیے کافی وسائل ہوتے ہیں۔ اگر ہم یہ راستہ اختیار کرتے ہیں، تو پروگرام منجمد نہیں ہو گا اور صارف اندر کیا ہو رہا ہے اس کی فکر کیے بغیر اسکرینوں کے درمیان آسانی سے حرکت کرے گا۔ ایک دوسرے کے ساتھ مداخلت نہیں کرتا :)
-
حسابات کو زیادہ تیزی سے انجام دیں۔
یہاں سب کچھ بہت آسان ہے۔ اگر ہمارے پروسیسر میں ایک سے زیادہ کور ہیں، اور آج زیادہ تر پروسیسرز کرتے ہیں، تو کئی کور ہمارے کاموں کی فہرست کو متوازی طور پر سنبھال سکتے ہیں۔ ظاہر ہے، اگر ہمیں 1000 کاموں کو انجام دینے کی ضرورت ہے اور ہر ایک میں ایک سیکنڈ لگتا ہے، تو ایک کور 1000 سیکنڈ میں فہرست کو ختم کر سکتا ہے، دو کور 500 سیکنڈ میں، تین 333 سیکنڈ سے کچھ زیادہ میں، وغیرہ۔
public class MyFirstThread extends Thread {
@Override
public void run() {
System.out.println("I'm Thread! My name is " + getName());
}
}
تھریڈز بنانے اور چلانے کے لیے، ہمیں ایک کلاس بنانے کی ضرورت ہے، اسے java.lang کا وارث بنانا ہوگا ۔ تھریڈ کلاس، اور اس کے 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() طریقہ کو کال کرکے انہیں شروع کریں۔ اسٹارٹ() میتھڈ کو کال کرنے کے بعد رن() میتھڈ میں لاجک پر عمل درآمد ہوتا ہے۔ نوٹ: تھریڈ کے نام ترتیب میں نہیں ہیں۔ یہ عجیب بات ہے کہ وہ ترتیب وار نہیں تھے: Thread-0 ، Thread-1 ، Thread-2 ، وغیرہ؟ جیسا کہ یہ ہوتا ہے، یہ اس وقت کی ایک مثال ہے جب 'ترتیباتی' سوچ فٹ نہیں ہوتی ہے۔ مسئلہ یہ ہے کہ ہم نے صرف 10 تھریڈز بنانے اور چلانے کے لیے کمانڈ فراہم کیے ہیں۔ تھریڈ شیڈیولر، ایک خصوصی آپریٹنگ سسٹم میکانزم، ان کے عمل درآمد کے آرڈر کا فیصلہ کرتا ہے۔ اس کا قطعی ڈیزائن اور فیصلہ سازی کی حکمت عملی ایک گہری بحث کے عنوانات ہیں جن پر ہم ابھی غور نہیں کریں گے۔ یاد رکھنے کی اہم بات یہ ہے کہ پروگرامر تھریڈز کے عمل درآمد کے آرڈر کو کنٹرول نہیں کر سکتا۔ صورت حال کی سنگینی کو سمجھنے کے لیے، اوپر کی مثال میں مین() طریقہ کو ایک دو بار مزید چلانے کی کوشش کریں۔ دوسرے رن پر کنسول آؤٹ پٹ: میں تھریڈ ہوں! میرا نام تھریڈ ہے-0 میں تھریڈ ہوں! میرا نام تھریڈ 4 ہے میں تھریڈ ہوں! میرا نام تھریڈ 3 ہے میں تھریڈ ہوں! میرا نام تھریڈ 2 ہے میں تھریڈ ہوں! میرا نام تھریڈ ہے-1 میں تھریڈ ہوں! میرا نام تھریڈ 5 ہے میں تھریڈ ہوں! میرا نام تھریڈ 6 ہے میں تھریڈ ہوں! میرا نام تھریڈ 8 ہے میں تھریڈ ہوں! میرا نام تھریڈ 9 ہے میں تھریڈ ہوں! میرا نام تھریڈ 7 کنسول کی تیسری رن سے آؤٹ پٹ ہے: میں تھریڈ ہوں! میرا نام تھریڈ ہے-0 میں تھریڈ ہوں! میرا نام تھریڈ 3 ہے میں تھریڈ ہوں! میرا نام تھریڈ ہے-1 میں تھریڈ ہوں! میرا نام تھریڈ 2 ہے میں تھریڈ ہوں! میرا نام تھریڈ 6 ہے میں تھریڈ ہوں! میرا نام تھریڈ 4 ہے میں تھریڈ ہوں! میرا نام تھریڈ 9 ہے میں تھریڈ ہوں! میرا نام تھریڈ 5 ہے میں تھریڈ ہوں! میرا نام تھریڈ 7 ہے میں تھریڈ ہوں! میرا نام Thread-8 ہے۔
ملٹی تھریڈنگ سے پیدا ہونے والے مسائل
کتابوں کے ساتھ ہماری مثال میں، آپ نے دیکھا کہ ملٹی تھریڈنگ بہت اہم کاموں کو حل کرتی ہے اور ہمارے پروگراموں کو تیز تر بنا سکتی ہے۔ اکثر کئی گنا تیز۔ لیکن ملٹی تھریڈنگ ایک مشکل موضوع سمجھا جاتا ہے۔ درحقیقت، اگر غلط طریقے سے استعمال کیا جاتا ہے، تو یہ ان کو حل کرنے کے بجائے مسائل پیدا کرتا ہے. جب میں کہتا ہوں کہ 'مسائل پیدا کرتا ہے'، میرا مطلب کسی تجریدی معنوں میں نہیں ہے۔ دو مخصوص مسائل ہیں جو ملٹی تھریڈنگ پیدا کر سکتے ہیں: تعطل اور ریس کے حالات۔ تعطل ایک ایسی صورت حال ہے جہاں متعدد دھاگے ایک دوسرے کے پاس موجود وسائل کے منتظر ہیں، اور ان میں سے کوئی بھی چلنا جاری نہیں رکھ سکتا۔ ہم اگلے اسباق میں اس کے بارے میں مزید بات کریں گے۔ درج ذیل مثال ابھی کے لیے کافی ہوگی:
- تھریڈ-1 آبجیکٹ-1 کے ساتھ تعامل کرنا بند کر دیتا ہے اور جیسے ہی تھریڈ-2 آبجیکٹ-2 کے ساتھ تعامل کرنا بند کر دیتا ہے اور آبجیکٹ-1 پر سوئچ کرتا ہے۔
- تھریڈ-2 آبجیکٹ-2 کے ساتھ تعامل کرنا بند کر دیتا ہے اور جیسے ہی تھریڈ-1 آبجیکٹ-1 کے ساتھ تعامل کرنا بند کر دیتا ہے اور آبجیکٹ-2 پر سوئچ کرتا ہے۔
public class MyFirstThread extends Thread {
@Override
public void run() {
System.out.println("Thread executed: " + 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 چولہا آن کر دیتا ہے۔ تھریڈ -2 ایک پین حاصل کرتا ہے اور اسے چولہے پر رکھتا ہے۔ تھریڈ-3 چولہے کو روشن کرتا ہے۔ تھریڈ-4 پین میں تیل ڈالتا ہے۔ تھریڈ-5 انڈوں کو توڑ کر پین میں ڈالتا ہے۔ تھریڈ-6 انڈے کے چھلکوں کو کوڑے دان میں پھینک دیتا ہے۔ تھریڈ-7 برنر سے پکے ہوئے انڈوں کو ہٹاتا ہے۔ تھریڈ-8 پکے ہوئے انڈے کو پلیٹ میں رکھتا ہے۔ Thread-9 برتن دھوتا ہے۔ ہمارے پروگرام کے نتائج دیکھیں: تھریڈ ایگزیکیٹڈ: تھریڈ-0 تھریڈ ایگزیکیٹڈ: تھریڈ-2 تھریڈ ایگزیکیٹڈ تھریڈ-1 تھریڈ ایگزیکیوٹڈ: تھریڈ-4 تھریڈ ایگزیکیٹڈ: تھریڈ-9 تھریڈ ایگزیکیٹڈ: تھریڈ-5 تھریڈ ایگزیکیٹڈ: تھریڈ-8 تھریڈ executed: Thread-7 Thread executed: Thread-3 کیا یہ کامیڈی کا معمول ہے؟ :) اور یہ سب اس لیے کہ ہمارے پروگرام کا کام تھریڈز کی ترتیب پر منحصر ہے۔ مطلوبہ ترتیب کی معمولی سی خلاف ورزی کے پیش نظر، ہمارا باورچی خانہ جہنم میں بدل جاتا ہے، اور ایک پاگل روبوٹ اپنے اردگرد کی ہر چیز کو تباہ کر دیتا ہے۔ ملٹی تھریڈ پروگرامنگ میں یہ بھی ایک عام مسئلہ ہے۔ آپ اس کے بارے میں ایک سے زیادہ بار سنیں گے۔ اس سبق کو ختم کرتے ہوئے، میں ملٹی تھریڈنگ کے بارے میں ایک کتاب تجویز کرنا چاہوں گا۔ 
GO TO FULL VERSION