آموزش جاوا – قسمت 14 (مفهوم نخ و رشته)

در این جلسه قصد داریم تا آخرین مبحث آموزشی جاوا را به مفهوم نخ (Thread) و چندنخی بودن (Multi-Threaded) زبان جاوا که مبحثی کاربردی  در پیاده‌سازی‌ شبکه‌های اس دی ان است، اختصاص دهیم.

احتمالا تا به حال شنیده‌اید که جاوا یک زبان برنامه‌نویسی چندنخی محسوب می‌شود و می‌توان برنامه‌های چندنخی را با زبان جاوا ایجاد کرد. اما بیایید ببینیم که این جمله چه مفهومی دارد، و چه مزیتی را برای ما برنامه‌نویسان فراهم می‌کند.

یک برنامه چندنخی شامل حداقل دو بخش است که هر بخش یک وظیفه خاص را موازی با سایر بخش‌ها انجام می‌دهد و به این ترتیب باعث استفاده بهینه از منابع موجود می‌شود به خصوص زمانی که سیستم شما دارای چند پردازنده مرکزی باشد.

جا دارد تا شما را با مفهومی دیگر به نام چندوظیفه‌ای (multitasking) آشنا کنیم. multitasking زمانی اتفاق می‌افتد که چند پردازش، منابع پردازشی مشترکی مانند پردازنده مرکزی را با یکدیگر به اشتراک بگذارند، مفهوم چندنخی درواقع حالت بسط یافته چندوظیفه‌ای است که یک برنامه کاربردی طبق عملیاتی که در آن انجام می‌شود به بخش‌های تقسیم می‌شود که هریک در قالب نخ یا رشته (Thread) با استفاده از منابع مشترک، اجرا می‌شوند.به این ترتیب سیستم‌عامل نه تنها زمان پردازش را بین برنامه‌های کاربردی تقسیم می‌کند، بلکه در هر برنامه کابردی، بین نخ‌های آن برنامه نیز تقسیم می‌کند.

چرخه حیات یک نخ

هر نخ در طول عمر بابرکت خود (!) ممکن است در وضعیت‌های مختلفی قرار بگیرد(به وجود بیاید، شروع به کار کند، اجرا شود،و  از بین برود). در شکل زیر می‌توانید تمام این مراحل را مشاهده کنید:

از زمانی که یک نخ وارد وضعیت اول(New) می‌شود، تا زمانی که برنامه، نخ مورد نظر را شروع کند در همین موقعیت قرار می‌گیرد. به چنین نخی اصطلاحا born thread نیز گفته می‌شود.

یک نخ زمانی که در انتظار تمام شدن وظیفه نخ دیگر به سر می‌برد، در وضعیت waiting قرار می‌گیرد. در این صورت نخ دوم  با ارسال یک سیگنال به نخ اول،   اتمام وظیفه خود را اعلام می‌کند. حال نخ اول می‌تواند به وضعیت قبل بازگشته و اجرای خود را از سر گیرد.

یک نخ می‌تواند به مدت زمان مشخصی وارد وضعیت timed waiting که نوع دیگری از waiting است بشود. در این صورت پس از منقضی شدن زمان تعیین شده، به اجرای وظیفه خود ادامه خواهد داد.

در صورت تمام شدن وظیفه یک نخ یا به وجود آمدن دلایل دیگر برای تمام کردن اجباری وظیفه، آن نخ وارد وضعیت dead خواهد شد.

اولویت‌ اجرا در نخ

در جاوا برای هر نخ یک اولویت مشخص شده است که باعث می‌شود تا سیستم‌عامل بتواند برای ترتیب اجرای آن‌ها برنامه‌ریزی کند.اولویت هر نخ عددی بین 1 و 10 است که در حالت معممول این عدد برابر 5 است. نخ‌ها با اولویت بیشتر از اهمیت بیشتری برخوردارند و باید نسبت به پردازش‌های کم‌اهمیت‌تر، سریع‌تر منابع مورد نیاز را در اختیار بگیرند. لازم به ذکر است که این اولویت‌ها خیلی هم تضمین‌کننده ترتیب اجرا نیستند و بستگی به پلتفرم نیز دارند.

نحوه ایجاد یک نخ

در این قسمت با مثالی عملی شما را با دو روش برای ایجاد نخ و اجرای آن آشنا خواهیم کرد…

روش اول: Implementing a Runnable Interface

