Deadlock কি এবং কেন ঘটে?

Deadlock, Livelock, এবং Starvation - জাভা কনকারেন্সি (Java Concurrency) - Java Technologies

470

Deadlock হলো একটি অবস্থা যেখানে দুটি বা তার বেশি থ্রেড একে অপরের থেকে রিসোর্স অধিকার করতে গিয়ে অনির্দিষ্ট সময়ের জন্য অপেক্ষা করে। এর ফলে থ্রেডগুলি তাদের কাজ সম্পন্ন করতে পারে না, এবং পুরো প্রোগ্রাম স্থবির হয়ে যায়।


Deadlock ঘটার কারণ

Deadlock সাধারণত তখন ঘটে যখন:

  1. বহু রিসোর্স ব্যবহৃত হয়: একাধিক থ্রেড বিভিন্ন রিসোর্সে অ্যাক্সেস করতে চায়, কিন্তু একটি রিসোর্স লক করা থাকে।
  2. লকিং অর্ডার বিভ্রান্তিকর: থ্রেডগুলো রিসোর্সে অ্যাক্সেস করার জন্য ভিন্ন অর্ডার অনুসরণ করে।
  3. নন-প্রি-এম্পটিভ লক: রিসোর্সটি লক হয়ে গেলে অন্য থ্রেড তা পুনরুদ্ধার করতে পারে না।
  4. সাইক্লিক ওয়েটিং: একাধিক থ্রেড একে অপরের ওপর নির্ভর করে, ফলে একটি চক্র তৈরি হয়।

Deadlock এর শর্তসমূহ (Necessary Conditions)

  1. Mutual Exclusion: একটি রিসোর্স একবারে শুধুমাত্র একটি থ্রেড ব্যবহার করতে পারে।
  2. Hold and Wait: একটি থ্রেড একটি রিসোর্স ধরে রেখে অন্য রিসোর্সের জন্য অপেক্ষা করে।
  3. No Preemption: একটি রিসোর্স বাধ্যতামূলকভাবে অন্য থ্রেড থেকে নেওয়া যায় না।
  4. Circular Wait: একাধিক থ্রেড এমনভাবে অপেক্ষা করে যে তারা একটি চক্র তৈরি করে।

Deadlock উদাহরণ

নিচে একটি সহজ উদাহরণ দেওয়া হলো যেখানে Deadlock ঘটে:

public class DeadlockExample {
    public static void main(String[] args) {
        final Object resource1 = "Resource 1";
        final Object resource2 = "Resource 2";

        // Thread 1
        Thread thread1 = new Thread(() -> {
            synchronized (resource1) {
                System.out.println("Thread 1: Locked resource 1");

                try { Thread.sleep(100); } catch (InterruptedException e) {}

                synchronized (resource2) {
                    System.out.println("Thread 1: Locked resource 2");
                }
            }
        });

        // Thread 2
        Thread thread2 = new Thread(() -> {
            synchronized (resource2) {
                System.out.println("Thread 2: Locked resource 2");

                try { Thread.sleep(100); } catch (InterruptedException e) {}

                synchronized (resource1) {
                    System.out.println("Thread 2: Locked resource 1");
                }
            }
        });

        thread1.start();
        thread2.start();
    }
}

Deadlock কিভাবে ঘটছে:

  1. Thread 1 প্রথমে resource1 লক করে এবং resource2 এর জন্য অপেক্ষা করে।
  2. Thread 2 প্রথমে resource2 লক করে এবং resource1 এর জন্য অপেক্ষা করে।
  3. এই সাইক্লিক ওয়েটিং এর ফলে Deadlock ঘটে।

Deadlock প্রতিরোধের কৌশল

১. রিসোর্স লক করার অর্ডার নির্ধারণ করুন

সব থ্রেডকে একটি নির্দিষ্ট অর্ডারে রিসোর্স লক করতে বাধ্য করুন।

public class DeadlockPrevention {
    public static void main(String[] args) {
        final Object resource1 = "Resource 1";
        final Object resource2 = "Resource 2";

        Thread thread1 = new Thread(() -> {
            synchronized (resource1) {
                System.out.println("Thread 1: Locked resource 1");

                synchronized (resource2) {
                    System.out.println("Thread 1: Locked resource 2");
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (resource1) { // একই অর্ডার অনুসরণ
                System.out.println("Thread 2: Locked resource 1");

                synchronized (resource2) {
                    System.out.println("Thread 2: Locked resource 2");
                }
            }
        });

        thread1.start();
        thread2.start();
    }
}

২. Try-Lock ব্যবহার করুন

tryLock() মেথড ব্যবহার করে থ্রেডকে Deadlock এড়ানোর জন্য নির্দিষ্ট সময়ের জন্য অপেক্ষা করান।

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

public class TryLockExample {
    public static void main(String[] args) {
        final Lock lock1 = new ReentrantLock();
        final Lock lock2 = new ReentrantLock();

        Thread thread1 = new Thread(() -> {
            try {
                if (lock1.tryLock() && lock2.tryLock()) {
                    System.out.println("Thread 1: Acquired both locks");
                }
            } finally {
                lock1.unlock();
                lock2.unlock();
            }
        });

        Thread thread2 = new Thread(() -> {
            try {
                if (lock2.tryLock() && lock1.tryLock()) {
                    System.out.println("Thread 2: Acquired both locks");
                }
            } finally {
                lock2.unlock();
                lock1.unlock();
            }
        });

        thread1.start();
        thread2.start();
    }
}

৩. Circular Wait এড়ানো

একটি কেন্দ্রীয় রিসোর্স অর্ডারিং মেকানিজম তৈরি করুন। থ্রেডগুলি সর্বদা অর্ডারের নীচে থাকা রিসোর্স লক করবে।


৪. Timeout ব্যবহার করুন

রিসোর্স অ্যাক্সেস করার সময় নির্দিষ্ট timeout সেট করুন।


৫. ডেডলক সনাক্তকরণ এবং সমাধান

ডেডলক সনাক্ত করার জন্য থ্রেড ডাম্প ব্যবহার করুন। jstack কমান্ড বা ডিবাগার ব্যবহার করে থ্রেড অবস্থা বিশ্লেষণ করুন।


Deadlock থেকে বাঁচার Best Practices

  1. লকিং অর্ডার নির্ধারণ করুন: সব থ্রেড একই অর্ডারে রিসোর্স লক করবে।
  2. Minimize Synchronization: শুধুমাত্র প্রয়োজনীয় কোড ব্লকে synchronized ব্যবহার করুন।
  3. Timeout ব্যবহার করুন: tryLock() এর মতো মেথড ব্যবহার করে নির্দিষ্ট সময়ের জন্য অপেক্ষা করুন।
  4. Avoid Nested Locks: সম্ভব হলে লকগুলিকে নেস্টিং থেকে বিরত রাখুন।
  5. Deadlock Monitoring Tools: ডেডলক সনাক্ত করতে ডেডিকেটেড টুল ব্যবহার করুন যেমন jvisualvm

Deadlock হলো কনকারেন্ট প্রোগ্রামিংয়ের একটি সাধারণ সমস্যা, যা থ্রেডগুলির ভুল ব্যবস্থাপনার ফলে ঘটে। তবে সঠিক কৌশল এবং সেরা অনুশীলন অনুসরণ করলে Deadlock এড়ানো সম্ভব। Deadlock এড়াতে রিসোর্স অর্ডারিং, tryLock, এবং timeout ব্যবহারের মাধ্যমে উন্নত কনকারেন্সি মেকানিজম তৈরি করা যায়।

Content added By
Promotion

Are you sure to start over?

Loading...