Deadlock হলো একটি অবস্থা যেখানে দুটি বা তার বেশি থ্রেড একে অপরের থেকে রিসোর্স অধিকার করতে গিয়ে অনির্দিষ্ট সময়ের জন্য অপেক্ষা করে। এর ফলে থ্রেডগুলি তাদের কাজ সম্পন্ন করতে পারে না, এবং পুরো প্রোগ্রাম স্থবির হয়ে যায়।
Deadlock ঘটার কারণ
Deadlock সাধারণত তখন ঘটে যখন:
- বহু রিসোর্স ব্যবহৃত হয়: একাধিক থ্রেড বিভিন্ন রিসোর্সে অ্যাক্সেস করতে চায়, কিন্তু একটি রিসোর্স লক করা থাকে।
- লকিং অর্ডার বিভ্রান্তিকর: থ্রেডগুলো রিসোর্সে অ্যাক্সেস করার জন্য ভিন্ন অর্ডার অনুসরণ করে।
- নন-প্রি-এম্পটিভ লক: রিসোর্সটি লক হয়ে গেলে অন্য থ্রেড তা পুনরুদ্ধার করতে পারে না।
- সাইক্লিক ওয়েটিং: একাধিক থ্রেড একে অপরের ওপর নির্ভর করে, ফলে একটি চক্র তৈরি হয়।
Deadlock এর শর্তসমূহ (Necessary Conditions)
- Mutual Exclusion: একটি রিসোর্স একবারে শুধুমাত্র একটি থ্রেড ব্যবহার করতে পারে।
- Hold and Wait: একটি থ্রেড একটি রিসোর্স ধরে রেখে অন্য রিসোর্সের জন্য অপেক্ষা করে।
- No Preemption: একটি রিসোর্স বাধ্যতামূলকভাবে অন্য থ্রেড থেকে নেওয়া যায় না।
- 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 কিভাবে ঘটছে:
Thread 1প্রথমেresource1লক করে এবংresource2এর জন্য অপেক্ষা করে।Thread 2প্রথমেresource2লক করে এবংresource1এর জন্য অপেক্ষা করে।- এই সাইক্লিক ওয়েটিং এর ফলে 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
- লকিং অর্ডার নির্ধারণ করুন: সব থ্রেড একই অর্ডারে রিসোর্স লক করবে।
- Minimize Synchronization: শুধুমাত্র প্রয়োজনীয় কোড ব্লকে
synchronizedব্যবহার করুন। - Timeout ব্যবহার করুন:
tryLock()এর মতো মেথড ব্যবহার করে নির্দিষ্ট সময়ের জন্য অপেক্ষা করুন। - Avoid Nested Locks: সম্ভব হলে লকগুলিকে নেস্টিং থেকে বিরত রাখুন।
- Deadlock Monitoring Tools: ডেডলক সনাক্ত করতে ডেডিকেটেড টুল ব্যবহার করুন যেমন
jvisualvm।
Deadlock হলো কনকারেন্ট প্রোগ্রামিংয়ের একটি সাধারণ সমস্যা, যা থ্রেডগুলির ভুল ব্যবস্থাপনার ফলে ঘটে। তবে সঠিক কৌশল এবং সেরা অনুশীলন অনুসরণ করলে Deadlock এড়ানো সম্ভব। Deadlock এড়াতে রিসোর্স অর্ডারিং, tryLock, এবং timeout ব্যবহারের মাধ্যমে উন্নত কনকারেন্সি মেকানিজম তৈরি করা যায়।
Read more