مالتی تردینگ (Multithreading) در جاوا یک قابلیت قدرتمند است که به برنامهها اجازه میدهد چندین کار را به صورت همزمان اجرا کنند. این ویژگی باعث افزایش کارایی برنامه و استفاده بهتر از منابع سختافزاری میشود. در این مقاله، به معرفی مفهوم مالتی تردینگ، نحوه پیادهسازی آن در جاوا و مدیریت تردها خواهیم پرداخت.
مالتی تردینگ به معنای اجرای همزمان چندین رشته پردازشی (Thread) در یک برنامه است. در جاوا، هر برنامه حداقل یک ترد اصلی (Main Thread) دارد که اجرای برنامه را کنترل میکند.
✅ افزایش کارایی برنامه
✅ استفاده بهینه از پردازنده (CPU Utilization)
✅ کاهش زمان پاسخگویی در برنامههای گرافیکی و شبکهای
✅ اجرای چندین وظیفه بهطور همزمان
در جاوا، دو روش اصلی برای ایجاد یک ترد وجود دارد:
Thread
class MyThread extends Thread {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println("Thread: " + Thread.currentThread().getName() + " - Count: " + i);
try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
}
}
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
t1.start();
t2.start();
}
}
✅در این روش، کلاس MyThread
از Thread
ارثبری کرده و متد run()
را پیادهسازی میکند. سپس با متد start()
ترد اجرا میشود.
۲. استفاده از اینترفیس Runnable
class MyRunnable implements Runnable {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println("Runnable Thread: " + Thread.currentThread().getName() + " - Count: " + i);
try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
}
}
public static void main(String[] args) {
Thread t1 = new Thread(new MyRunnable());
Thread t2 = new Thread(new MyRunnable());
t1.start();
t2.start();
}
}
✅ این روش برای پیادهسازی چندکلاسه و جلوگیری از محدودیت ارثبری در جاوا بهتر است.
در برنامههای چندنخی، وقتی چندین ترد به یک منبع مشترک دسترسی دارند، باید از Synchronization استفاده کنیم.
class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
}
public class SyncExample {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
Thread t1 = new Thread(() -> { for (int i = 0; i < 1000; i++) counter.increment(); });
Thread t2 = new Thread(() -> { for (int i = 0; i < 1000; i++) counter.increment(); });
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final Count: " + counter.getCount());
}
}
✅ کلمه کلیدی synchronized
باعث میشود دو ترد همزمان به متد increment()
دسترسی نداشته باشند و از شرایط رقابتی (Race Condition) جلوگیری شود.
✅ متد join تضمین میکند که برنامه،قبل از نمایش نتیجه،منتظر پایان تردها بماند.
✅ اگر syncronized حذف شود،شرایط رقابتی پیش میاد و مقدار count نادرست خواهد بود.
Thread
و Runnable
روش پیادهسازی : ارثبری از کلاس Thread و
پیادهسازی اینترفیس Runnable
محدودیت ارثبری : در استفاده از کلاس Thread
فقط از Thread
ارث میبرد،در استفاده از Runnable میتوان از چند کلاس ارثبری کرد
قابلیت استفاده مجدد: در استفاده از کلاس Thread
کمتر،در استفاده از Runnable بیشتر
عملکرد در پردازشها: در استفاده از کلاس Thread
کم،در استفاده از Runnable بهینه تر
✅ توصیه: اگر کلاس شما از قبل از کلاس دیگری ارثبری کرده است، بهتر است از Runnable
استفاده کنید.
ExecutorService
در جاوا، استفاده از ExecutorService
برای مدیریت تردها توصیه میشود:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(3);
for (int i = 1; i <= 5; i++) {
int task = i;
executor.submit(() -> {
System.out.println("Executing Task: " + task + " - Thread: " + Thread.currentThread().getName());
});
}
executor.shutdown();
}
}
✅ این روش باعث مدیریت بهینه منابع و افزایش عملکرد برنامه میشود.
✅ در این کد، 5 تسک با 3 ، thread انجام میشود.
✅ متد submit برای ارسال تسک به threadpool، انجام میشود.
✅ پس از ارسال همه تسکها، متد shutdown()
برای بستن ExecutorService
و آزادسازی منابع استفاده میشود. این متد تضمین میکند که هیچ تسک جدیدی به ThreadPool اضافه نمیشود، ولی تسکهای در حال اجرا تمام خواهند شد.
ExecutorService
میتوانید تعداد تردها را محدود کنید و منابع را بهینهسازی کنید.✅ اگر در برنامهای چند تردی دارید که با دادههای مشترک کار میکند، نیاز به همگامسازی (synchronization) خواهید داشت. در این کد خاص، چون تردها فقط عملیات مستقل چاپ انجام میدهند و به دادههای مشترک دسترسی ندارند، synchronized
لازم نیست:
public class ExecutorExample {
private static int counter = 0;
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(3);
for (int i = 1; i <= 5; i++) {
executor.submit(() -> {
synchronized (ExecutorExample.class) { // Synchronizing access to the shared variable
counter++;
System.out.println("Executing Task: " + counter + " - Thread: " + Thread.currentThread().getName());
}
});
}
executor.shutdown();
}
}
✅ در اینجا، از synchronized
برای همگامسازی دسترسی به متغیر counter
استفاده شده است تا مقدار آن به طور ایمن توسط چند ترد تغییر یابد.
🔹 مالتی تردینگ در جاوا به برنامه اجازه میدهد تا وظایف مختلف را همزمان اجرا کند.
🔹 دو روش اصلی برای ایجاد ترد وجود دارد: ارثبری از Thread
و پیادهسازی Runnable
.
🔹 استفاده از Synchronization برای جلوگیری از تداخل تردها ضروری است.
🔹 برای مدیریت بهتر، میتوان از ExecutorService استفاده کرد.