معرفی و نحوه کار با Thread ها در جاوا

چند نخی (Multi-Threading) مکانیزمی در برنامه نویسی است که امکان می دهد فرآیند ها به طور موازی و یا همزمان اجرا شوند که در نتیجه باعث بهبود سرعت و عملکرد برنامه می شود. اگرچه کار با نخ ها در برنامه های تجاری خیلی معمول نیست اما در فریم ورک های جاوا به وفور مورد استفاده قرار می گیرند. در ادامه نحوه کار با Thread ها در جاوا را توضیح و آموزش خواهیم داد.

به عنوان مثال، فریم ورک هایی که حجم زیادی از اطلاعات را پردازش می کنند، مانند Spring Batch، از نخ ها برای مدیریت داده ها استفاده می کنند. استفاده از نخ ها عملکرد را بهبود می بخشد، درنتیجه برنامه های سریعتر و کارآمدتری ایجاد می شود.

نخ اصلی هر برنامه: نخ main

حتی اگر هرگز مستقیما با نخ های جاوا کار نکرده باشید، همیشه به طور غیر مستقیم با یکی از آن ها کار کرده اید، زیرا متد ()main جاوا حاوی یک نخ اصلی است. هر زمان که متد main را اجرا کردید، شما نخ main را نیز اجرا کرده اید.

مطالعه کلاس Thread برای درک نحوه کار کردن رشته در برنامه های جاوا بسیار مفید است. همانطور که در مثال زیر نشان داده شده است، می توانیم با استفاده از متد های ()currentThread و ()getName به نخ اصلی و نام آن دسترسی پیدا کنیم.

خروجی کد بالا رشته “main” است. نخی که در حال حاضر اجرا می شود. دانستن نحوه شناسایی موضوع در حال اجرا اولین قدم برای درک مفایم چند نخی است.

چرخه زندگی نخ ها یا Thread ها در جاوا

هنگام کار با نخ ها مهم است که از وضعیت نخ مطلع شوید. چرخه طول عمر thread ها در جاوا از 6 حالت تشکیل شده است:

  • جدید (New) : یک نمونه از کلاس Thread ایجاد شده است.
  • آماده اجرا(Runnable) : متد ()start از کلاس نمونه فراخوانی شده است.
  • در حال اجرا(Running) : متد ()start شروع به کار کرده است.
  • تعلیق شده(Suspended) : رشته موقتا به حالت تعلیق درآمده و می تواند توسط نخی دیگری از سر گرفته شود
  • بلاک شده(Blocked) : رشته منتظر فرصتی برای اجرا است. این اتفاق معمولا زمانی می افتد که یک رشته از متد ()synchronized استفاده کرده است و نخ بعدی تا اتمام کار آن باید صبر کند.
  • خاتمه یافته (Terminated) : اجرای نخ کامل شده و به پایان رسیده است.

پردازش همزمان: گسترش کلاس Thread

همانطور که در کد زیر نشان داده شده است، در ساده ترین حالت، پردازش همزمان با گسترش کلاس Thread انجام می شود.

در کد بالا ما 2 نخ را اجرا کرده ایم، نخ main و نخ مربوط به کلاس InheritingThread. هنگامی که متد ()start از کلاس InhertingThread را اجرا کنیم، متد ()run آن کلاس اجرا می شود. در واقع نخ جدید ایجاد می شود.

همچنین ما نام نخ جدید را از طریق سازنده کلاس InheritingThread به آن ارسال کرده ایم. خروجی کد فوق:

واسط Runnable

به جای استفاده از وراثت، می توانید واسط Runnable را پیاده سازی کنید. در این روش کافیست تا کلاسی که واسط را پیاده سازی کرده است را به عنوان آرگومان به سازنده کلاس Thread بفرستیم. این کار باعث اتصال کمتر و انعطاف پذیری بیشتر می شود. برای اجرای آن نیز مانند کلاس Thread، متد ()start را فراخوانی می کنیم.

نخ های daemon و non-daemon

نخ ها از نظر اجرا به دو دسته تقسیم می شوند:

  • نخ های non-daemon : دشته های non-daemon تا انتها اجرا می شوند تا زمانی که ()System.exit برنامه را مجبور به بستن کند. نخ main مثال خوبی برای این نوع نخ ها است که همیشه تا انتها اجرا می شود.
  • نخ های daemon : این نخ ها بر عکس نخ های non-daemon هستند. اساسا فرآیند هایی هستند که لزوما تا انتها اجرا نمی شوند.

نکته: اگر یک نخ non-daemon قبل از یک نخ daemon به پایان برسد، نخ daemon تا انتها اجرا نمی شود.

مثال زیر رابط بین این دو نخ را بهتر نشان داده است:

