CodeGym /وبلاگ جاوا /Random-FA /Multithreading در جاوا
John Squirrels
مرحله
San Francisco

Multithreading در جاوا

در گروه منتشر شد
سلام! اول از همه به شما تبریک می گویم: شما به مبحث Multithreading در جاوا رسیده اید! این یک دستاورد جدی است - شما راه طولانی را پیموده اید. اما خودتان را آماده کنید: این یکی از دشوارترین مباحث دوره است. و این نیست که ما در اینجا از کلاس های پیچیده یا روش های زیادی استفاده می کنیم: در واقع، ما کمتر از بیست مورد استفاده خواهیم کرد. بیشتر این است که باید طرز فکر خود را کمی تغییر دهید. قبلاً برنامه های شما به صورت متوالی اجرا می شد. برخی از خطوط کد پس از برخی دیگر آمدند، برخی از روش ها پس از برخی دیگر آمدند، و همه چیز اساساً واضح بود. ابتدا چیزی را محاسبه کردیم، سپس نتیجه را روی کنسول نمایش دادیم و سپس برنامه به پایان رسید. برای درک چند رشته ای، بهتر است بر حسب موازی فکر کنیم. بیایید با یک چیز کاملاً ساده شروع کنیم :) تصور کنید خانواده شما از یک خانه به خانه دیگر نقل مکان می کنند. جمع آوری تمام کتاب های خود بخش مهمی از حرکت خواهد بود. شما کتاب های زیادی جمع آوری کرده اید و باید آنها را در جعبه ها قرار دهید. در حال حاضر، شما تنها در دسترس هستید. مامان در حال آماده کردن غذا، برادر در حال بسته بندی لباس، و خواهر به فروشگاه رفت. به تنهایی، شما می توانید به نوعی مدیریت کنید. دیر یا زود، این کار را خودتان انجام خواهید داد، اما زمان زیادی طول خواهد کشید. خواهرت تا 20 دقیقه دیگه از مغازه برمیگرده و دیگه کاری نداره. بنابراین او می تواند به شما ملحق شود. کار تغییر نکرده است: کتاب ها را در جعبه ها قرار دهید. اما دو برابر سریعتر اجرا می شود. چرا؟ چون کار به صورت موازی در حال انجام است. دو "رشته" متفاوت (شما و خواهرتان) به طور همزمان یک کار را انجام می دهند. و اگر چیزی تغییر نکند، در مقایسه با موقعیتی که همه کارها را به تنهایی انجام می دهید، تفاوت زمانی بسیار زیادی وجود خواهد داشت. اگر برادر زودتر کارش را تمام کند، می تواند به شما کمک کند و کارها سریعتر پیش می روند.

مشکلات با چند رشته حل می شود

Multithreading در واقع برای دستیابی به دو هدف مهم اختراع شد:
  1. چندین کار را همزمان انجام دهید.

    در مثال بالا، نخ های مختلف (اعضای خانواده) چندین عمل را به طور موازی انجام دادند: ظرف ها را می شستند، به فروشگاه می رفتند و وسایل را بسته بندی می کردند.

    ما می توانیم مثالی را ارائه دهیم که بیشتر به برنامه نویسی مرتبط است. فرض کنید یک برنامه با رابط کاربری دارید. هنگامی که روی "ادامه" در برنامه کلیک می کنید، باید محاسباتی انجام شود و کاربر باید صفحه زیر را ببیند. اگر این اقدامات به صورت متوالی انجام می شد، پس از اینکه کاربر روی دکمه «ادامه» کلیک کرد، برنامه متوقف می شد. کاربر صفحه را با صفحه دکمه "ادامه" می بیند تا زمانی که برنامه تمام محاسبات داخلی را انجام دهد و به قسمتی که رابط کاربری در آن به روز می شود برسد.

    خوب، حدس می زنم چند دقیقه صبر کنیم!

    Multithreading در جاوا: چیست، فواید و مشکلات رایج آن - 3

    یا می‌توانیم برنامه‌مان را دوباره کار کنیم، یا به قول برنامه‌نویس‌ها، آن را «موازی» کنیم. بیایید محاسبات خود را روی یک رشته انجام دهیم و رابط کاربری را روی دیگری ترسیم کنیم. اکثر کامپیوترها منابع کافی برای انجام این کار را دارند. اگر این مسیر را در پیش بگیریم، برنامه مسدود نمی‌شود و کاربر به آرامی بین صفحه‌ها حرکت می‌کند، بدون اینکه نگران اتفاقات داخل آن باشد. یکی با دیگری تداخل ندارد :)

  2. محاسبات را با سرعت بیشتری انجام دهید.

    همه چیز در اینجا بسیار ساده تر است. اگر پردازنده ما چندین هسته داشته باشد، و اکثر پردازنده های امروزی این کار را انجام می دهند، چندین هسته می توانند لیست وظایف ما را به صورت موازی انجام دهند. بدیهی است که اگر نیاز به انجام 1000 کار داشته باشیم و هر کدام یک ثانیه طول بکشد، یک هسته می تواند لیست را در 1000 ثانیه، دو هسته در 500 ثانیه، سه هسته در کمی بیش از 333 ثانیه و غیره به پایان برساند.