زمانی که تصمیم گرفتید تا کلاس خود را در قالب یه نخ اجرا کنید، می‌توانید این کار را با interfaceای به نام Runnable انجام دهید.(مبحث Interface را می‌توانید اینجا مرور کنید). برای این کار باید این سه مرحله را انجام دهید:

مرحله اول

در اولین قدم شما نیاز دارید تا تابع run از Runnable را پیاده‌سازی کنید و تمام منطق بیزینسی خود را داخل این تابع قرار دهید.

مرحله دوم

سپس شما نیاز خواهید داشت تا یک نمونه از شی Thread را با استفاده از constructor زیر ایجاد کنید:

Thread(Runnable threadObj, String threadName);
مرحله سوم

تا اینجا شما توانستید یک نخ را ایجاد کنید. با اجرای تابع start، نخ شروع به کار می‌کند.

 

برای اینکه با نحوه عملکرد نخ و ترتیب اجرای توابع آن بیشتر آشنا شوید به کدی که در زیر آورده شده است توجه کنید. این کد طوری در نظر گرفته شده است که در هر مرحله در کنسول یک خروجی چاپ شود تا شما بتوانید مراحل کار را به راحتی دنبال کنید:

class RunnableDemo implements Runnable {
   private Thread t;
   private String threadName;
   
   RunnableDemo( String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   public void run() {
      System.out.println("Running " +  threadName );
      try {
         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
            // Let the thread sleep for a while.
            Thread.sleep(50);
         }
      } catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }
   
   public void start () {
      System.out.println("Starting " +  threadName );
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}

public class TestThread {

   public static void main(String args[]) {
      RunnableDemo R1 = new RunnableDemo( "Thread-1");
      R1.start();
      
      RunnableDemo R2 = new RunnableDemo( "Thread-2");
      R2.start();
   }   
}

با اجرای این کد، خروجی زیر را مشاهده خواهید کرد:

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

روش دوم: Extending a Thread Class

تا اینجا با یکی از روش‌های ایجاد نخ آشنا شدید. روش دیگر، ساخت یک کلاس جدید است که extend شده کلاس Thread است. این روش نسبت به روش قبل انعطاب‌پذیری بیشتری در سر و کار داشتن با نخ‌های ایجاد شده توسط توابع موجود در کلاس Thread دارد. مراحل ایجاد نخ در این روش به این صورت است:

مرحله اول

ابتدا شما باید تابع run موحود در کلاس thread را override کنید. مشابه مرحله قبل شما می‌توانید تمام منطق بیزینسی خود را داخل این تابع قرار دهید.

مرحله دوم

به محض ایجاد یک شی Thread، شما می‌توانید با صدا زدن تابع start اجرای نخ را شروع کنید.

 

در مثال زیر ایجاد و اجرای یک نخ را با این روش مشاهده می‌کنید:

class ThreadDemo extends Thread {
   
   private String threadName;
   
