Producer-Consumer Problem এর সমাধান

BlockingQueue এবং Producer-Consumer Pattern - জাভা কনকারেন্সি (Java Concurrency) - Java Technologies

269

Producer-Consumer Problem একটি ক্লাসিক কনকারেন্সি সমস্যা, যেখানে একটি প্রযোজক (Producer) ডেটা তৈরি করে এবং একটি গ্রাহক (Consumer) সেই ডেটা ব্যবহার করে। এই সমস্যা সমাধানের জন্য প্রযোজক এবং গ্রাহকের মধ্যে সিঙ্ক্রোনাইজেশন দরকার যাতে ডেটা লস বা ডেডলক না ঘটে।


সমাধান কৌশল

  1. BlockingQueue ব্যবহার করে: জাভার BlockingQueue ক্লাস এই সমস্যার জন্য সহজ ও কার্যকর সমাধান প্রদান করে।
  2. wait()-notify() মেথড ব্যবহার করে: ম্যানুয়ালি থ্রেড সিঙ্ক্রোনাইজেশনের মাধ্যমে সমস্যার সমাধান করা।
  3. Locks এবং Conditions ব্যবহার করে: লক এবং কন্ডিশন ভেরিয়েবল ব্যবহার করে আরও কাস্টমাইজড সমাধান।

BlockingQueue ব্যবহার করে সমাধান

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class ProducerConsumerWithBlockingQueue {
    public static void main(String[] args) {
        BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(5); // কিউ-এর আকার ৫

        // প্রযোজক থ্রেড
        Thread producer = new Thread(() -> {
            try {
                for (int i = 1; i <= 10; i++) {
                    queue.put(i); // কিউতে ডেটা যোগ করা
                    System.out.println("Produced: " + i);
                    Thread.sleep(500); // স্লিপ করে ধীরে উৎপাদন
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        // গ্রাহক থ্রেড
        Thread consumer = new Thread(() -> {
            try {
                while (true) {
                    int value = queue.take(); // কিউ থেকে ডেটা পড়া
                    System.out.println("Consumed: " + value);
                    Thread.sleep(1000); // স্লিপ করে ধীরে গ্রাহন
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        producer.start();
        consumer.start();
    }
}

কোডের ব্যাখ্যা

  • put() এবং take(): BlockingQueue স্বয়ংক্রিয়ভাবে ব্লক করে যদি কিউ পূর্ণ বা খালি থাকে।
  • সিঙ্ক্রোনাইজেশন: থ্রেড সেফটি নিশ্চিত করতে কোনও অতিরিক্ত লক বা wait-notify প্রয়োজন নেই।

wait()-notify() ব্যবহার করে সমাধান

import java.util.LinkedList;

class SharedResource {
    private final LinkedList<Integer> list = new LinkedList<>();
    private final int CAPACITY = 5;

    public synchronized void produce(int value) throws InterruptedException {
        while (list.size() == CAPACITY) {
            wait(); // কিউ পূর্ণ হলে অপেক্ষা
        }
        list.add(value);
        System.out.println("Produced: " + value);
        notify(); // গ্রাহককে জাগ্রত করা
    }

    public synchronized int consume() throws InterruptedException {
        while (list.isEmpty()) {
            wait(); // কিউ খালি হলে অপেক্ষা
        }
        int value = list.removeFirst();
        System.out.println("Consumed: " + value);
        notify(); // প্রযোজককে জাগ্রত করা
        return value;
    }
}

public class ProducerConsumerWithWaitNotify {
    public static void main(String[] args) {
        SharedResource sharedResource = new SharedResource();

        // প্রযোজক থ্রেড
        Thread producer = new Thread(() -> {
            try {
                for (int i = 1; i <= 10; i++) {
                    sharedResource.produce(i);
                    Thread.sleep(500);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        // গ্রাহক থ্রেড
        Thread consumer = new Thread(() -> {
            try {
                while (true) {
                    sharedResource.consume();
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        producer.start();
        consumer.start();
    }
}

কোডের ব্যাখ্যা

  • wait() এবং notify():
    • যখন কিউ পূর্ণ থাকে, প্রযোজক থ্রেড wait() করে।
    • যখন কিউ খালি থাকে, গ্রাহক থ্রেড wait() করে।
    • notify() ব্যবহার করে অপেক্ষমান থ্রেডকে জাগ্রত করা হয়।
  • সিঙ্ক্রোনাইজড ব্লক: মাল্টিথ্রেডেড এক্সেসকে সুরক্ষিত করে।

Locks এবং Conditions ব্যবহার করে সমাধান

import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class SharedResourceWithLock {
    private final LinkedList<Integer> list = new LinkedList<>();
    private final int CAPACITY = 5;
    private final Lock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();
    private final Condition notEmpty = lock.newCondition();

    public void produce(int value) throws InterruptedException {
        lock.lock();
        try {
            while (list.size() == CAPACITY) {
                notFull.await(); // কিউ পূর্ণ হলে অপেক্ষা
            }
            list.add(value);
            System.out.println("Produced: " + value);
            notEmpty.signal(); // গ্রাহককে জাগ্রত করা
        } finally {
            lock.unlock();
        }
    }

    public int consume() throws InterruptedException {
        lock.lock();
        try {
            while (list.isEmpty()) {
                notEmpty.await(); // কিউ খালি হলে অপেক্ষা
            }
            int value = list.removeFirst();
            System.out.println("Consumed: " + value);
            notFull.signal(); // প্রযোজককে জাগ্রত করা
            return value;
        } finally {
            lock.unlock();
        }
    }
}

public class ProducerConsumerWithLocks {
    public static void main(String[] args) {
        SharedResourceWithLock sharedResource = new SharedResourceWithLock();

        // প্রযোজক থ্রেড
        Thread producer = new Thread(() -> {
            try {
                for (int i = 1; i <= 10; i++) {
                    sharedResource.produce(i);
                    Thread.sleep(500);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        // গ্রাহক থ্রেড
        Thread consumer = new Thread(() -> {
            try {
                while (true) {
                    sharedResource.consume();
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        producer.start();
        consumer.start();
    }
}

কোডের ব্যাখ্যা

  • Lock এবং Condition:
    • notFull.await() এবং notEmpty.await() নির্দিষ্ট কন্ডিশনে থ্রেডকে অপেক্ষা করায়।
    • notFull.signal() এবং notEmpty.signal() ব্যবহার করে অপেক্ষমান থ্রেডকে জাগ্রত করা হয়।
  • উন্নত নিয়ন্ত্রণ: Condition ব্যবহারে নির্দিষ্ট কন্ডিশনের উপর ভিত্তি করে সিঙ্ক্রোনাইজেশন সহজ হয়।

  1. BlockingQueue: সরল এবং কার্যকর। BlockingQueue ব্যবহার করা সর্বাধিক সুপারিশকৃত সমাধান।
  2. wait()-notify(): বেশি কাস্টমাইজড এবং ম্যানুয়াল কনট্রোলের জন্য উপযোগী।
  3. Locks এবং Conditions: জটিল সমস্যার জন্য যেখানে স্পষ্ট এবং নির্দিষ্ট নিয়ন্ত্রণ প্রয়োজন।

Producer-Consumer সমস্যা সমাধানে এই পদ্ধতিগুলি জাভার কনকারেন্সি ফ্রেমওয়ার্কের শক্তি এবং নমনীয়তা প্রমাণ করে।

Content added By
Promotion

Are you sure to start over?

Loading...