مشکلات با چند رشته حل می شود
Multithreading در واقع برای دستیابی به دو هدف مهم اختراع شد:-
چندین کار را همزمان انجام دهید.
در مثال بالا، نخ های مختلف (اعضای خانواده) چندین عمل را به طور موازی انجام دادند: ظرف ها را می شستند، به فروشگاه می رفتند و وسایل را بسته بندی می کردند.
ما می توانیم مثالی را ارائه دهیم که بیشتر به برنامه نویسی مرتبط است. فرض کنید یک برنامه با رابط کاربری دارید. هنگامی که روی "ادامه" در برنامه کلیک می کنید، باید محاسباتی انجام شود و کاربر باید صفحه زیر را ببیند. اگر این اقدامات به صورت متوالی انجام می شد، پس از اینکه کاربر روی دکمه «ادامه» کلیک کرد، برنامه متوقف می شد. کاربر صفحه را با صفحه دکمه "ادامه" می بیند تا زمانی که برنامه تمام محاسبات داخلی را انجام دهد و به قسمتی که رابط کاربری در آن به روز می شود برسد.
خوب، حدس می زنم چند دقیقه صبر کنیم!
یا میتوانیم برنامهمان را دوباره کار کنیم، یا به قول برنامهنویسها، آن را «موازی» کنیم. بیایید محاسبات خود را روی یک رشته انجام دهیم و رابط کاربری را روی دیگری ترسیم کنیم. اکثر کامپیوترها منابع کافی برای انجام این کار را دارند. اگر این مسیر را در پیش بگیریم، برنامه مسدود نمیشود و کاربر به آرامی بین صفحهها حرکت میکند، بدون اینکه نگران اتفاقات داخل آن باشد. یکی با دیگری تداخل ندارد :)
-
محاسبات را با سرعت بیشتری انجام دهید.
همه چیز در اینجا بسیار ساده تر است. اگر پردازنده ما چندین هسته داشته باشد، و اکثر پردازنده های امروزی این کار را انجام می دهند، چندین هسته می توانند لیست وظایف ما را به صورت موازی انجام دهند. بدیهی است که اگر نیاز به انجام 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 تبدیل کنیم . کلاس Thread کنید و متد run() آن را لغو کنید . این آخرین نیاز بسیار مهم است. در متد run() است که ما منطقی را برای اجرای رشته خود تعریف می کنیم. حال، اگر نمونهای از MyFirstThread را ایجاد و اجرا کنیم ، متد run() خطی را با نام نمایش میدهد: متد getName() نام «system» رشته را نمایش میدهد که به طور خودکار اختصاص داده میشود. اما چرا ما به طور آزمایشی صحبت می کنیم؟ بیایید یکی بسازیم و بفهمیم!
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
MyFirstThread thread = new MyFirstThread();
thread.start();
}
}
}
خروجی کنسول: I'm Thread! نام من Thread-2 است I'm Thread! نام من Thread-1 است I'm Thread! نام من Thread-0 است من موضوع هستم! نام من Thread-3 است I'm Thread! نام من Thread-6 است I'm Thread! نام من Thread-7 است I'm Thread! نام من Thread-4 است I'm Thread! نام من Thread-5 است I'm Thread! نام من Thread-9 است I'm Thread! نام من Thread-8 است، بیایید 10 رشته ( اشیاء MyFirstThread ، که Thread را به ارث می برند) ایجاد کنیم و با فراخوانی متد start() روی هر شی شروع کنیم . پس از فراخوانی متد start() منطق در متد run() اجرا می شود. توجه: نام تاپیک ها به ترتیب نیست. عجیب است که آنها به صورت متوالی نبودند: Thread-0 ، Thread-1 ، Thread-2 ، و غیره؟ همانطور که اتفاق می افتد، این نمونه ای از زمانی است که تفکر «متوالی» مناسب نیست. مسئله این است که ما فقط دستوراتی برای ایجاد و اجرای 10 رشته ارائه کرده ایم. زمانبندی رشته، مکانیزم سیستم عامل ویژه، ترتیب اجرای آنها را تعیین می کند. طراحی دقیق و استراتژی تصمیم گیری آن موضوعاتی برای یک بحث عمیق است که ما در حال حاضر به آن نمی پردازیم. نکته اصلی این است که برنامه نویس نمی تواند ترتیب اجرای رشته ها را کنترل کند. برای درک جدی بودن وضعیت، متد main() در مثال بالا را چند بار دیگر اجرا کنید. خروجی کنسول در اجرای دوم: I'm Thread! نام من Thread-0 است من موضوع هستم! نام من Thread-4 است I'm Thread! نام من Thread-3 است I'm Thread! نام من Thread-2 است I'm Thread! نام من Thread-1 است I'm Thread! نام من Thread-5 است I'm Thread! نام من Thread-6 است I'm Thread! نام من Thread-8 است I'm Thread! نام من Thread-9 است I'm Thread! نام من خروجی کنسول Thread-7 از اجرای سوم است: من Thread هستم! نام من Thread-0 است من موضوع هستم! نام من Thread-3 است I'm Thread! نام من Thread-1 است I'm Thread! نام من Thread-2 است I'm Thread! نام من Thread-6 است I'm Thread! نام من Thread-4 است I'm Thread! نام من Thread-9 است I'm Thread! نام من Thread-5 است I'm Thread! نام من Thread-7 است I'm Thread! نام من Thread-8 است
مشکلات ایجاد شده توسط multithreading
در مثال ما با کتاب ها، دیدید که چند رشته ای وظایف بسیار مهمی را حل می کند و می تواند برنامه های ما را سریعتر کند. اغلب چندین برابر سریعتر. اما چند رشته ای موضوعی دشوار در نظر گرفته می شود. در واقع، در صورت استفاده نادرست، به جای حل آن، مشکلاتی را ایجاد می کند. وقتی می گویم «مشکلات ایجاد می کند»، منظورم به معنای انتزاعی نیست. دو مشکل خاص وجود دارد که multithreading می تواند ایجاد کند: بن بست و شرایط مسابقه. بن بست وضعیتی است که در آن چندین رشته منتظر منابعی هستند که توسط یکدیگر نگهداری می شوند و هیچ یک از آنها نمی توانند به کار خود ادامه دهند. در درس های بعدی بیشتر در مورد آن صحبت خواهیم کرد. مثال زیر در حال حاضر کافی است:
- Thread-1 تعامل با Object-1 را متوقف می کند و به محض اینکه Thread-2 تعامل با Object-2 را متوقف می کند به Object-2 تغییر می کند و به Object-1 تغییر می کند.
- Thread-2 تعامل با Object-2 را متوقف می کند و به محض اینکه Thread-1 تعامل با Object-1 را متوقف می کند به Object-1 تغییر می کند و به Object-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();
}
}
}
حال تصور کنید که این برنامه وظیفه اجرای رباتی را دارد که غذا می پزد! Thread-0 تخم مرغ ها را از یخچال خارج می کند. نخ-1 اجاق گاز را روشن می کند. Thread-2 یک ماهیتابه می گیرد و روی اجاق می گذارد. نخ 3 اجاق گاز را روشن می کند. نخ 4 داخل تابه روغن می ریزد. نخ 5 تخم مرغ ها را می شکند و داخل تابه می ریزیم. نخ 6 پوسته های تخم مرغ را داخل سطل زباله می اندازد. Thread-7 تخم مرغ های پخته شده را از مشعل خارج می کند. Thread-8 تخم مرغ های پخته شده را در یک بشقاب قرار می دهد. Thread-9 ظروف را می شویند. به نتایج برنامه ما نگاه کنید: Thread executed: Thread-0 Thread executed: Thread-2 Thread executed Thread-1 Thread executed: Thread-4 Thread executed: Thread-9 Thread executed: Thread-5 Thread executed: Thread-8 executed: Thread-7 Thread executed: Thread-3 آیا این یک روال کمدی است؟ :) و همه به این دلیل که کار برنامه ما به ترتیب اجرای نخ ها بستگی دارد. با کوچکترین نقض توالی لازم، آشپزخانه ما به جهنم تبدیل می شود و یک ربات دیوانه همه چیز را در اطراف خود نابود می کند. این نیز یک مشکل رایج در برنامه نویسی چند رشته ای است. بیش از یک بار در مورد آن خواهید شنید. در پایان این درس، میخواهم کتابی را در مورد چند رشتهای توصیه کنم. 
GO TO FULL VERSION