জাভাতে মাল্টিথ্রেডিং ও কনকারেন্সি ব্যবস্থাপনা সহজ করার জন্য কিছু ক্লাসিক্যাল Design Patterns ব্যবহার করা হয়। এর মধ্যে সবচেয়ে গুরুত্বপূর্ণ দুটি হল:
- Producer-Consumer Pattern
- Readers-Writers Pattern
১. Producer-Consumer Pattern
বিবরণ:
- Producer-Consumer প্যাটার্ন একটি সাধারণ কনকারেন্সি সমস্যা যেখানে একাধিক প্রযোজক (Producer) ডেটা তৈরি করে এবং একাধিক গ্রাহক (Consumer) সেই ডেটা প্রসেস করে।
- BlockingQueue ব্যবহার করলে এটি সহজ হয়।
সমস্যার সমাধান:
- একটি shared buffer (queue) ব্যবহার করা হয়।
- প্রযোজক ডেটা যোগ করে এবং গ্রাহক ডেটা তুলে নেয়।
- যদি কিউ পূর্ণ থাকে, প্রযোজক অপেক্ষা করে।
- যদি কিউ খালি থাকে, গ্রাহক অপেক্ষা করে।
উদাহরণ:
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
class Producer implements Runnable {
private BlockingQueue<Integer> queue;
public Producer(BlockingQueue<Integer> queue) {
this.queue = queue;
}
@Override
public void run() {
try {
for (int i = 1; i <= 10; i++) {
System.out.println("Produced: " + i);
queue.put(i); // কিউতে ডেটা যোগ করা
Thread.sleep(500); // ডেটা তৈরি করার সময়
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
class Consumer implements Runnable {
private BlockingQueue<Integer> queue;
public Consumer(BlockingQueue<Integer> queue) {
this.queue = queue;
}
@Override
public void run() {
try {
while (true) {
Integer data = queue.take(); // কিউ থেকে ডেটা নেওয়া
System.out.println("Consumed: " + data);
Thread.sleep(1000); // ডেটা প্রসেস করার সময়
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
public class ProducerConsumerExample {
public static void main(String[] args) {
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(5);
Thread producerThread = new Thread(new Producer(queue));
Thread consumerThread = new Thread(new Consumer(queue));
producerThread.start();
consumerThread.start();
}
}
কী ঘটবে:
- প্রযোজক ডেটা তৈরি করে কিউতে যোগ করবে।
- গ্রাহক কিউ থেকে ডেটা তুলে নেবে।
- কিউ পূর্ণ হলে প্রযোজক থামবে এবং কিউ খালি হলে গ্রাহক থামবে।
২. Readers-Writers Pattern
বিবরণ:
- Readers-Writers প্যাটার্ন এমন পরিস্থিতিতে ব্যবহৃত হয় যেখানে অনেক থ্রেড পড়তে (read) এবং কিছু থ্রেড লিখতে (write) চায়।
- লক্ষ্য:
- রিডারদের মধ্যে সমান্তরাল পড়ার অনুমতি দিন।
- রাইটারদের একচেটিয়াভাবে (exclusive) লিখতে দিন।
- রিডার ও রাইটারদের মধ্যে প্রায়োরিটি সঠিকভাবে বজায় রাখুন।
উদাহরণ:
import java.util.concurrent.locks.ReentrantReadWriteLock;
class SharedResource {
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private int data = 0;
public void write(int value) {
lock.writeLock().lock(); // রাইট লক নিন
try {
System.out.println(Thread.currentThread().getName() + " is writing: " + value);
data = value;
Thread.sleep(1000); // লেখার সময়
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.writeLock().unlock(); // রাইট লক মুক্ত করুন
}
}
public int read() {
lock.readLock().lock(); // রিড লক নিন
try {
System.out.println(Thread.currentThread().getName() + " is reading: " + data);
Thread.sleep(500); // পড়ার সময়
return data;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return -1;
} finally {
lock.readLock().unlock(); // রিড লক মুক্ত করুন
}
}
}
public class ReadersWritersExample {
public static void main(String[] args) {
SharedResource resource = new SharedResource();
// রিডার থ্রেড
Runnable readerTask = () -> {
while (true) {
resource.read();
}
};
// রাইটার থ্রেড
Runnable writerTask = () -> {
int value = 1;
while (true) {
resource.write(value++);
}
};
// থ্রেড চালানো
Thread reader1 = new Thread(readerTask, "Reader-1");
Thread reader2 = new Thread(readerTask, "Reader-2");
Thread writer = new Thread(writerTask, "Writer");
reader1.start();
reader2.start();
writer.start();
}
}
কী ঘটবে:
- রিডাররা একসঙ্গে পড়তে পারবে।
- রাইটার একা ডেটা লিখবে এবং সেই সময় অন্য রিডার বা রাইটার ঢুকতে পারবে না।
Producer-Consumer এবং Readers-Writers এর তুলনা
| বৈশিষ্ট্য | Producer-Consumer | Readers-Writers |
|---|---|---|
| ব্যবহার ক্ষেত্র | ডেটা উৎপাদন ও ব্যবস্থাপনা | পড়া ও লেখা পরিচালনা |
| থ্রেড সমন্বয় | প্রযোজক এবং গ্রাহকের মধ্যে সমন্বয় | রিডার এবং রাইটারের মধ্যে সমন্বয় |
| কনকারেন্সি লেভেল | প্রযোজক বা গ্রাহক একত্রে কাজ করতে পারে না | একাধিক রিডার একত্রে কাজ করতে পারে |
| সুবিধা | সরল এবং থ্রেড-সেফ | ডেটার উপর নিয়ন্ত্রণ এবং সমান্তরাল পড়া |
- Producer-Consumer Pattern:
- ব্যবহার করুন যখন একটি থ্রেড ডেটা তৈরি করবে এবং অন্যটি তা প্রসেস করবে।
- BlockingQueue এর মত স্ট্রাকচার ব্যবহার করে সহজ করা যায়।
- Readers-Writers Pattern:
- ব্যবহার করুন যেখানে পড়ার অপারেশন বেশি এবং লেখার অপারেশন কম।
- ReentrantReadWriteLock এর মাধ্যমে রিডারদের সমান্তরাল পড়ার অনুমতি দিন এবং রাইটারদের একচেটিয়াভাবে লিখতে দিন।
এই প্যাটার্নগুলো সঠিকভাবে প্রয়োগ করলে মাল্টিথ্রেডেড অ্যাপ্লিকেশন আরও কার্যকর ও দক্ষ হবে।
Content added By
Read more