اما همانطور که قبلاً در این درس خواندید، سیستم‌های امروزی بسیار هوشمند هستند و حتی در یک هسته محاسباتی می‌توانند به موازی‌سازی یا بهتر بگوییم شبه موازی‌سازی دست یابند که در آن وظایف به طور متناوب انجام می‌شوند. بیایید کلیات را به جزئیات منتقل کنیم و با مهم ترین کلاس در کتابخانه چند رشته ای جاوا - java.lang.Thread آشنا شویم. به طور دقیق، رشته های جاوا با نمونه هایی از کلاس 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() نام «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 می تواند ایجاد کند: بن بست و شرایط مسابقه. بن بست وضعیتی است که در آن چندین رشته منتظر منابعی هستند که توسط یکدیگر نگهداری می شوند و هیچ یک از آنها نمی توانند به کار خود ادامه دهند. در درس های بعدی بیشتر در مورد آن صحبت خواهیم کرد. مثال زیر در حال حاضر کافی است: Multithreading در جاوا: چیست، فواید و مشکلات رایج آن - 4تصور کنید که Thread-1 با برخی از Object-1 تعامل دارد، و Thread-2 با Object-2 تعامل دارد. علاوه بر این، برنامه به گونه ای نوشته شده است:
  1. Thread-1 تعامل با Object-1 را متوقف می کند و به محض اینکه Thread-2 تعامل با Object-2 را متوقف می کند به Object-2 تغییر می کند و به Object-1 تغییر می کند.
  2. Thread-2 تعامل با Object-2 را متوقف می کند و به محض اینکه Thread-1 تعامل با Object-1 را متوقف می کند به Object-1 تغییر می کند و به Object-2 تغییر می کند.
حتی بدون درک عمیق از multithreading، به راحتی می توانید ببینید که هیچ اتفاقی نخواهد افتاد. نخ ها هرگز جای خود را عوض نمی کنند و برای همیشه منتظر یکدیگر می مانند. به نظر می رسد خطا آشکار است، اما در واقعیت اینطور نیست. شما به راحتی می توانید این کار را در یک برنامه انجام دهید. در درس‌های بعدی نمونه‌هایی از کدهایی که باعث بن‌بست می‌شوند را در نظر خواهیم گرفت. به هر حال، Quora یک مثال عالی از زندگی واقعی دارد که توضیح می دهد که بن بست چیست. در برخی از ایالت‌های هند، زمین کشاورزی را به شما نمی‌فروشند مگر اینکه کشاورز ثبت‌شده باشید. با این حال، اگر شما مالک زمین کشاورزی نباشید، آنها شما را به عنوان یک کشاورز ثبت نمی کنند. عالی! چه بگوییم؟! :) حالا بیایید در مورد شرایط مسابقه صحبت کنیم. شرط مسابقه یک خطای طراحی در یک سیستم یا برنامه چند رشته ای است که در آن عملکرد سیستم یا برنامه به ترتیب اجرای بخش هایی از کد بستگی دارد. به یاد داشته باشید، مثال ما که در آن رشته ها را شروع کردیم:
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 آیا این یک روال کمدی است؟ :) و همه به این دلیل که کار برنامه ما به ترتیب اجرای نخ ها بستگی دارد. با کوچکترین نقض توالی لازم، آشپزخانه ما به جهنم تبدیل می شود و یک ربات دیوانه همه چیز را در اطراف خود نابود می کند. این نیز یک مشکل رایج در برنامه نویسی چند رشته ای است. بیش از یک بار در مورد آن خواهید شنید. در پایان این درس، می‌خواهم کتابی را در مورد چند رشته‌ای توصیه کنم. Multithreading در جاوا: چیست، فواید و مشکلات رایج آن - 6"جاوا همزمانی در عمل" در سال 2006 نوشته شد، اما ارتباط خود را از دست نداده است. این برنامه به برنامه نویسی جاوا چند رشته ای اختصاص دارد - از اصول اولیه تا رایج ترین اشتباهات و ضد الگوها. اگر روزی تصمیم گرفتید که یک گورو چند رشته ای شوید، این کتاب حتماً باید بخوانید. در درس های بعدی می بینمت! :)
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION