در این آموزش یکی از مباحث بسیار مهم در زبان برنامهنویسی جاوا تحت عنوان Thread را معرفی کرده و مقدمهای از کاربرد آن در اجرای تَسکهای نوشتهشده در برنامههای جاوا را تشریح میکنیم. به طور کلی، میتوان گفت که تِرِدها دارای کاربردهای فراوانی هستند که از آن جمله میتوان به توسعۀ گیم، اپلیکیشنهای تحت وب و غیره اشاره کرد (جهت کسب اطلاعات بیشتر در رابطه با نحوۀ اجرای برنامه به صورت مالتیتِرِد به مقالۀ آشنایی با مفاهیم Thread ،Process و نحوۀ کارکرد Multithreading مراجعه نمایید.) در واقع، زمانی از تِرِدها در پروسهٔ توسعهٔ نرمافزار استفاده میکنیم که بخواهیم برنامهای طراحی کنیم تا در آن بیش از یک کار را به طور همزمان پیش ببریم که برای این منظور نیز کلاسی تحت عنوان Thread
در زبان برنامهنویسی جاوا تعبیه شده است.
حال برای درک بهتر مفهوم تِرِدها، مثالی را مد نظر قرار میدهیم بدین صورت که وقتی یک فایل ویدئویی را به صورت آنلاین تماشا میکنیم، نیازی نیست تا صبر کنیم تا فایل کاملاً بارگذاری شود بلکه پخش ویدئو شروع شده و همزمان با نمایش ویدئو بارگذاری بخشهای دیگر آن نیز انجام میشوند. به عبارت دیگر، دو کار نمایش ویدئو و بارگذاری آن به صورت همزمان صورت میگیرند که این موضوع دقیقاً به کاربرد تِرِدها در پیشبرد دو تَسک به صورت همزمان اشاره دارد.
در حقیقت، به طور خلاصه میتوان گفت که با استفاده از تِرِدها میتوانیم نرمافزاری طراحی کنیم تا به جای انتظار برای تکمیل انجام یک کار سپس آغاز کار بعدی، هر دو کار به صورت همزمان پیش روند که اهمیت چنین مسئلهای در توسعهٔ گیم دو چندان میگردد. از سوی دیگر، تِرِدها صرفاً در بازیسازی کاربرد نداشته و در حوزۀ اپلیکیشنهای تحت وب و دسکتاپ نیز کاربردهای فراوانی دارند. به طور مثال، فرض کنیم که یک اپلیکیشن تحت وب با زبان جاوا طراحی کردهایم که در نقش یک وب سرور بوده و وظیفۀ هندل کردن بیش از یک ریکوئست (درخواست) در آنِ واحد را دارا است که این کار به سادگی با استفاده از مفهوم تِرِدها در زبان جاوا امکانپذیر میباشد.
حال در ادامه قصد داریم تا ببینیم که چگونه میتوان به صورت عملی یک تِرِد در زبان برنامهنویسی جاوا ایجاد کرد و اجرای برنامهها با استفاده از چند تِرِد چه مزایایی دارا است. به طور کلی، میتوان گفت که پیادهسازی تِرِدها در زبان برنامهنویسی جاوا به دو روش مختلف امکانپذیر میباشد که عبارتند از:
- روش اول بدین صورت است که کلاسی ایجاد کرده سپس کلاس مذکور ویژگیهای خود را از کلاس
Thread
در زبان جاوا به ارث میبرد. - در روش دوم کلاسی ایجاد کرده و آن را از روی اینترفیسی تحت عنوان
Runnable
ایمپلیمنت میکنیم که در چنین شرایطی میتوانیم بدون ارثبری از کلاسThread
اقدام به ساخت تِرِد نماییم.
در ادامۀ این آموزش و به منظور درک سازوکار تِرِدها، هر دو روش را مورد بررسی قرار خواهیم داد.
نحوۀ ساخت تِرِد با بهکارگیری کلاس Thread
در این مرحله به بررسی نحوۀ ساخت یک تِرِد با ارثبری از کلاسی تحت عنوان Thread
میپردازیم که در ایپیآی زبان جاوا گنجانده شده است. برای شروع، یک پروژۀ جدید تحت عنوان Thread ایجاد کرده و کلاسی به نام ThreadA
در آن میسازیم که در ابتدا کدی به صورت زیر خواهیم داشت:
public class ThreadA extends Thread {
}
در کد فوق، با استفاده از کیورد extends
کلاس ThreadA
را به نحوی پیادهسازی کردهایم تا از کلاس Thread
ارثبری نماید و بدین ترتیب کلاس مذکور کلیۀ خصوصیات، ویژگیها و متدهای کلاس Thread
را به ارث خواهد برد. حال به منظور درک بهتر مفهوم تِرِدها، کد فوق را بدین صورت تکمیل میکنیم که متدی تحت عنوان ()run
از کلاس Thread
را اُورراید کرده و در آن سعی میکنیم تا استرینگی را به صورت زیر در کنسول چاپ نماییم:
public class ThreadA extends Thread {
@Override
public void run() {
System.out.println("Thread A");
for (int i = 1; i <= 5; i++) {
System.out.println("From thread A, loop no: " + i);
}
}
}
در کد فوق، با استفاده از دستور Override@
متد ()run
از کلاس Thread
را اُورراید کردهایم به طوری که متد مذکور در صورت فراخوانی ابتدا استرینگ «Thread A» را در کنسول چاپ میکند که به نوعی مرتبط با آغاز اجرای تِرِد اول میباشد سپس یک حلقۀ for
تعریف کردهایم که در آن گفتهایم در هر بار اجرای حلقه مقدار منتسب به متغیر i
به همراه استرینگ «:From thread A loop no» در کنسول چاپ شود و این در حالی است که در هر تکرار مقدار منتسب به این متغیر یک واحد افزایش یافته و از سوی دیگر اجرای حلقۀ for
نیز تا زمان رسیدن مقدار متغیر i
به عدد 5 ادامه مییابد (جهت کسب اطلاعات بیشتر در رابطه با نحوۀ عملکرد حلقههای for
به آموزش آشنایی با ساختار حلقۀ for در زبان برنامهنویسی جاوا مراجعه نمایید.)
توجه داشته باشیم که وقتی کلاسی از Thread
ارثبری میکند میباید متد ()run
از این کلاس را اُورراید کرد چرا که بدین طریق میتوانیم دستورات مورد نظر خود را در آن پیادهسازی نماییم و در غیر این صورت آیدیای اکلیپس واژۀ run
را با نقطهچین مشخص مینماید که به منزلۀ وجود اروری مرتبط با متد مذکور در برنامه میباشد.
حال به منظور درک مفهوم مالتیتِرِدینگ و اجرای برنامهها با بهکارگیری چند تِرِد مختلف، علاوه بر کلاس ThreadA
کلاس دیگری تحت عنوان ThreadB
نیز در پروژهٔ خود ایجاد کرده و در آن متد ()run
را به گونهای اُورراید میکنیم تا استرینگی مبنی بر اجرای تِرِد دوم را در کنسول چاپ نماید تا ببینیم اجرای همزمان برنامه توسط دو تِرِد چگونه میتواند باشد. از همین روی، کلاس ThreadB
را ساخته و آن را به صورت زیر تکمیل میکنیم:
public class ThreadB extends Thread {
@Override
public void run() {
System.out.println("Thread B");
for (int i = 1; i <= 5; i++) {
System.out.println("From thread B, loop no: " + i);
}
}
}
همانطور که ملاحظه میکنیم، کلاس ThreadB
نیز از کلاس Thread
ارثبری کرده است و تنها تفاوت آن با کلاس ThreadA
این است که در صورت آغاز اجرای تِرِد دوم استرینگی به صورت «Thread B» در کنسول چاپ شده و در ادامه برنامه وارد حلقه شده و استرینگ مرتبط با این کلاس را به صورت «:From thread B, loop no» به همراه مقدار منتسب به متغیر i
در کنسول چاپ میکند. به علاوه، توجه داشته باشیم که مقدار متغیر i
در هر بار اجرای حلقه یک واحد افزایش یافته و اجرای آن نیز تا زمان رسیدن مقدار متغیر مذکور به عدد 5 ادامه مییابد.
در این مرحله به منظور ساخت آبجکت از روی دو کلاس فوق سپس فراخوانی متدهای ()run
روی آبجکتهای ساختهشده، کلاس جدیدی تحت عنوان ActionClass
ساخته و در حین ساخت کلاس نیز تیک گزینۀ public static void main را میزنیم که در ابتدا کدی مانند زیر خواهیم داشت:
public class ActionClass {
public static void main(String args[]) {
}
}
در ادامه نیاز به ساخت آبجکت از روی هر دو کلاس ThreadA
و ThreadB
داریم که برای این منظور کد فوق را به صورت زیر تکمیل میکنیم:
public class ActionClass {
public static void main(String args[]) {
ThreadA a = new ThreadA();
ThreadB b = new ThreadB();
}
}
در کد فوق، مشابه آموزشهای پیشین دو آبجکت تحت عناوین a
و b
به ترتیب از روی کلاسهای ThreadA
و ThreadB
ساختهایم. اکنون به هر دو متد ()run
از دو کلاس مذکور دسترسی داشته و میتوانیم آنها را روی آبجکتهای مورد نظر فراخوانی نماییم. از سوی دیگر، جهت ایجاد تِرِدها یا به عبارتی اجرای برنامه به صورت مالتیتِرِد نیاز به فراخوانی متدی از پیش تعریفشده از کلاس Thread
تحت عنوان ()start
داریم که فراخوانی این متد منجر به ایجاد یک تِرِد شده و در ادامه متدهای ()run
را فراخوانی مینماید. بنابراین در ادامه متد ()start
را روی هر دو آبجکت ساختهشده فراخوانی مینماییم و برای این منظور به روش زیر عمل میکنیم:
public class ActionClass {
public static void main(String args[]) {
ThreadA a = new ThreadA();
a.start();
ThreadB b = new ThreadB();
b.start();
}
}
در کد فوق، ابتدا آبجکتی به نام a
از روی کلاس ThreadA
ساخته و در ادامه متد ()start
را روی آن فراخوانی میکنیم که فراخوانی این متد منجر ایجاد تِرِد اول شده و همچنین متد ()run
را جهت اجرا روی تِرِد ساختهشده فراخوانی مینماید. در ادامه، آبجکت جدیدی به نام b
از روی کلاس ThreadB
ساخته و متد ()start
را روی آن فراخوانی نمودهایم که بدین ترتیب تِرِد دیگری ساخته شده و متد ()run
از کلاس ThreadB
نیز به منظور اجرا روی تِرِد جدید فراخوانی میشود.
اکنون دو تِرِد ایجاد کردهایم که موجب اجرای برنامه به صورت همزمان میشوند بدین معنی که ممکن است تِرِد اول منابع سیستم را به منظور اجرای حلقۀ for
از کلاس ThreadA
گرفته و آن را یک مرتبه تکرار کرده و در ادامه منابع سیستم به تِرِد دوم اختصاص یافته و حلقۀ for
از کلاس ThreadB
یک مرتبه اجرا شود و این فرآیند تا اتمام اجرای هر دو حلقه تکرار شود یا به عنوان مثالی دیگر ممکن است تِرِد اول حلقۀ for
از کلاس ThreadB
را سه مرتبه تکرار کرده و در ادامه منابع سیستم را آزاد کند که در این صورت تِرِد دوم اجرای حلقۀ for
از کلاس ThreadA
را ادامه داده و آن را یک مرتبه اجرا کند که این فرآیند تا زمان اتمام تعداد اجرای هر دو حلقه تکرار خواهد شد. حال برنامۀ فوق را اجرا کرده و در خروجی خواهیم داشت:
Thread A
Thread B
From thread A, loop no: 1
From thread B, loop no: 1
From thread A, loop no: 2
From thread B, loop no: 2
From thread A, loop no: 3
From thread A, loop no: 4
From thread A, loop no: 5
From thread B, loop no: 3
From thread B, loop no: 4
From thread B, loop no: 5
همانطور که میبینیم، ابتدا تِرِدی برای اجرای متد ()run
از کلاس ThreadA
ایجاد شده و در ادامه تِرِد دیگری برای اجرای متد ()run
از کلاس ThreadB
ایجاد شده است. در ادامه، تِرِد اول متد ()run
از کلاس ThreadA
را اجرا کرده و در نتیجه حلقۀ for
از این متد یک مرتبه اجرا شده و استرینگ مربوطه در کنسول چاپ گردیده است؛ سپس تِرِد دوم منابع سیستم را در اختیار گرفته و متد ()run
از کلاس ThreadB
را فراخوانی کرده و حلقۀ for
آن را یک مرتبه اجرا نموده و این امر نیز منجر به چاپ استرینگ مربوطه در کنسول شده است.
به همین ترتیب، مجدداً منابع سیستم به تِرِد اول اختصاص یافته و اجرای متد ()run
از کلاس ThreadA
از سر گرفته شده و بدین ترتیب حلقۀ for
برای بار دوم اجرا شده است سپس تِرِد دوم منابع سیستم را در اختیار گرفته و حلقۀ for
از کلاس ThreadB
را برای بار دوم اجرا کرده است. در مرحلۀ بعدی مجدداً تِرِد اول اقدام به اجرای متد ()run
از کلاس ThreadA
نموده و دو مرتبه حلقۀ for
از این کلاس را اجرا کرده است و به همین منوال مراحل دیگری مشابه آنچه که تاکنون توضیح دادیم تا زمان تکمیل هر پنج مرتبه از هر دو حلقه ادامه یافته و بدین ترتیب حلقههای هر دو کلاس توسط هر یک از دو تِرِد به صورت همزمان اجرا شدهاند. حال اگر برنامۀ فوق را مجدداً اجرا کنیم در خروجی خواهیم داشت:
Thread A
Thread B
From thread A, loop no: 1
From thread A, loop no: 2
From thread A, loop no: 3
From thread A, loop no: 4
From thread B, loop no: 1
From thread A, loop no: 5
From thread B, loop no: 2
From thread B, loop no: 3
From thread B, loop no: 4
From thread B, loop no: 5
همانطور که در خروجی میبینیم، در ابتدا دو تِرِد ساخته شده و در ادامه تِرِد اول متد ()run
از کلاس ThreadA
را اجرا میکند که در این مورد تِرِد اول به تعداد چهار مرتبه حلقۀ for
را اجرا کرده و منابع سیستم را آزاد میکند و در ادامه تِرِد دوم با در اختیار داشتن منابع سیستم متد ()run
از کلاس ThreadB
را اجرا میکند و همانطور که میبینیم این تِرِد یک مرتبه حلقۀ for
را اجرا کرده و تِرِد اول مجدداً اجرای حلقۀ for
از متد ()run
از کلاس ThreadA
را از سر گرفته و آن را یک بار دیگر اجرا میکند که در اینجا کار تِرِد اول به پایان رسیده و منابع سیستم را به طور کامل آزاد کرده و در ادامه تِرِد دوم به تعداد چهار مرتبۀ دیگر حلقۀ for
از متد ()run
از کلاس ThreadB
را اجرا کرده و در نهایت اجرای برنامه به پایان میرسد.
نحوۀ ساخت تِرِد با بهکارگیری اینترفیس Runnable
در این بخش از آموزش قصد داریم تا با ایپلیمنت کردن اینترفیسی از پیش تعریفشده تحت عنوان Runnable
، در ابتدا یک تِرِد ایجاد کرده و در ادامه به بررسی مفهوم مالتیتِرِدینگ با بهکارگیری این اینترفیس بپردازیم. بنابراین پروژۀ دیگری تحت عنوان Runnable ایجاد کرده و کلاسی به نام ThreadA
در آن میسازیم که در ابتدا کدی به صورت زیر خواهیم داشت:
public class ThreadA {
}
به طور کلی، میتوان گفت که در این روش به منظور ایجاد یک تِرِد از اینترفیسی تحت عنوان Runnable
استفاده کرده و آن را در کلاس فوق ایمپلیمنت مینماییم. در واقع، همانطور که در ابتدای آموزش اشاره کردیم، با پیادهسازی اینترفیس مذکور در کلاس ThreadA
میتوانیم بدون ارثبری از کلاس Thread
تِرِدهای مورد نظر به منظور اجرای برنامه را بسازیم که در همین راستا در ادامه اینترفیس Runnable
را در کلاس فوق ایمپلیمنت کرده و کد آن را به صورت زیر تکمیل مینماییم:
public class ThreadA implements Runnable {
public void run() {
System.out.println("Thread A");
for (int i = 1; i <= 5; i++) {
System.out.println("From My First Thread, loop no: " + i);
}
}
}
در کد فوق، ابتدا نام کلاس را نوشته سپس کیورد implemets
و در ادامه نام اینترفیس Runnable
را نوشتهایم که بدین ترتیب قصد داریم تا اینترفیس مذکور را در کلاس ThreadA
ایمپلیمنت نماییم. بنابراین در ادامه دستورات داخلی متد ()run
از اینترفیس Runnable
را پیادهسازی مینماییم چرا که متد ()run
در اینترفیس Runnable
یک متد بدون دستورات داخلی بوده و بدین طریق میتوانیم دستورات مورد نظر خود را در آن پیادهسازی نماییم. در واقع، متد ()run
دستوراتی را شامل میشود که قصد داریم تا پس از ساخت تِرِد مورد نظر توسط آن اجرا شوند.
در تفسیر دستورات داخلی متد ()run
باید گفت که ابتدا استرینگ «Thread A» به منزلۀ آغاز اجرای تِرِد اول چاپ شده و مشابه مثال پیشین، حلقۀ for
به تعداد پنج مرتبه تکرار شده و در هر مرتبه مقدار منتسب به متغیر i
به همراه استرینگ «:From My First Thread, loop no» را در کنسول چاپ میکند (توجه داشته باشیم که در هر بار اجرای حلقه مقدار منتسب به متغیر i
یک واحد افزایش یافته و اجرای حلقه تا زمان رسیدن مقدار متغیر i
به عدد 5 ادامه مییابد.) در این مرحله به منظور اجرای کلاس فوق و ساخت تِرِد، کلاس دیگری تحت عنوان ActionClass
ایجاد کرده و در حین ساخت کلاس نیز تیک گزینۀ public static void main را میزنیم که در ابتدا کدی به صورت زیر خواهیم داشت:
public class ActionClass {
public static void main(String[] args) {
}
}
در ادامه، آبجکتی از روی کلاس ThreadA
ایجاد کرده و قصد داریم تا با فراخوانی متد ()start
روی آبجکت مذکور تِرِدی ساخته و بدین ترتیب متد ()run
را با استفاده از آن تِرِد اجرا نماییم که برای این منظور کد فوق را به صورت زیر تکمیل میکنیم:
public class ActionClass {
public static void main(String[] args) {
ThreadA test = new ThreadA();
}
}
در کد فوق، آبجکتی تحت عنوان test
از روی کلاس ThreadA
ساختهایم و در ادامه به منظور دسترسی به متد ()start
و فراخوانی آن از کلاس Thread
میباید آبجکتی از روی کلاس Thread
ایجاد کرده و در ادامه آبجکت test
را به کانستراکتور این کلاس پاس دهیم که بدین ترتیب در ادامه میتوانیم متد ()start
را روی آبجکت جدید ساختهشده از روی کلاس Thread
فراخوانی نماییم. بنابراین به منظور ساخت آبجکت جدید از روی کلاس Thread
کد فوق را به صورت زیر تکمیل مینماییم:
public class ActionClass {
public static void main(String[] args) {
ThreadA test = new ThreadA();
Thread thread = new Thread(test);
thread.start();
}
}
همانطور که ملاحظه میکنیم، آبجتی به نام thread
از روی کلاس Thread
ساخت و آبجکت test
را داخل علائم ( )
در سطر چهارم درج کرده و بدین طریق آن را به کانستراکتور کلاس Thread
پاس دادهایم که در این صورت آبجکت جدیدی به نام thread
از روی کلاس Thread
ساخته میشود و در ادامه متد ()start
از این کلاس را روی آبجکت جدید ساختهشده فراخوانی مینماییم. حال برنامۀ فوق را اجرا کرده و در خروجی خواهیم داشت:
Thread A
From My First Thread, loop no: 1
From My First Thread, loop no: 2
From My First Thread, loop no: 3
From My First Thread, loop no: 4
From My First Thread, loop no: 5
همانطور که میبینیم، تِرِد مورد نظر ایجاد شده و متد ()run
را اجرا کرده و منجر به چاپ استرینگهای تعریفشده داخل حلقۀ for
گردیده است به طوری که دستورات داخلی حلقۀ for
پنج مرتبه تکرار شده و در نهایت اجرای برنامه متوقف شده است.
حال اگر بخواهیم تا نحوۀ اجرای برنامه را به صورت مالتیتِرِد مورد بررسی قرار دهیم، نیاز است تا کلاس دیگری تحت عنوان ThreadB
ایجاد کرده و بدین ترتیب تِرِد دومی ساخته و برنامۀ فوق را با دو تِرِد اجرا نماییم. بنابراین کلاس دیگری به نام ThreadB
داخل پروژهٔ خود ایجاد کرده و در ابتدا کدی به صورت زیر خواهیم داشت:
public class ThreadB implements Runnable {
}
در ادامه، کلاس فوق را از روی اینترفیس Runnable
ایمپلیمنت کرده و متد ()run
را در آن پیادهسازی مینماییم که برای این منظور کد فوق را به صورت زیر تکمیل میکنیم:
public class ThreadB implements Runnable {
public void run() {
System.out.println("Thread B");
for (int i = 1; i <= 5; i++) {
System.out.println("From My Second Thread, loop no: " + i);
}
}
}
همانطور که در کد فوق میبینیم، مشابه کلاس ThreadA
متد ()run
را به گونهای پیادهسازی نمودهایم که در صورت فراخوانی ابتدا استرینگ «Thread B» مبنی بر آغاز اجرای برنامه توسطر تِرِد دوم چاپ شده و در ادامه حلقۀ for
اجرا میشود که بدین ترتیب استرینگ «:From My Second Thread, loop no» به همراه مقدار منتسب به متغیر i
پنج مرتبه در کنسول چاپ میگردد به طوری که در هر مرتبه اجرای آن نیز یک واحد به مقدار i
افزوده میشود تا در صورت رسیدن این مقدار به عدد 5 اجرای حلقه متوقف گردد. حال به منظور اجرای کلاس فوق و ساخت تِرِد دوم به کلاس ActionClass
بازگشته و مشابه کلاس ThreadA
آبجکتی از روی کلاس ThreadB
به صورت زیر میسازیم:
public class ActionClass {
public static void main(String[] args) {
ThreadA test = new ThreadA();
Thread thread = new Thread(test);
thread.start();
// Second Object
ThreadB testB = new ThreadB();
Thread threadB = new Thread(testB);
threadB.start();
}
}
همانطور که در کد فوق میبینیم، ابتدا آبجکتی تحت عنوان testB
از روی کلاس ThreadB
ساخته و در ادامه به منظور ساخت آبجکتی از روی کلاس Thread
آبجکت testB
را به کانستراکتور کلاس Thread
پاس میدهیم و بدین ترتیب به متد ()start
از کلاس Thread
دسترسی داشته و آن را روی آبجکت جدید ساختهشده فراخوانی مینماییم که در نتیجۀ فراخوانی این متد، تِرِد دیگری ساخته شده و متد ()run
از کلاس ThreadB
فراخوانی میگردد به طوری که با اجرای برنامۀ فوق در خروجی خواهیم داشت:
Thread A
Thread B
From My First Thread, loop no: 1
From My Second Thread, loop no: 1
From My Second Thread, loop no: 2
From My Second Thread, loop no: 3
From My First Thread, loop no: 2
From My Second Thread, loop no: 4
From My First Thread, loop no: 3
From My Second Thread, loop no: 5
From My First Thread, loop no: 4
From My First Thread, loop no: 5
مشابه روش پیشین در این مورد نیز برنامه به صورت مالتیتِرِد اجرا شده است به طوری که در ابتدا هر دو تِرِد ایجاد شده و در ادامه حلقۀ for
از کلاس ThreadA
یک مرتبه توسط تِرِد اول اجرا شده سپس تِرِد دوم حلقۀ for
از کلاس ThreadB
را سه مرتبه اجرا میکند. در ادامه، تِرِد اول با در اختیار داشتن منابع سیستم اجرای حلقۀ for
از کلاس ThreadA
را از سر گرفته و یک مرتبۀ دیگر آن را اجرا کرده سپس تِرِد دوم منابع سیستم را در اختیار گرفته و برای بار چهارم حلقۀ for
از کلاس ThreadB
را اجرا مینماید و این مراحل تا زمانی ادامه مییابد که هر دو حلقۀ for
از کلاسهای مذکور پنج مرتبه تکرار شده و استرینگهای مربوطه را در کنسول نمایش دهند.
در این آموزش به بررسی کاربرد تِرِدها در اجرای برنامه پرداخته و نحوۀ ایجاد یک تِرِد با بهکارگیری دو روش مختلف در زبان برنامهنویسی جاوا را آموختیم و دیدیم که چگونه میتوان با استفاده از هر یک از روشهای مذکور برنامهای را پیادهسازی کرد که به صورت مالتیتِرِد اجرا شود.