জাভা কনকারেন্সি হল এমন একটি প্রযুক্তি, যা একই সময়ে একাধিক টাস্ক বা প্রক্রিয়া সম্পাদন করতে সক্ষম করে। কনকারেন্সি ব্যবহার করে, একটি প্রোগ্রাম একই সময়ে একাধিক থ্রেড পরিচালনা করতে পারে, যা মডার্ন সিস্টেমের মাল্টি-কোর প্রসেসরের সুবিধা নেয়।
কনকারেন্সির গুরুত্বপূর্ণ বিষয়
- থ্রেড (Thread): একটি প্রোগ্রামের ক্ষুদ্রতম এক্সিকিউটেবল ইউনিট। একাধিক থ্রেড একসাথে কাজ করতে পারে।
- প্রসেস (Process): একটি সম্পূর্ণ অ্যাপ্লিকেশন বা প্রোগ্রাম।
- সিঙ্ক্রোনাইজেশন (Synchronization): থ্রেডের মধ্যে ডেটা শেয়ার করার সময় ডেটা রেস এবং অসঙ্গতি এড়ানোর প্রক্রিয়া।
- লকিং (Locking): থ্রেডগুলোর মধ্যে সঠিক সিকোয়েন্স মেনে ডেটা অ্যাক্সেস করতে সাহায্য করে।
- মাল্টি-থ্রেডিং (Multi-threading): একাধিক থ্রেডের মাধ্যমে একই অ্যাপ্লিকেশন চলানো।
Java Concurrency এর মৌলিক কনসেপ্ট
১. Thread Creation (থ্রেড তৈরি করা)
জাভায় দুটি উপায়ে থ্রেড তৈরি করা যায়:
- Thread Class:
Threadক্লাস এক্সটেন্ড করে। - Runnable Interface:
Runnableইন্টারফেস ইমপ্লিমেন্ট করে।
উদাহরণ:
// Thread ক্লাস ব্যবহার করে
class MyThread extends Thread {
public void run() {
System.out.println("Thread is running");
}
}
public class ThreadExample {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start(); // Thread শুরু
}
}
// Runnable ইন্টারফেস ব্যবহার করে
class MyRunnable implements Runnable {
public void run() {
System.out.println("Runnable is running");
}
}
public class RunnableExample {
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start();
}
}
২. Synchronization (সিঙ্ক্রোনাইজেশন)
যখন একাধিক থ্রেড একই রিসোর্সে কাজ করে, তখন ডেটা অসঙ্গতি এড়ানোর জন্য সিঙ্ক্রোনাইজেশন প্রয়োজন।
উদাহরণ:
class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
}
public class SynchronizationExample {
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());
}
}
৩. Executor Framework (থ্রেড পুলিং)
Java Executor framework ব্যবহারের মাধ্যমে থ্রেড ম্যানেজমেন্ট আরও সহজ করা যায়। এটি নতুন থ্রেড তৈরি করার পরিবর্তে থ্রেড পুল থেকে থ্রেড পুনর্ব্যবহার করে।
উদাহরণ:
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 = 0; i < 5; i++) {
final int taskId = i;
executor.execute(() -> {
System.out.println("Task " + taskId + " is running");
});
}
executor.shutdown(); // থ্রেড পুল বন্ধ করুন
}
}
৪. Callable এবং Future
Callable ইন্টারফেস ব্যবহার করে থ্রেড থেকে রিটার্ন ভ্যালু পাওয়া যায়, যা Runnable-এ সম্ভব নয়। Future অবজেক্ট থ্রেডের আউটপুট অ্যাক্সেস করতে ব্যবহার করা হয়।
উদাহরণ:
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class CallableExample {
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newSingleThreadExecutor();
Callable<Integer> callableTask = () -> {
int sum = 0;
for (int i = 1; i <= 10; i++) {
sum += i;
}
return sum;
};
Future<Integer> result = executor.submit(callableTask);
System.out.println("Sum: " + result.get()); // আউটপুট পেতে `get()` ব্যবহার করা হয়
executor.shutdown();
}
}
৫. BlockingQueue
BlockingQueue থ্রেডগুলোর মধ্যে ডেটা শেয়ার করতে এবং প্রোডিউসার-কনজিউমার সমস্যার সমাধান করতে ব্যবহার করা হয়।
উদাহরণ:
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class BlockingQueueExample {
public static void main(String[] args) {
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(5);
// Producer Thread
Thread producer = new Thread(() -> {
try {
for (int i = 0; i < 10; i++) {
queue.put(i);
System.out.println("Produced: " + i);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
// Consumer Thread
Thread consumer = new Thread(() -> {
try {
for (int i = 0; i < 10; i++) {
int value = queue.take();
System.out.println("Consumed: " + value);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
producer.start();
consumer.start();
}
}
জাভা কনকারেন্সির সুবিধা
- মাল্টি-কোর প্রসেসরের সম্পূর্ণ সুবিধা নেওয়া।
- উচ্চ পারফরম্যান্স এবং রেসপন্সিভ অ্যাপ্লিকেশন তৈরি।
- জটিল টাস্কগুলো সহজে ডিভাইড এবং ম্যানেজ করা।
জাভা কনকারেন্সির চ্যালেঞ্জ
- ডেটা রেস (Data Race): একাধিক থ্রেড একই ডেটায় একসাথে কাজ করলে সমস্যা হয়।
- ডেডলক (Deadlock): থ্রেড একে অপরকে অপেক্ষা করতে বাধ্য করে।
- রিসোর্স কন্টেনশন (Resource Contention): একাধিক থ্রেড একই রিসোর্সের জন্য প্রতিযোগিতা করে।
জাভা কনকারেন্সি একটি শক্তিশালী টুল, যা উচ্চ পারফরম্যান্স এবং স্কেলেবল অ্যাপ্লিকেশন তৈরি করতে সাহায্য করে। তবে সঠিক পরিকল্পনা এবং থ্রেড নিরাপত্তা নিশ্চিত করা আবশ্যক।
Read more