کد بالا از یک نخ daemon برای تعریف اعداد 1 تا 100000 استفاده کرده و همه آن ها را چاپ می کند. به یاد داشته باشید که اگر نخ main که یک نخ non-daemon است به اتمام برسد، نخ daemon اجرا نمی شود.

مراحل اجرای کد بالا به شکل زیر خواهد بود:

  1. آغاز شدن (start) اجرای نخ main
  2. اجرای نخ daemonThread و شروع کردن به چاپ اعداد 1 تا 100000
  3. پایان نخ main. به احتمال زیاد قبل از تکمیل شدن وظیفه نخ daemonThread (چاپ اعداد) پایان می یابد.

خروجی می تواند برای هر کامپیوتر و JVM ای فرق کند. غیر قابل پیش بینی بودن، یکی از ویژگی های اصلی نخ ها هستند.

اولویت نخ و JVM

اولویت بندی اجرای نخ ها با متد ()setPriorty امکان پذیر است، اما نحوه رسیدگی به آن به  JVM بستگی دارد. لینوکس، مک او اس و ویندوز هر سه از پیاده سازی های مختلفی برای JVM برخودارد هستند. هرکدام با توجه به پیش فرض های خود از اولویت نخ استفاده می کنند.

اولویت نخی که تنظیم می کنید، بر ترتیب فراخوانی آن ها تأثیر گذار است. به هر حال، 3 ثابت اعلام شده در کلاس Thread عبارتند از:

برخی از تست ها را بر روی کد زیر اجرا کنید تا ببینید با چه اولویتی اجرا می شوند:

حتی اگر اولویت moeThread را روی MAX_PRIORTY قرار دهیم، JVM اجرا شدن آن به عنوان اولین نخ را تضمین نمی کند. در عوض، ترتیب اجرا تصادفی خواهد بود.

کمی چالش با Thread ها در جاوا

شما اطلاعات کمی درباره thread ها در جاوا در این مطلب یاد گرفته اید، اما به اندازه ای کافی هست تا بتوانید خودتان را با کد زیر محک بزنید.

کد زیر را مرور کنید:

خروجی کد بالا چه خواهد بود؟ کد بالا را تحلیل کرده و پاسخ خود را بیابید.

چه اتفاقی می افتد؟ درک رفتار نخ ها در جاوا

در کد بالا، سه نخ ایجاد کرده ایم. اولین نخ Harley Davidson است و اولویت آن را تعیین نکرده ایم (اولویت آن پیشفرض درنظر گرفته شده است) . نخ دوم، Dodge Tomahawk است که اولویت MAX_PRIORTY به آن اختصاص داده شده است. سومین نخ Yamaha YZF با اولویت MIN_PRIORTY است. سپس نخ ها را اجرا می کنیم.

کلاس Motorcycle از کلاس Thread ارث بری کرده و ما نام نخ را به عنوان آرگومان به سازنده این کلاس ارسال می کنیم. همچنین برای متد ()run یک شرط گذاشته ایم که اگر مقدار wolverineAdrenaline برابر با 13 باشد، آنگاه اجرا می شود.

نخ Yamaha YZF با اینکه سومین نخی هست که اعلان می شود و دارای اولویت MIN_PRORTY است، هیچ تضمینی وجود ندارد که به عنوان سومین یا آخرین نخ اجرا شود.

همچنین ممکن است توجه داشته باشید که ما نخ Dodge Tomahawk را به عنوان daemon تنظیم کرده ایم. از ان جا که این یک نخ daemon است، ممکن است هرگز به طور کامل اجرا نشود. اما دو نخ دیگر به طور پیشفرض non-daemon هستند. بنابراین اجرای آن ها قطعا به طور کامل خواهد بود.

در نهایت بید این را بگوییم که نتیجه در هر بار اجرا متفاوت خواهد بود. زیرا هیچ تضمینی وجود ندارد که زمان بند نخ ها از ترتیب اولویت هایی که ما تعری کرده ایم، پیروی کند.

اشتباهات رایج هنگام کار با thread ها در جاوا

  • برای اجرای یک نخ جدید، متد ()run را به جای متد ()start فراخوانی می کنید
  • تلاش می کنید تا یک نخ را 2 بار اجرا کنید (خطای IllegalThreadStateExceptiom را به همراه دارد)
  • اجازه دادن به چندین نخ برای تغییر دادن وضعیت یک شئ، درحالی که نباید تغییر کند
  • نوشتن منطق برنامه با تکیه و اعتماد بر اولویت های نخ (که غیر قابل پیشبینی و تضمین نشده است)
  • اعتماد به ترتیب اجرای نخ ها (حتی اگر یک نخ را ابتدا اجرا کنیم، هیچ ضمانتی وجود ندارد که اول از همه اجرا شود)

 

QR:  معرفی و نحوه کار با Thread ها در جاوا
به اشتراک بگذارید