   ThreadDemo( String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   public void run() {
      System.out.println("Running " +  threadName );
      try {
         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
            // Let the thread sleep for a while.
            Thread.sleep(50);
         }
      }catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }
}
public class TestThread {
   public static void main(String args[]) {
      ThreadDemo T1 = new ThreadDemo( "Thread-1");
      T1.start();
     
      ThreadDemo T2 = new ThreadDemo( "Thread-2");
      T2.start();
   }  
}

خروجی حاصل از اجرای این برنامه به این صورت خواهد بود:

Creating Thread-1
Creating Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

توابع کلاس Thread

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

()public void start: شروع نخ در یک مسیر اجرایی مجزا. در این تابع، تایع run فراخوانی می‌شود.

()public void run: پیشتر درمورد این تابع توضیح داده شد.

(public final void setName (String name: تغییر نام شی ایجاد شده از Thread. متقابلا تابعی نیز به نام getName برای بازیابی نام شی مورد نظر وجود دارد.

(public final void setPriority( int priority: تعیین اولویت شی ایجاد شده از کلاس Thread. این مقدار عددی بین 1 تا 10 خواهد بود.

(public final void setDaemon( boolean on: برای تنظیم daemon بود یا نبودن نخ به کار می‌رود. در جاوا daemon به نخ‌هایی گفته می‌شود که جلوی JVM را از exit شدن نمی‌گیرند. درواقع JVM تنها در صورتی exit می‌شود که تنها نخ‌های باقی مانده، نخ‌های daemon باشند.

(public finalvoid join (long millisec: با صدا زدن این تابع از نخ دوم توسط نخ فعلی، تا زمانی که نخ دوم تمام نشده یا مدت زمان مشخص شده در آرگومان تابع به اتمام نرسیده است، نخ فعلی در حالت بلاک باقی می‌ماند.

()public void interrupt: با اجرای این تابع، در صورتی که نخ مورد نظر به هر دلیلی در حالت بلاک باقی مانده باشد، به اجرای خود ادامه می‌دهد.

()public final boolean isAlive:  در صورتی که نخ مربوطه در زمانی بین شروع تا پایان اجرای خود قرار داشته باشد، مقداری که با فراخوانی این تابع برگردانده می‌شود، true خواهد بود.

()public static void yield: با اجرای این تابع، نخی که در حال حاضر در حال اجراست، نوبت خود را به نخی هم اولویت با خود که در انتظار schedule شدن است می‌دهد.

(public static void sleep( long millisec: نخ در حال اجرای فعلی، حداقل به اندازه مدت زمان مشخص شده در آرگومان بلاک خواهد شد.

()public static Thread currentThread: نخی که در حال حاضر در حال اجراست مشخص می‌شود. که درواقع همان نخی است که این تابع را صدا زده است!

()public static void dumpStack:  تابعی مفید برای عیب‌یابی برنامه‌های چندنخی که می‌توان با اجرای این تابع محتویات پشته را برای نخ در حال اجرا مشاهده نمود.

 

در این قسمت از آموزش جاوا سعی کردیم تا شما را با موجوداتی به نام Thread آشنا کنیم. با توجه به آموخته های خود درباره life story این موجودات و توابعی که برای کار با آن‌ها وجود دارد، خواهید توانست تا با اندکی تمرین برنامه‌هایی چندنخی نوشته و حرفه‌ای تر از قبل، از منابع موجودبه صورت بهینه استفاده  کنید.

آخرین قسمت از آموزش جاوا نیز به پایان رسید. با توجه به نظرسنجی اخیر انجام شده در کانال تلگرامی SDNCentral و استقبال شما همراهان از ادامه آموزش جاوا به صورت ویدئویی، تیم sdncentral قصد دارد تا در آینده‌ای نزدیک مطالب گفته شده را به صورت کامل تر و حرفه‌ای تر در قالب آموزش ویدئویی  ارائه دهد.

شما می‌توانید در طول این مدت علاوه بر کامنت، سوالات خود از هر یک از قسمت‌های آموزشی جاوا را از طریق آی دی تلگرامی @SM_SDN نیز مطرح کنید.

 

با آرزوی موفقیت برای شما sdn آموزان عزیز…

 

تاریخچه آموزش جاوا به ترتیب:

قسمت اول آموزش جاوا (مقدمه)

قسمت دوم آموزش جاوا (Types and Variables)

قسمت سوم آموزش جاوا (دستورات شرطی)

قسمت چهارم آموزش جاوا (آرایه‌ها)

قسمت پنجم آموزش جاوا (حلقه‌ها)

قسمت ششم آموزش جاوا (توابع)

قسمت هفتم آموزش جاوا (اشیا)

قسمت هشتم آموزش جاوا (ارث‌بری)

قسمت نهم آموزش جاوا (try and catch)

قسمت دهم آموزش جاوا (کلاس‌های abstract)

قسمت یازدهم آموزش جاوا (Interfaces)

قسمت دوازدهم آموزش جاوا (مفهوم Generic)

قسمت سیزدهم آموزش جاوا (Networking)

قسمت چهاردهم آموزش جاوا (مفهوم نخ و رشته)

آموزش جاوا – قسمت 14 (مفهوم نخ و رشته)
امتیاز دهید

(3) دیدگاه

  • ناشناس پاسخ

    برای ایجاد حوضچه نخ هم باید از این روش استفاده کرد؟

    6 فوریه 2018 در 2:56 ب.ظ
    • صدف مظفری
      صدف مظفری پاسخ

      سلام
      خیر در پیاده سازی Thread Pool از مفهومی به نام Executor استفاده می‌شود و کاملا متفاوت از روش شرح داده شده برای Thread است. که خود می‌تواند مبحث یک جلسه آموزشی مجزا باشد.

      6 فوریه 2018 در 9:22 ب.ظ
  • ناشناس پاسخ

    سلام درود برشما وب سایت خیلی خوبییی بود ممنون از اشتراک گذاریتون موفق و پیروز باشید دوست عزیز.

    7 فوریه 2018 در 9:07 ق.ظ

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *