Concurrent Collections কি?
Concurrent Collections হলো জাভার একটি সেট, যা মাল্টি-থ্রেডেড পরিবেশে ডেটা সেফটি এবং উচ্চ পারফরম্যান্স নিশ্চিত করতে ব্যবহৃত হয়। এই সংগ্রহগুলো বিশেষভাবে ডিজাইন করা হয়েছে যাতে একাধিক থ্রেড নিরাপদে শেয়ার করা ডেটার উপর অপারেশন করতে পারে।
উদাহরণ: ConcurrentHashMap, CopyOnWriteArrayList, ConcurrentLinkedQueue ইত্যাদি।
Concurrent Collections এর সুবিধা
- Thread-Safe:
- একাধিক থ্রেড একই সময়ে ডেটা অ্যাক্সেস এবং আপডেট করতে পারে।
- Deadlock বা Race Condition এর ঝুঁকি কম।
- High Performance:
- Traditional synchronized collections (যেমন
Vector,Hashtable) এর তুলনায় উন্নত পারফরম্যান্স প্রদান করে।
- Traditional synchronized collections (যেমন
- Non-Blocking Algorithms:
- বেশিরভাগ Concurrent Collections লক-ফ্রি মেকানিজম ব্যবহার করে যা পারফরম্যান্স বাড়ায়।
- Scalability:
- Concurrent Collections বড় স্কেল অ্যাপ্লিকেশন পরিচালনায় কার্যকর।
Concurrent Collections এর প্রধান প্রকারভেদ
১. ConcurrentHashMap
ConcurrentHashMap হলো জাভার একটি হ্যাশম্যাপ, যা মাল্টি-থ্রেডিংয়ে ব্যবহারের জন্য ডিজাইন করা হয়েছে।
- বৈশিষ্ট্য:
- Thread-safe।
- লক-স্ট্রিপিং (Lock-Stripping) প্রযুক্তি ব্যবহার করে।
- Null কী বা ভ্যালু অনুমোদিত নয়।
উদাহরণ:
import java.util.concurrent.ConcurrentHashMap;
public class ConcurrentHashMapExample {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
// মান যোগ করা
map.put("A", 1);
map.put("B", 2);
// মান পড়া
System.out.println(map.get("A"));
// মান আপডেট করা
map.put("A", 5);
System.out.println(map.get("A"));
}
}
২. CopyOnWriteArrayList
CopyOnWriteArrayList হলো এমন একটি তালিকা যা প্রতিবার একটি নতুন কপি তৈরি করে যখন এটি পরিবর্তিত হয়।
- বৈশিষ্ট্য:
- Thread-safe।
- একাধিক থ্রেড একযোগে পড়তে পারে।
- পরিবর্তনের সময় নতুন কপি তৈরি হয়।
উদাহরণ:
import java.util.concurrent.CopyOnWriteArrayList;
public class CopyOnWriteArrayListExample {
public static void main(String[] args) {
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
// মান যোগ করা
list.add("A");
list.add("B");
// মান পড়া
System.out.println(list);
// মান পরিবর্তন
list.set(0, "C");
System.out.println(list);
}
}
৩. ConcurrentLinkedQueue
ConcurrentLinkedQueue হলো একটি থ্রেড-সেফ কিউ যা লক-ফ্রি পদ্ধতিতে কাজ করে।
- বৈশিষ্ট্য:
- FIFO (First-In-First-Out) আদলে কাজ করে।
- থ্রেড-সেফ এবং হালকা।
উদাহরণ:
import java.util.concurrent.ConcurrentLinkedQueue;
public class ConcurrentLinkedQueueExample {
public static void main(String[] args) {
ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();
// মান যোগ করা
queue.add("A");
queue.add("B");
// মান পড়া
System.out.println(queue.peek());
// মান মুছে ফেলা
System.out.println(queue.poll());
System.out.println(queue);
}
}
৪. BlockingQueue
BlockingQueue হলো এমন একটি কিউ যা উৎপাদক-গ্রাহক (Producer-Consumer) সমস্যা সমাধানের জন্য ব্যবহৃত হয়।
- বৈশিষ্ট্য:
- Capacity নির্ধারণ করা যায়।
- Thread-safe।
take()এবংput()মেথড ব্লক করে যতক্ষণ পর্যন্ত কিউ খালি বা পূর্ণ হয়।
উদাহরণ:
import java.util.concurrent.ArrayBlockingQueue;
public class BlockingQueueExample {
public static void main(String[] args) {
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(2);
try {
queue.put("A");
queue.put("B");
System.out.println(queue);
System.out.println(queue.take());
System.out.println(queue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Traditional Collections বনাম Concurrent Collections
| বিষয় | Traditional Collections | Concurrent Collections |
|---|---|---|
| Thread Safety | Synchronized ম্যানুয়ালভাবে যোগ করতে হয়। | বিল্ট-ইন Thread-safe। |
| Performance | ধীর, কারণ পুরো Object লক হয়। | দ্রুত, কারণ লক-স্ট্রিপিং বা লক-ফ্রি। |
| উদাহরণ | Hashtable, Vector | ConcurrentHashMap, CopyOnWriteArrayList |
কোথায় ব্যবহার করবেন?
- ConcurrentHashMap:
মাল্টি-থ্রেডেড অ্যাপ্লিকেশন যেখানে থ্রেডগুলি ডেটা পড়া এবং আপডেট করে। - CopyOnWriteArrayList:
যেখানে পড়ার অপারেশন বেশি এবং লেখার অপারেশন কম। - ConcurrentLinkedQueue:
মাল্টি-থ্রেডেড কিউ ব্যবহারের জন্য। - BlockingQueue:
উৎপাদক-গ্রাহক সমস্যা সমাধানের জন্য।
Concurrent Collections জাভার মাল্টি-থ্রেডেড অ্যাপ্লিকেশনগুলোর জন্য অপরিহার্য।
এটি ডেটার সঠিকতা, পারফরম্যান্স, এবং থ্রেড সেফটি নিশ্চিত করে।
আপনার অ্যাপ্লিকেশনের নির্দিষ্ট চাহিদা অনুযায়ী উপযুক্ত সংগ্রহ নির্বাচন করুন।
জাভাতে Concurrent Collections এমন ডেটা স্ট্রাকচার, যা সমান্তরাল পরিবেশে (concurrent environments) সঠিক ও কার্যকরভাবে কাজ করতে সক্ষম। এগুলো java.util.concurrent প্যাকেজের অন্তর্ভুক্ত এবং থ্রেড-সেফ ডেটা ম্যানিপুলেশন নিশ্চিত করতে ব্যবহৃত হয়।
Concurrent Collections এর ধারণা
- Concurrent Collections হলো ডেটা স্ট্রাকচার যা কনকারেন্ট অ্যাক্সেস (multiple threads accessing the same data structure) এবং সিঙ্ক্রোনাইজেশন পরিচালনা করে।
- সাধারণ
CollectionবাMapইন্টারফেসের বিকল্প হিসেবে এগুলো তৈরি করা হয়েছে, যেখানে সাধারণsynchronizedব্লকের পরিবর্তে অভ্যন্তরীণ লকিং মেকানিজম ব্যবহৃত হয়। - এগুলো স্পিন-লক, রিড-ওপ্টিমাইজেশন এবং অন্যান্য উন্নত টেকনিক ব্যবহার করে কর্মদক্ষতা বৃদ্ধি করে।
Concurrent Collections এর প্রয়োজনীয়তা
- থ্রেড সেফ অপারেশন:
- কনকারেন্ট পরিবেশে ডেটার অখণ্ডতা বজায় রাখতে।
- ডেটা রেস এবং ডেডলকের ঝুঁকি কমায়।
- উচ্চ কর্মদক্ষতা:
- কম লকিং ও ভালো পারফরম্যান্সের জন্য উন্নত লক-ফ্রি বা কম-লকিং প্রযুক্তি ব্যবহার করে।
- ডেডলক এবং রেস কন্ডিশন প্রতিরোধ:
- বিভিন্ন থ্রেডের মাধ্যমে একসাথে অ্যাক্সেসের সময় জটিল সমস্যা এড়ানো।
- সহজ ইমপ্লিমেন্টেশন:
- থ্রেড সেফ ডেটা স্ট্রাকচার ব্যবহারে ডেভেলপারদের জন্য কোড লেখার প্রক্রিয়া সহজ করে।
Concurrent Collections এর উদাহরণ
১. ConcurrentHashMap
- থ্রেড সেফ
HashMapযাsynchronizedব্লক ছাড়াই কাজ করে। - সেগমেন্টেড লকিং ব্যবহার করে শুধুমাত্র সংশ্লিষ্ট অংশ লক করে, ফলে পারফরম্যান্স ভালো হয়।
ব্যবহার:
import java.util.concurrent.ConcurrentHashMap;
public class ConcurrentHashMapExample {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
// ডেটা যুক্ত করা
map.put("A", 1);
map.put("B", 2);
// থ্রেড ১: মান পরিবর্তন
Thread t1 = new Thread(() -> {
map.put("C", 3);
System.out.println("Thread 1 added: " + map);
});
// থ্রেড ২: মান অ্যাক্সেস করা
Thread t2 = new Thread(() -> {
System.out.println("Thread 2 accessed: " + map.get("B"));
});
t1.start();
t2.start();
}
}
২. CopyOnWriteArrayList
- থ্রেড সেফ
ArrayList, যা প্রতিবার নতুন সংস্করণ তৈরি করে ডেটা অ্যাড/রিমুভ করে। - রিড-অপ্টিমাইজড ডেটা স্ট্রাকচার।
ব্যবহার:
import java.util.concurrent.CopyOnWriteArrayList;
public class CopyOnWriteArrayListExample {
public static void main(String[] args) {
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
list.add("A");
list.add("B");
// থ্রেড ১: নতুন ডেটা যুক্ত করা
Thread t1 = new Thread(() -> {
list.add("C");
System.out.println("Thread 1 added: " + list);
});
// থ্রেড ২: রিড অপারেশন
Thread t2 = new Thread(() -> {
for (String item : list) {
System.out.println("Thread 2 read: " + item);
}
});
t1.start();
t2.start();
}
}
৩. ConcurrentLinkedQueue
- থ্রেড সেফ
Queueযা নন-ব্লকিং ডেটা স্ট্রাকচার হিসেবে কাজ করে। - FIFO (First-In-First-Out) অর্ডারে কাজ করে।
ব্যবহার:
import java.util.concurrent.ConcurrentLinkedQueue;
public class ConcurrentLinkedQueueExample {
public static void main(String[] args) {
ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();
// ডেটা যুক্ত করা
queue.add("A");
queue.add("B");
// থ্রেড ১: নতুন ডেটা যুক্ত করা
Thread t1 = new Thread(() -> {
queue.add("C");
System.out.println("Thread 1 added: " + queue);
});
// থ্রেড ২: ডেটা পোল করা
Thread t2 = new Thread(() -> {
String item = queue.poll();
System.out.println("Thread 2 polled: " + item);
});
t1.start();
t2.start();
}
}
৪. BlockingQueue
- একটি
Queueযা থ্রেডের মধ্যে ডেটা শেয়ার করার জন্য ব্লকিং মেকানিজম ব্যবহার করে। - প্রযোজ্য: প্রোডিউসার-ডিফিউসার প্যাটার্ন।
ব্যবহার:
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class BlockingQueueExample {
public static void main(String[] args) {
BlockingQueue<String> queue = new ArrayBlockingQueue<>(3);
// প্রোডিউসার থ্রেড
Thread producer = new Thread(() -> {
try {
queue.put("A");
System.out.println("Produced: A");
queue.put("B");
System.out.println("Produced: B");
queue.put("C");
System.out.println("Produced: C");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// কনজিউমার থ্রেড
Thread consumer = new Thread(() -> {
try {
Thread.sleep(1000); // কিছুক্ষণ অপেক্ষা
System.out.println("Consumed: " + queue.take());
System.out.println("Consumed: " + queue.take());
System.out.println("Consumed: " + queue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
});
producer.start();
consumer.start();
}
}
Concurrent Collections এর গুরুত্বপূর্ণ ক্লাসসমূহ
| ক্লাসের নাম | ব্যবহার |
|---|---|
ConcurrentHashMap | থ্রেড সেফ HashMap |
CopyOnWriteArrayList | থ্রেড সেফ ArrayList |
CopyOnWriteArraySet | থ্রেড সেফ Set |
ConcurrentLinkedQueue | নন-ব্লকিং থ্রেড সেফ Queue |
BlockingQueue | প্রোডিউসার-ডিফিউসার প্যাটার্নে ব্লকিং মেকানিজম সমর্থনকারী Queue |
ConcurrentSkipListMap | থ্রেড সেফ SortedMap |
ConcurrentSkipListSet | থ্রেড সেফ SortedSet |
Concurrent Collections এর সুবিধা
- থ্রেড সেফ:
- এগুলো থ্রেড সেফ এবং ডেটার সঠিকতা বজায় রাখে।
- উচ্চ পারফরম্যান্স:
- লক-ফ্রি এবং কম-লকিং অপারেশন নিশ্চিত করে।
- সহজ ব্যবহার:
- ম্যানুয়াল সিঙ্ক্রোনাইজেশন না করেও থ্রেড সেফ ডেটা ম্যানেজ করা যায়।
- বিস্তৃত অ্যাপ্লিকেশন:
- ডেটা শেয়ারিং, প্রোডিউসার-ডিফিউসার প্যাটার্ন, এবং থ্রেড কনট্রোল সিস্টেমে ব্যবহৃত হয়।
Concurrent Collections থ্রেড সেফ প্রোগ্রামিংয়ে উন্নত কার্যকারিতা এবং স্থিতিশীলতা নিশ্চিত করতে অপরিহার্য। এদের ব্যবহার সমান্তরাল পরিবেশে প্রোগ্রামিং আরও সহজ এবং কার্যকর করে তোলে।
জাভা কনকারেন্সি ফ্রেমওয়ার্কে মাল্টিথ্রেডেড প্রোগ্রামিংয়ের সময় সাধারণ ডেটা স্ট্রাকচারগুলি নিরাপদে ব্যবহারের জন্য এই ক্লাসগুলি গুরুত্বপূর্ণ ভূমিকা পালন করে।
১. ConcurrentHashMap
ConcurrentHashMap হল একটি থ্রেড-সেফ সংস্করণ HashMap এর, যা একই সময়ে একাধিক থ্রেড থেকে ডেটা অ্যাক্সেস এবং আপডেট করতে দেয়। এটি লকিং কৌশল (bucket-level locking) ব্যবহার করে পারফরম্যান্স বাড়ায়।
ব্যবহার:
import java.util.concurrent.ConcurrentHashMap;
public class ConcurrentHashMapExample {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
// মান যোগ করা
map.put("One", 1);
map.put("Two", 2);
// মাল্টিথ্রেডিং ব্যবহার
Thread thread1 = new Thread(() -> {
map.put("Three", 3);
System.out.println("Thread 1: " + map);
});
Thread thread2 = new Thread(() -> {
map.put("Four", 4);
System.out.println("Thread 2: " + map);
});
thread1.start();
thread2.start();
// শেষ ফলাফল
System.out.println("Final Map: " + map);
}
}
বৈশিষ্ট্য:
- একাধিক থ্রেড ডেটা অ্যাক্সেস করতে পারে।
- শুধুমাত্র প্রয়োজনীয় অংশে লকিং প্রয়োগ করে।
২. CopyOnWriteArrayList
CopyOnWriteArrayList হলো একটি থ্রেড-সেফ সংস্করণ ArrayList এর, যা মূলত রিড অপারেশন বেশি হলে ব্যবহৃত হয়। এটি প্রতিবার আপডেট করার সময় একটি নতুন কপি তৈরি করে।
ব্যবহার:
import java.util.concurrent.CopyOnWriteArrayList;
public class CopyOnWriteArrayListExample {
public static void main(String[] args) {
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
// মান যোগ করা
list.add("One");
list.add("Two");
// মাল্টিথ্রেডিং ব্যবহার
Thread thread1 = new Thread(() -> {
list.add("Three");
System.out.println("Thread 1: " + list);
});
Thread thread2 = new Thread(() -> {
list.add("Four");
System.out.println("Thread 2: " + list);
});
thread1.start();
thread2.start();
// রিড অপারেশন
list.forEach(System.out::println);
}
}
বৈশিষ্ট্য:
- প্রতিবার রাইট অপারেশনের জন্য একটি নতুন কপি তৈরি করে।
- রিড অপারেশনের সময় কোন লকিং প্রয়োজন হয় না।
৩. BlockingQueue
BlockingQueue হলো একটি থ্রেড-সেফ কিউ যা থ্রেড সিঙ্ক্রোনাইজেশনের জন্য ব্লকিং অপারেশন ব্যবহার করে। এটি প্রযোজক-গ্রাহক (Producer-Consumer) প্যাটার্নে ব্যবহৃত হয়।
ব্যবহার:
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);
// প্রযোজক থ্রেড
Thread producer = new Thread(() -> {
try {
for (int i = 1; i <= 5; i++) {
queue.put(i);
System.out.println("Produced: " + i);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// গ্রাহক থ্রেড
Thread consumer = new Thread(() -> {
try {
while (true) {
Integer value = queue.take();
System.out.println("Consumed: " + value);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
producer.start();
consumer.start();
}
}
বৈশিষ্ট্য:
put()ব্লক করে যদি কিউ পূর্ণ হয়।take()ব্লক করে যদি কিউ খালি হয়।- বিভিন্ন ইমপ্লিমেন্টেশন রয়েছে:
ArrayBlockingQueue,LinkedBlockingQueue, ইত্যাদি।
সবগুলো একত্রে ব্যবহার: উদাহরণ
নিচে ConcurrentHashMap, CopyOnWriteArrayList, এবং BlockingQueue এর সম্মিলিত ব্যবহার দেখানো হলো:
import java.util.concurrent.*;
public class ConcurrencyExample {
public static void main(String[] args) {
// ConcurrentHashMap
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("Initial", 0);
// CopyOnWriteArrayList
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
list.add("Start");
// BlockingQueue
BlockingQueue<String> queue = new ArrayBlockingQueue<>(5);
// থ্রেড ১: মান যোগ করে
Thread thread1 = new Thread(() -> {
map.put("Thread1", 1);
list.add("Thread1");
try {
queue.put("Message from Thread1");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// থ্রেড ২: মান যোগ করে
Thread thread2 = new Thread(() -> {
map.put("Thread2", 2);
list.add("Thread2");
try {
queue.put("Message from Thread2");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// থ্রেড চালু করা
thread1.start();
thread2.start();
// কিউ থেকে মেসেজ পড়া
Thread thread3 = new Thread(() -> {
try {
while (true) {
String message = queue.take();
System.out.println("Consumed: " + message);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread3.start();
}
}
ConcurrentHashMap: থ্রেড-সেফ ম্যাপ যেখানে একাধিক থ্রেড একসাথে ডেটা অ্যাক্সেস এবং আপডেট করতে পারে।CopyOnWriteArrayList: থ্রেড-সেফ লিস্ট যেখানে রিড অপারেশনের জন্য দ্রুত কার্যকর এবং রাইট অপারেশনে একটি কপি তৈরি হয়।BlockingQueue: প্রযোজক-গ্রাহক প্যাটার্নে ব্যবহৃত কিউ যা ব্লকিং মেকানিজম সমর্থন করে।
এই ক্লাসগুলো সঠিকভাবে ব্যবহার করলে মাল্টিথ্রেডেড প্রোগ্রামিং সহজ এবং কার্যকর করা সম্ভব।
ArrayBlockingQueue এবং LinkedBlockingQueue উভয়ই BlockingQueue ইন্টারফেসের ইমপ্লিমেন্টেশন, যা Producer-Consumer Problem এর মতো সিঙ্ক্রোনাইজড ডেটা এক্সচেঞ্জ ব্যবস্থাপনা করতে ব্যবহৃত হয়। তবে এদের মধ্যে উল্লেখযোগ্য কিছু পার্থক্য রয়েছে।
১. ArrayBlockingQueue
- সারাংশ:
- এটি একটি নির্দিষ্ট আকারের fixed-size array ব্যবহার করে তৈরি করা হয়।
- FIFO (First In, First Out) পদ্ধতি অনুসরণ করে।
- এর আকার আগে থেকে নির্ধারিত হতে হয় এবং এটি পরে পরিবর্তন করা যায় না।
- সিঙ্ক্রোনাইজেশন:
- পুরো queue একটি single lock দ্বারা সিঙ্ক্রোনাইজ হয়।
- একই সময়ে শুধু একটি থ্রেড queue এর সাথে কাজ করতে পারে।
- পারফরম্যান্স:
- একাধিক প্রোডিউসার এবং কনজিউমার থাকলে এটি তুলনামূলক ধীর হতে পারে, কারণ একসাথে কাজ করার অনুমতি নেই।
- ব্যবহার:
- সীমিত মেমোরি বা নির্দিষ্ট আকারের queue প্রয়োজন হলে।
কোড উদাহরণ:
import java.util.concurrent.ArrayBlockingQueue; public class ArrayBlockingQueueExample { public static void main(String[] args) throws InterruptedException { ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(3); queue.put(1); queue.put(2); queue.put(3); System.out.println(queue.take()); // 1 System.out.println(queue.take()); // 2 } }
২. LinkedBlockingQueue
- সারাংশ:
- এটি একটি লিঙ্কড লিস্ট ভিত্তিক queue যা linked nodes ব্যবহার করে।
- এর আকার সীমিত বা অসীম (default) হতে পারে।
- FIFO পদ্ধতি অনুসরণ করে।
- সিঙ্ক্রোনাইজেশন:
- প্রোডিউসার এবং কনজিউমারদের জন্য দুটি separate locks ব্যবহার করে।
- এটি একাধিক থ্রেডকে একই সময়ে কাজ করার অনুমতি দেয় (একটি ডেটা যোগ করছে, অন্যটি সরাচ্ছে)।
- পারফরম্যান্স:
- তুলনামূলকভাবে ভালো পারফরম্যান্স দেয়, বিশেষ করে একাধিক প্রোডিউসার এবং কনজিউমার থাকলে।
- ব্যবহার:
- যদি queue এর আকার সীমাহীন হওয়ার প্রয়োজন হয় অথবা একাধিক প্রোডিউসার এবং কনজিউমার একসাথে কাজ করবে।
কোড উদাহরণ:
import java.util.concurrent.LinkedBlockingQueue; public class LinkedBlockingQueueExample { public static void main(String[] args) throws InterruptedException { LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<>(); queue.put(1); queue.put(2); queue.put(3); System.out.println(queue.take()); // 1 System.out.println(queue.take()); // 2 } }
তুলনামূলক পার্থক্য টেবিল
| বৈশিষ্ট্য | ArrayBlockingQueue | LinkedBlockingQueue |
|---|---|---|
| স্টোরেজ ডেটা স্ট্রাকচার | Array (ফিক্সড আকার) | Linked List (লিঙ্কড নোড) |
| ডিফল্ট আকার | প্রয়োজনীয় | অসীম (Integer.MAX_VALUE) |
| সিঙ্ক্রোনাইজেশন লক | Single Lock | Separate Locks for Producer & Consumer |
| পারফরম্যান্স | তুলনামূলক ধীর | তুলনামূলক দ্রুত |
| মেমোরি ব্যবস্থাপনা | পূর্বনির্ধারিত (Fixed Size) | ডায়নামিক (Dynamic Allocation) |
| উপযুক্ত ক্ষেত্রে | সীমিত queue প্রয়োজন হলে | অনেক প্রোডিউসার এবং কনজিউমার থাকলে |
বুঝতে হবে:
ArrayBlockingQueueযখন queue-এর আকার আগে থেকেই জানা থাকে এবং মেমোরি স্থিতিশীল রাখতে হয়, তখন ব্যবহৃত হয়।LinkedBlockingQueueযেখানে queue-এর আকার ডায়নামিক হতে পারে এবং একাধিক প্রোডিউসার/কনজিউমার সমান্তরাল কাজ করবে, সেখানে ব্যবহৃত হয়।
উদাহরণ:
ArrayBlockingQueue:সীমিত ক্যাশে বা ব্যান্ডউইথ ব্যবহার করার জন্য।LinkedBlockingQueue:লগ মেসেজ প্রসেসিং বা বড় ডেটা স্ট্রিমিং এর জন্য।
এটি ব্যবহারকারীর নির্দিষ্ট প্রয়োজনীয়তা অনুযায়ী নির্বাচন করা উচিত।
জাভার Concurrent Collections মাল্টিথ্রেডেড অ্যাপ্লিকেশনে থ্রেড-সেফ ডেটা স্ট্রাকচার সরবরাহ করে। তবে সঠিকভাবে ব্যবহার না করলে ডেডলক, ডেটা রেস বা পারফরম্যান্স সমস্যা দেখা দিতে পারে। এখানে ConcurrentHashMap, CopyOnWriteArrayList, এবং BlockingQueue সহ জাভার কনকারেন্ট কালেকশনের জন্য সেরা অনুশীলনগুলো (best practices) উল্লেখ করা হলো।
১. উপযুক্ত কনকারেন্ট কালেকশন নির্বাচন করুন
ConcurrentHashMap: থ্রেড-সেফ ম্যাপ যেখানে একাধিক থ্রেড থেকে ডেটা পড়া এবং লেখা করা যায়। দ্রুত read-heavy operations এর জন্য উপযুক্ত।CopyOnWriteArrayList: রিড-অপ্টিমাইজড লিস্ট যেখানে লেখার সময় নতুন কপি তৈরি হয়। রিড অপারেশন বেশি হলে এটি ব্যবহার করুন।BlockingQueue: প্রযোজক-গ্রাহক (Producer-Consumer) প্যাটার্নের জন্য উপযুক্ত।ConcurrentSkipListMapএবংConcurrentSkipListSet: যদি ডেটা sorted রাখতে হয়, তবে এই ক্লাস ব্যবহার করুন।
২. ডেটা রেস এড়ানোর জন্য Atomic অপারেশন ব্যবহার করুন
computeIfAbsent(),putIfAbsent()বাmerge()ব্যবহার করুন একাধিক থ্রেডে ডেটা রেস এড়াতে।
উদাহরণ:
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.putIfAbsent("Key", 1); // ডেটা রেস এড়ানো
map.computeIfAbsent("NewKey", key -> 2); // কন্ডিশনাল ডেটা সেটিং
map.merge("Key", 1, Integer::sum); // ডেটা আপডেটের জন্য
৩. কনকারেন্ট কালেকশন থেকে রেস কন্ডিশন এড়াতে Avoid Manual Synchronization
- কনকারেন্ট কালেকশন ব্যবহার করার সময়
synchronizedব্লক প্রয়োগ করার চেষ্টা করবেন না। এটি পারফরম্যান্স কমিয়ে দিতে পারে।
Avoid (Bad Practice):
synchronized (map) {
map.put("Key", 1);
}
Use (Good Practice):
map.put("Key", 1); // ConcurrentHashMap নিজেই থ্রেড-সেফ
৪. ইটারেটর ব্যবহার করার সময় সতর্ক থাকুন
- ConcurrentHashMap এর ইটারেটর ডেটা পরিবর্তনের সময়
fail-safeকিন্তু তাৎক্ষণিক প্রতিফলন দেয় না। - CopyOnWriteArrayList ইটারেটর ব্যবহার করলে এক সময়ে শুধু রিড অপারেশন নিশ্চিত করুন।
উদাহরণ:
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>(List.of("One", "Two"));
for (String item : list) {
if ("Two".equals(item)) {
list.add("Three"); // নিরাপদ
}
}
System.out.println(list); // [One, Two, Three]
৫. প্রযোজক-গ্রাহক প্যাটার্নে BlockingQueue ব্যবহার করুন
- BlockingQueue যেমন
ArrayBlockingQueueবাLinkedBlockingQueueব্যবহার করুন থ্রেড সিঙ্ক্রোনাইজেশনের জন্য। - put() এবং take() মেথড ব্লক করে কিউ পূর্ণ বা খালি থাকলে।
উদাহরণ:
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);
// প্রযোজক থ্রেড
Thread producer = new Thread(() -> {
try {
for (int i = 1; i <= 10; i++) {
queue.put(i);
System.out.println("Produced: " + i);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
// গ্রাহক থ্রেড
Thread consumer = new Thread(() -> {
try {
while (true) {
Integer value = queue.take();
System.out.println("Consumed: " + value);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
producer.start();
consumer.start();
৬. CopyOnWriteArrayList এড়িয়ে চলুন যদি লেখার অপারেশন বেশি হয়
- CopyOnWriteArrayList প্রতিবার লেখার সময় একটি নতুন কপি তৈরি করে। রাইট-ইনটেনসিভ অপারেশন থাকলে এটি এড়িয়ে চলুন।
পরিবর্তে ব্যবহার করুন:
Collections.synchronizedList()বা নিজস্ব সিঙ্ক্রোনাইজড স্ট্রাকচার তৈরি করুন।
৭. ক্যাশের জন্য ConcurrentHashMap ব্যবহার করুন
- ক্যাশ মেকানিজম তৈরির জন্য
ConcurrentHashMapব্যবহার করুন এবং অপারেশনাল মেথড (যেমনcomputeIfAbsent) ব্যবহার করুন।
উদাহরণ:
ConcurrentHashMap<String, String> cache = new ConcurrentHashMap<>();
String value = cache.computeIfAbsent("Key", key -> "ComputedValue");
System.out.println(value); // ComputedValue
৮. Thread-Safe Queue ব্যবহার করুন
- PriorityBlockingQueue বা DelayQueue ব্যবহার করুন থ্রেড-সেফ কিউ ম্যানেজমেন্টের জন্য।
উদাহরণ:
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
class DelayedTask implements Delayed {
private final long delayTime;
private final long creationTime;
public DelayedTask(long delayInMilliseconds) {
this.delayTime = delayInMilliseconds;
this.creationTime = System.currentTimeMillis();
}
@Override
public long getDelay(TimeUnit unit) {
long diff = (creationTime + delayTime) - System.currentTimeMillis();
return unit.convert(diff, TimeUnit.MILLISECONDS);
}
@Override
public int compareTo(Delayed o) {
return Long.compare(this.getDelay(TimeUnit.MILLISECONDS), o.getDelay(TimeUnit.MILLISECONDS));
}
}
public class DelayQueueExample {
public static void main(String[] args) throws InterruptedException {
DelayQueue<DelayedTask> delayQueue = new DelayQueue<>();
delayQueue.put(new DelayedTask(2000));
System.out.println("Task added to delay queue. Waiting...");
DelayedTask task = delayQueue.take(); // Waits until delay expires
System.out.println("Task executed!");
}
}
৯. পারফরম্যান্স মনিটর করুন
- Concurrent Collections ব্যবহার করার সময় জাভা প্রোফাইলিং টুল (যেমন JVisualVM) দিয়ে পারফরম্যান্স যাচাই করুন।
- বেশি সংখ্যক থ্রেড বা বড় ডেটা ব্যবস্থাপনায় ব্লকিং এবং নন-ব্লকিং পারফরম্যান্স তুলনা করুন।
১০. ডেডলক এবং লাইভলক এড়ান
- একাধিক থ্রেড থেকে একই রিসোর্সে অ্যাক্সেস করার সময় ডেডলক এড়ানোর জন্য যথাযথ থ্রেড সিঙ্ক্রোনাইজেশন ব্যবহার করুন।
- সর্বদা নির্দিষ্ট অর্ডারে রিসোর্স অ্যাক্সেস নিশ্চিত করুন।
ConcurrentHashMapএবংBlockingQueueথ্রেড-সেফ অপারেশনের জন্য দ্রুত এবং কার্যকর।CopyOnWriteArrayListরিড-ইনটেনসিভ পরিবেশে পারফেক্ট।- সর্বদা থ্রেড-সেফ কালেকশনের সঠিক ব্যবহার নিশ্চিত করুন এবং সিঙ্ক্রোনাইজেশন জটিলতা এড়াতে চেষ্টা করুন।
Read more