۱۳۹۰ آذر ۱۱, جمعه

مقدمه ای بر Thread ها در جاوا

این مقاله شرح می‌دهد چگونه Thread ها در برنامه نویسی جاوا ایفای نقش می کنند. قبل از کنکاش در جزییات جاوا یک نگاه عمومی به thread ها مورد نیاز است.

به تعبیر ساده ، یک thread مسیر اجرای یک برنامه می‌باشد. امروزه بیشتر برنامه‌های نوشته شده مانند یک تک thread اجرا می‌شوند ، مسأله ای را فرض کنید باید در یک زمان چندین رویداد یا کنش اتفاق بیفتند. اجازه دهید بگوییم برای مثال، یک برنامه قادر نیست یک عکس را بکشد مادامیکه در حال خواندن اطلاعات ارسال شده از صفحه‌کلید است . این برنامه باید تمام توجه خود را معطوف به خواندن اطلاعات ارسال شده از صفحه‌کلید نماید و فاقد توانای برای کنترل بیش از یک رویداد در یک زمان می باشد.راه حل ایده‌آل برای این مشکل اجرای یکپارچه ی دو بخش یا بیشتر، از یک نرم‌افزار در یک زمان می باشد. Thread ها به ما این اجازه را می دهند.

نرم‌افزار های چند Thread همه ی توان خود را انجام می‌دهند تا چندین thread همزمان در یک تک برنامه اجرا شود.از یک نگاه منطقی مالتی تریدینگ به معنای این است که چندین خط از یک برنامه می‌تواند در یک زمان اجرا شود، به هر حال، این بدان معنی نیست که یک برنامه دو بار اجرا شود و بگوییم چندین خط از برنامه وجود دارد که در یک زمان اجرا شده است. در این حالت سیستم عامل با برنامه مثل دو فرایند مجزا رفتار می کند. در سیستم عامل یونیکس انشعاب یک جریان یک زیر شاخه با آدرس متفاوت برای هر دو کد و داده ایجاد می‌کند. به هر حال ()fork تعداد زیادی overhead برای سیستم عامل می‌سازد، باعث تمرکز عملیات بر روی cpu می شود. در عوض با شروع thread ، یک مسیر کار آمد برای اجرای برنامه ایجاد شده مادامی که هنوز در محدوده ی داده‌های اصلی می باشد. ایده ی تسهیم محدوده ی داده‌ها ایده ی بسیار مفیدی است، اما باعث برخی محدوده های به هم مرتبط می‌شود که بعداً در باره ی آن بحث خواهیم کرد.

ایجاد thread ها

آفریننده های جاوا دو روش دوست‌ داشتنی برای خلق thread ها ایجاد کرده اند: پیاده‌سازی یک رابط
(Interface)و توسعه ی یک کلاس. توسعه ی یک کلاس راهی است که جاوا، متد ها و متغییر ها را از کلاس‌های مادر به ارث می برد. این محدودیت در جاوا می‌تواند بوسیله ی پیاده‌سازی رابط برطرف شود که متداول ترین روش برای آفریدن thread هاست. ( توجه داشته باشید که عمل ارث بری فقط به کلاس این اجازه را می‌دهد که همانند یک thread اجرا شود. آن کلاس را شروع یا اجرا می کند.)

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

تفاوت‌هایی بین یک کلاس و یک رابط وجود دارد. اول، یک را بط می‌تواند فقط شامل متد های انتزاعی (abstract) و یا متغییرهای پایانی پایا ( static final variables )یا ثوابت باشند. به عبارت دیگر، کلاس‌ها می‌توانند متد ها را پیاده‌سازی کنند و همچنین شامل متغییر ها یی باشند که مقدار آنها ثابت نیست. دوم، یک رابط نمی‌تواند هر متدی را پیاده‌سازی کند. یک کلاسی که یک رابط را پیاده‌سازی می‌کند باید همه ی متد های تعریف شده در آن رابط را پیاده‌سازی کند. یک رابط توانایی آن را را دارد تا توسط دیگر رابط ها توسعه داده شود و (بر خلاف کلاس ها) می‌تواند توسط چندین رابط توسعه یابد. از این گذشته، یک رابط نمی‌تواند بوسیله ی یک عملگر جدید تعریف شود، برای مثال:

Runnable a=new Runnable();

مجاز نیست.
اولین روش برای آفریدن یک thread بست یک thread از کلاس آن است. این کار را فقط زمانی انجام دهید که کلاسی را که می‌خواهید به شکل thread بست دهید هرگز نیاز به بست آن کلاس به دیگر کلاس‌ها را نداشته باشید. این کلاس در بسته ی java.lang تعریف شده است که نیاز به وارد کردن این بسته دارید بنا بر این کلاس‌های ما از این تعریف آگاه می شوند.


import java.lang.*;
public class Counter extends Thread 
{                      
        public void run()                       
        {              
        ....            
        }
}
 
مثال بالایک کلاس جدید به نام Counter ایجاد میکند که کلاس Thread را بسط می‌دهد و متد Thread.run() را برای اجرای خود پیاده می کند. متد run جایی به کار می‌رود که همه ی وظایف کلاس Counter انجام شده باشد.


import java.lang.*;
public class Counter implements Runnable
{
        Thread T;                        
        public void run()                       
        {                              
        ....            
        }
}
 
 
در اینجا متد run در رابط Runnable تعریف و پیاده‌سازی شده است. توجه داشته باشید ما یک رابط از کلاس Thread همچون یک متغییر از کلاس Counter داریم. تنها تفاوت میان دو متد، پیاده‌سازی متد Runnable است، این کار انعطاف بیشتری در ایجاد کلاس Counter در اختیار ما قرار می دهد. در مثال بالا هنوز این فرصت وجود دارد که در صورت لزوم کلاس Counter، بسط داده شود. بیشتر کلاس‌های ساخته شده‌ای که نیاز به اجرا run به عنوان thread داشته ًباشند ، Runnable را پیاده ساری می‌کنند، از این رو آن‌ها برخی دیگر از وظایف کلاس‌های دیگر را احتمالاً بسط می‌دهند.

گمان نکنید که رابط Runnable هر کار واقعی را زمانی که Thread اجرا شده است انجام انجام می‌دهد. این تنها کلاس آفریده شده ایست، تا ایده ای برای طراحی کلاس thread باشد. در حقیقت، این یک محتوی بسیار کوچک است فقط یک متد انتزاعی (abstract). در اینجا تعریف رابط Runnable مستقیماً از منابع جاوا آمده است.

package java.lang;
public interface Runnable {    
        public abstract void run();
}
 
این همه ی آن چیزی است که رابط Runnable می نامیم.یک رابط فقط طرحی که کدام کلاس‌ها باید پیاده‌سازی شوند را ارائه می کند. در این حالت رابط Runnable،فقط بر روی متد run تمرکز می کند. بنا بر این، بیشتر کار در کلاس thread انجام می شود. یک نگاه نزدیک تر به یک بخش در تعریف کلاس thread این ایده رابه ما می‌دهد که چه چیز واقعاً در حال انجام است:

public class Thread implements Runnable {
...
        public void run() {    
                if (target != null) {  
                        target.run();   
                }
        }
...
} 
 
 
از کد بالا این مطلب آشکار است که کلاس thread همچنین رابط Runnable را پیاده‌سازی می کند.
 Thread.run چک می‌کند تا اطمینان یابد هدف کلاس ( کلاسی که می‌رود تا همانند یک thread اجرا شود)
 پوچ نیست، و سپس متد run  به عنوان هدف اجرا می شود. زمانی که این اتفاق بیفتد متد run هدف همانند thread خود
 اجرا خواهد شد.   
 
شروع و پایان
 
از آنجایی که روش‌های مختلفی برای ایجاد یک نمونه از thread در حال حاضر ارائه شده ، ما بحث خواهیم کرد که پیاده‌سازی 
 یک thread  ها با روش‌های در دسترس برای شروع و پایان آن‌ها با استفاده از یک اپلت کوچک شامل یک thread برای
 نمایش مکانیک:
مثال و کد:  CounterThread  
 
 اپلت بالا شمارش را از صفر شروع خواهد کرد و خروجی را  در یک پنجره و  در یک کنسول هردو به نمایش در خواهد آورد
 یک نگاه اجمالی این احساس را به ما می‌دهد که برنامه شمارش را شروع خواهد کرد و هر عدد را نمایش خواهد داد، اما این همه
 چیز نیست. یک نگاه دقیق‌تر به اجرای این اپلت هویت ,واقعی آن را آشکار خواهد کرد.