জাভার কনকারেন্সি মডেলে একাধিক থ্রেড একই ডেটার উপর কাজ করার সময় ডেটার সঠিকতা এবং নিরাপত্তা বজায় রাখা অত্যন্ত গুরুত্বপূর্ণ। Synchronization এবং Locks হল দুটি মূল প্রক্রিয়া, যা এই উদ্দেশ্যে ব্যবহৃত হয়।
Synchronization
সংজ্ঞা: Synchronization একটি প্রক্রিয়া, যা নিশ্চিত করে যে একাধিক থ্রেড একই সময়ে একটি নির্দিষ্ট ব্লকের কোড বা মেথড অ্যাক্সেস করতে পারবে না। এটি মূলত intrinsic locks (monitor locks) ব্যবহার করে থ্রেড নিরাপত্তা বজায় রাখে।
উদাহরণ: Synchronized মেথড
class SharedResource {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
}
public class SynchronizationExample {
public static void main(String[] args) throws InterruptedException {
SharedResource resource = new SharedResource();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
resource.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
resource.increment();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final Count: " + resource.getCount());
}
}
উদাহরণ: Synchronized ব্লক
class SharedResource {
private int count = 0;
public void increment() {
synchronized (this) {
count++;
}
}
public int getCount() {
synchronized (this) {
return count;
}
}
}
Locks
সংজ্ঞা: Locks হল একটি উন্নততর মেকানিজম, যা থ্রেডের মধ্যে আরও বেশি নিয়ন্ত্রণ এবং স্থিতিশীলতা প্রদান করে। এটি জাভার java.util.concurrent.locks প্যাকেজে পাওয়া যায়।
Locks-এর প্রকারভেদ
- ReentrantLock: একটি সাধারণ লক যা পুনরায় প্রবেশযোগ্য।
- ReadWriteLock: একাধিক থ্রেডকে পড়ার অনুমতি দেয়, কিন্তু শুধুমাত্র একটি থ্রেডকে লেখার অনুমতি দেয়।
ReentrantLock উদাহরণ
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class SharedResource {
private int count = 0;
private final Lock lock = new ReentrantLock();
public void increment() {
lock.lock(); // লক নিন
try {
count++;
} finally {
lock.unlock(); // লক ছাড়ুন
}
}
public int getCount() {
lock.lock();
try {
return count;
} finally {
lock.unlock();
}
}
}
public class LockExample {
public static void main(String[] args) throws InterruptedException {
SharedResource resource = new SharedResource();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
resource.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
resource.increment();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final Count: " + resource.getCount());
}
}
ReadWriteLock উদাহরণ
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
class SharedResource {
private int data = 0;
private final ReadWriteLock lock = new ReentrantReadWriteLock();
public void write(int value) {
lock.writeLock().lock(); // Write Lock নিন
try {
data = value;
} finally {
lock.writeLock().unlock(); // Write Lock ছাড়ুন
}
}
public int read() {
lock.readLock().lock(); // Read Lock নিন
try {
return data;
} finally {
lock.readLock().unlock(); // Read Lock ছাড়ুন
}
}
}
public class ReadWriteLockExample {
public static void main(String[] args) {
SharedResource resource = new SharedResource();
Thread writer = new Thread(() -> resource.write(42));
Thread reader = new Thread(() -> System.out.println("Read Data: " + resource.read()));
writer.start();
reader.start();
}
}
Synchronization vs Locks: তুলনামূলক পার্থক্য
| প্যারামিটার | Synchronization | Locks |
|---|---|---|
| প্যাকেজ | java.lang | java.util.concurrent.locks |
| গ্রানুলারিটি | সহজ এবং কম নিয়ন্ত্রণ প্রদান করে। | উন্নত নিয়ন্ত্রণ এবং নমনীয়তা প্রদান করে। |
| লকিং মেকানিজম | Intrinsic locks (monitor locks) ব্যবহার করে। | Explicit locks (ReentrantLock, ReadWriteLock)। |
| ট্রাই লক মেকানিজম | সমর্থন করে না। | Try-locking বা টাইমআউট সাপোর্ট করে। |
| পুনরায় প্রবেশযোগ্যতা | Reentrant (পুনরায় প্রবেশযোগ্য)। | Reentrant এবং আরও নির্ধারিত। |
| ডেডলক ডিবাগিং | ডেডলক সমস্যাগুলি সনাক্ত করা কঠিন। | ডেডলক সনাক্ত করা সহজ। |
- Synchronization সহজ এবং ছোট মেথড বা কোড ব্লকের জন্য আদর্শ।
- Locks জটিল এবং উন্নত কনকারেন্সি পরিস্থিতিতে বেশি কার্যকর।
- প্রয়োজন অনুযায়ী এই দুটি পদ্ধতির ব্যবহার কনকারেন্সি অ্যাপ্লিকেশনের কার্যকারিতা বৃদ্ধি করে।
Race Condition: কী?
Race Condition এমন একটি অবস্থা, যখন একাধিক থ্রেড একই রিসোর্স বা ডেটাতে একসাথে অ্যাক্সেস করতে চেষ্টা করে এবং ডেটা সংক্রান্ত সমস্যা সৃষ্টি হয়। এটি ঘটে যদি:
- একাধিক থ্রেড একই ডেটা বা মেমোরি পরিবর্তন করে।
- ডেটা অ্যাক্সেস করার সিকোয়েন্স প্রেডিক্টেবল না হয়।
Race Condition এর উদাহরণ:
class Counter {
private int count = 0;
public void increment() {
count++; // এই লাইনটি Race Condition এর শিকার হতে পারে
}
public int getCount() {
return count;
}
}
public class RaceConditionExample {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final Count: " + counter.getCount()); // সম্ভাব্য ফলাফল সঠিক নাও হতে পারে
}
}
সমস্যা:
উপরের কোডে, count++ অপারেশন তিনটি ধাপে হয়:
countপড়া।countইনক্রিমেন্ট করা।- নতুন মান স্টোর করা।
যদি দুইটি থ্রেড একই সময়ে এই অপারেশন সম্পাদন করতে চায়, তাহলে Race Condition হতে পারে, এবং count এর মান সঠিক হবে না।
Synchronization: কেন দরকার?
Synchronization ব্যবহৃত হয় Race Condition প্রতিরোধ করতে। এটি নিশ্চিত করে যে এক সময়ে শুধুমাত্র একটি থ্রেড একটি নির্দিষ্ট ব্লকে বা মেথডে প্রবেশ করতে পারবে।
Synchronization এর উদাহরণ:
class Counter {
private int count = 0;
public synchronized void increment() { // সিঙ্ক্রোনাইজড ব্লক
count++;
}
public int getCount() {
return count;
}
}
public class SynchronizedExample {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final Count: " + counter.getCount()); // ফলাফল সবসময় সঠিক হবে
}
}
কীভাবে কাজ করে?
synchronizedকীওয়ার্ড ব্যবহার করলে, এক সময়ে শুধুমাত্র একটি থ্রেডincrement()মেথডে প্রবেশ করতে পারবে।- এটি একটি monitor lock তৈরি করে, যা থ্রেডকে ক্রমবদ্ধভাবে ডেটা অ্যাক্সেস করতে দেয়।
Alternative: Synchronized Block
সম্পূর্ণ মেথড সিঙ্ক্রোনাইজড না করে নির্দিষ্ট কোড ব্লক সিঙ্ক্রোনাইজড করা যেতে পারে।
class Counter {
private int count = 0;
public void increment() {
synchronized (this) { // শুধুমাত্র এই ব্লকটি সিঙ্ক্রোনাইজড
count++;
}
}
public int getCount() {
return count;
}
}
Java Concurrency Tools ব্যবহার করে Synchronization
১. ReentrantLock: ReentrantLock একটি আরও ফাইন-গ্রেইনড লক মেকানিজম প্রদান করে।
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Counter {
private int count = 0;
private Lock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock(); // সবসময় লক মুক্ত করুন
}
}
public int getCount() {
return count;
}
}
Race Condition এর প্রতিরোধে Synchronization কেন গুরুত্বপূর্ণ?
- ডেটা ইন্টিগ্রিটি: ডেটার সঠিকতা এবং ধারাবাহিকতা বজায় রাখা।
- ডেটা রেস এড়ানো: একাধিক থ্রেডের মধ্যে ডেটা অ্যাক্সেস কন্ট্রোল করা।
- ডেডলক প্রতিরোধ: সঠিকভাবে সিঙ্ক্রোনাইজ না করলে থ্রেড ডেডলক হতে পারে।
Race Condition এবং Synchronization এর চ্যালেঞ্জ
- সঠিকভাবে Synchronization না করলে ডেডলক এবং পারফরম্যান্স সমস্যা হতে পারে।
- অতিরিক্ত Synchronization অ্যাপ্লিকেশনের পারফরম্যান্স হ্রাস করতে পারে।
Race Condition জাভা কনকারেন্সির একটি সাধারণ সমস্যা যা ডেটার সঠিকতা নষ্ট করে। Synchronization এর মাধ্যমে এই সমস্যা সমাধান করা যায়। তবে, প্রতিটি ক্ষেত্রে Synchronization ব্যবহার করার আগে এর প্রভাব এবং চ্যালেঞ্জগুলো বুঝে প্রয়োগ করা উচিত।
জাভাতে synchronized কীওয়ার্ড থ্রেড-সেফটি নিশ্চিত করার জন্য ব্যবহৃত হয়। এটি একটি মিউচুয়াল এক্সক্লুশন মেকানিজম প্রদান করে যা একাধিক থ্রেডকে একই সময়ে একটি ক্রিটিক্যাল সেকশন অ্যাক্সেস করতে বাধা দেয়।
synchronized কীওয়ার্ডের বৈশিষ্ট্য
- থ্রেড-সেফিটি নিশ্চিত করা: একাধিক থ্রেড একই সময়ে শেয়ারড রিসোর্সে অ্যাক্সেস করতে পারবে না।
- মেমরি ভিজিবিলিটি নিশ্চিত করা: এক থ্রেড দ্বারা করা পরিবর্তন অন্য থ্রেডের জন্য দৃশ্যমান হবে।
- মিউচুয়াল এক্সক্লুশন: এক সময়ে শুধুমাত্র একটি থ্রেড সিঙ্ক্রোনাইজড ব্লকে প্রবেশ করতে পারে।
synchronized কীভাবে কাজ করে?
Synchronized মূলত মনিটর লক (Monitor Lock) ব্যবহার করে। যখন একটি থ্রেড synchronized ব্লকে প্রবেশ করে, তখন এটি একটি লক অর্জন করে। কাজ শেষ হলে লকটি মুক্ত করে।
synchronized ব্যবহার করার উপায়
১. সিঙ্ক্রোনাইজড মেথড (Synchronized Method)
পুরো মেথড সিঙ্ক্রোনাইজড করা হলে, এটি একসাথে একাধিক থ্রেড দ্বারা অ্যাক্সেসযোগ্য হয় না।
class SynchronizedMethodExample {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
}
২. সিঙ্ক্রোনাইজড ব্লক (Synchronized Block)
শুধুমাত্র কোডের একটি নির্দিষ্ট অংশ সিঙ্ক্রোনাইজড করতে ব্যবহার করা হয়। এটি কার্যক্ষমতা উন্নত করতে সাহায্য করে।
class SynchronizedBlockExample {
private int count = 0;
public void increment() {
synchronized (this) { // সিঙ্ক্রোনাইজড ব্লক
count++;
}
}
public int getCount() {
synchronized (this) {
return count;
}
}
}
৩. স্ট্যাটিক মেথডে সিঙ্ক্রোনাইজড (Synchronized Static Method)
স্ট্যাটিক মেথড সিঙ্ক্রোনাইজড হলে, এটি ক্লাস লেভেলে লক ধরে।
class SynchronizedStaticMethodExample {
private static int count = 0;
public static synchronized void increment() {
count++;
}
public static synchronized int getCount() {
return count;
}
}
৪. কাস্টম অবজেক্টে সিঙ্ক্রোনাইজড
যদি আপনি this এর পরিবর্তে একটি কাস্টম অবজেক্টে লক ধরে রাখতে চান, তাহলে এটি ব্যবহার করা হয়।
class CustomLockExample {
private final Object lock = new Object();
private int count = 0;
public void increment() {
synchronized (lock) { // কাস্টম লক
count++;
}
}
public int getCount() {
synchronized (lock) {
return count;
}
}
}
প্রকৃত উদাহরণ
মাল্টি-থ্রেডিংয়ে সিঙ্ক্রোনাইজড ব্যবহার
class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
// থ্রেড তৈরি
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
// সঠিক রেজাল্ট
System.out.println("Final Count: " + counter.getCount());
}
}
synchronized এর সুবিধা ও অসুবিধা
সুবিধা:
- থ্রেড-সেফটি: একাধিক থ্রেডের জন্য ডেটা কনসিসটেন্সি নিশ্চিত করে।
- সহজতর সিঙ্ক্রোনাইজেশন: জটিল লক ব্যবস্থাপনার প্রয়োজন নেই।
অসুবিধা:
- পারফরম্যান্স ইস্যু: অতিরিক্ত লকিং অ্যাপ্লিকেশনের গতি কমিয়ে দিতে পারে।
- ডেডলক ঝুঁকি: ভুল লকিং ডেডলক পরিস্থিতি তৈরি করতে পারে।
- কমপ্লেক্সিটি: বড় কোডবেসে সঠিক সিঙ্ক্রোনাইজেশন বজায় রাখা কঠিন হতে পারে।
synchronized এবং Java Memory Model (JMM)
- JMM নিশ্চিত করে যে
synchronizedব্লকের মধ্যে পরিবর্তনগুলো মেইন মেমরিতে ফ্লাশ হয় এবং অন্যান্য থ্রেড সেগুলো দেখতে পায়। - এটি হ্যাপেন্স-বিফোর (Happens-Before) সম্পর্ক ব্যবহার করে থ্রেডগুলোর মধ্যে সঠিক এক্সিকিউশন অর্ডার নিশ্চিত করে।
- জাভা কনকারেন্সি ম্যানেজ করার জন্য
synchronizedএকটি গুরুত্বপূর্ণ টুল। - শুধুমাত্র সেই অংশ সিঙ্ক্রোনাইজ করুন যা থ্রেড-সেফ হওয়া প্রয়োজন।
- অতিরিক্ত লকিং এড়িয়ে কার্যক্ষমতা উন্নত করতে চেষ্টা করুন।
ReentrantLock এবং Lock ইন্টারফেস জাভাতে উন্নত লকিং মেকানিজম সরবরাহ করে, যা থ্রেড সিঙ্ক্রোনাইজেশনের জন্য আরও নমনীয়তা প্রদান করে। এগুলি সাধারণ synchronized ব্লকের বিকল্প হিসাবে ব্যবহৃত হয়।
১. ReentrantLock কি?
ReentrantLock একটি ক্লাস যা Lock ইন্টারফেসের অংশ এবং এটি মাল্টি-থ্রেডেড অ্যাপ্লিকেশনের জন্য একটি উন্নত লকিং কৌশল প্রদান করে। এটি নিম্নলিখিত বৈশিষ্ট্যগুলো সরবরাহ করে:
- একটি থ্রেড একাধিকবার লক করতে পারে।
- সময় সীমা নির্ধারণ করে লক করার চেষ্টা করা যায়।
- লক করার চেষ্টা ব্যর্থ হলে থ্রেড ওয়েট করতে পারে না।
- লক অবস্থা পরীক্ষা করার সুবিধা দেয়।
২. Lock Interface-এর গুরুত্বপূর্ণ মেথড
| মেথড | বর্ণনা |
|---|---|
lock() | লক অর্জন করে এবং অন্য থ্রেডগুলিকে ব্লক করে। |
unlock() | লক মুক্ত করে, অন্য থ্রেড লক অর্জন করতে পারে। |
tryLock() | লক করার চেষ্টা করে; সফল হলে true ফেরত দেয়, অন্যথায় false। |
tryLock(timeout, unit) | নির্দিষ্ট সময়ের জন্য লক করার চেষ্টা করে। |
lockInterruptibly() | থ্রেড লক করতে অপেক্ষা করে কিন্তু ইন্টারাপ্ট হতে পারে। |
৩. ReentrantLock-এর উদাহরণ
সাধারণ ব্যবহার
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockExample {
private final Lock lock = new ReentrantLock();
private int counter = 0;
public void increment() {
lock.lock(); // লক অর্জন
try {
counter++;
System.out.println(Thread.currentThread().getName() + " - Counter: " + counter);
} finally {
lock.unlock(); // লক মুক্ত
}
}
public static void main(String[] args) {
ReentrantLockExample example = new ReentrantLockExample();
Runnable task = example::increment;
Thread thread1 = new Thread(task, "Thread-1");
Thread thread2 = new Thread(task, "Thread-2");
thread1.start();
thread2.start();
}
}
tryLock() ব্যবহার
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TryLockExample {
private final Lock lock = new ReentrantLock();
private int counter = 0;
public void increment() {
if (lock.tryLock()) { // লক করার চেষ্টা
try {
counter++;
System.out.println(Thread.currentThread().getName() + " - Counter: " + counter);
} finally {
lock.unlock();
}
} else {
System.out.println(Thread.currentThread().getName() + " - Could not acquire lock");
}
}
public static void main(String[] args) {
TryLockExample example = new TryLockExample();
Runnable task = example::increment;
Thread thread1 = new Thread(task, "Thread-1");
Thread thread2 = new Thread(task, "Thread-2");
thread1.start();
thread2.start();
}
}
tryLock(timeout, unit) ব্যবহার
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TryLockWithTimeoutExample {
private final Lock lock = new ReentrantLock();
private int counter = 0;
public void increment() {
try {
if (lock.tryLock(1, TimeUnit.SECONDS)) { // নির্দিষ্ট সময়ের জন্য লক করার চেষ্টা
try {
counter++;
System.out.println(Thread.currentThread().getName() + " - Counter: " + counter);
} finally {
lock.unlock();
}
} else {
System.out.println(Thread.currentThread().getName() + " - Could not acquire lock within timeout");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
TryLockWithTimeoutExample example = new TryLockWithTimeoutExample();
Runnable task = example::increment;
Thread thread1 = new Thread(task, "Thread-1");
Thread thread2 = new Thread(task, "Thread-2");
thread1.start();
thread2.start();
}
}
৪. ReentrantLock-এর গুরুত্বপূর্ণ বৈশিষ্ট্য
- Interruptible Locking:
lockInterruptibly()ব্যবহার করে একটি থ্রেড ব্লক থাকা অবস্থায় ইন্টারাপ্ট করা যায়। - Condition Objects:
ReentrantLockমাল্টিপল কন্ডিশন অবজেক্ট সাপোর্ট করে, যাsynchronizedব্লকের তুলনায় উন্নত।
Condition ব্যবহার উদাহরণ
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ConditionExample {
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
private boolean ready = false;
public void producer() throws InterruptedException {
lock.lock();
try {
System.out.println("Producer waiting...");
while (!ready) {
condition.await(); // ওয়েট
}
System.out.println("Producer done");
} finally {
lock.unlock();
}
}
public void consumer() throws InterruptedException {
lock.lock();
try {
Thread.sleep(1000);
ready = true;
System.out.println("Consumer signal...");
condition.signal(); // সিগন্যাল
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
ConditionExample example = new ConditionExample();
Thread producerThread = new Thread(() -> {
try {
example.producer();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread consumerThread = new Thread(() -> {
try {
example.consumer();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
producerThread.start();
consumerThread.start();
}
}
৫. ReentrantLock বনাম synchronized
| বৈশিষ্ট্য | ReentrantLock | synchronized |
|---|---|---|
| লক রিলিজ | লক ম্যানুয়ালি মুক্ত করতে হয়। | স্বয়ংক্রিয়ভাবে মুক্ত হয়। |
| Interruptible | লক ইন্টারাপ্ট করা সম্ভব। | ইন্টারাপ্ট করা যায় না। |
| Try Lock | লক পাওয়ার চেষ্টা করা যায়। | এই বৈশিষ্ট্য নেই। |
| Multiple Conditions | একাধিক কন্ডিশন অবজেক্ট তৈরি করা যায়। | একটি মনিটর প্রতি একটি কন্ডিশন। |
- ReentrantLock ব্যবহার করে উন্নত লকিং কৌশল অর্জন করা যায়।
- Lock Interface কাস্টমাইজড থ্রেড সিঙ্ক্রোনাইজেশন নিশ্চিত করে।
- ReentrantLock ব্যবহার করার সময় finally ব্লকে
unlock()নিশ্চিত করতে হবে।
এই উদাহরণ এবং বৈশিষ্ট্যগুলোর সাহায্যে মাল্টি-থ্রেডিং অ্যাপ্লিকেশনের জন্য জাভা কনকারেন্সি আরও সহজ এবং কার্যকর হয়ে উঠবে।
ReadWriteLock হল জাভার java.util.concurrent.locks প্যাকেজের একটি ইন্টারফেস, যা এমন পরিস্থিতিতে ব্যবহৃত হয় যেখানে একাধিক থ্রেড ডেটা পড়তে পারে (read), কিন্তু শুধুমাত্র একটি থ্রেড ডেটা পরিবর্তন (write) করতে পারে। এটি একযোগে পড়া এবং ডেটা আপডেট করার মধ্যে সঠিক সমন্বয় (synchronization) নিশ্চিত করে।
ReadWriteLock এর ভূমিকা
- একাধিক পাঠক থ্রেড (Multiple Reader Threads): একাধিক থ্রেড একই সময়ে ডেটা পড়তে পারে।
- একক লেখক থ্রেড (Single Writer Thread): এক সময়ে শুধুমাত্র একটি থ্রেড ডেটা পরিবর্তন করতে পারে।
- লেখা-পড়ার সংঘাত প্রতিরোধ: লেখার সময় পড়া থ্রেড বন্ধ করে দেয়।
ReadWriteLock এর মূল মেথড
ReadWriteLock ইন্টারফেস দুটি লক সরবরাহ করে:
readLock(): ডেটা পড়ার জন্য লক।writeLock(): ডেটা লেখার জন্য লক।
ReadWriteLock ব্যবহার: উদাহরণ
১. ReadWriteLock এর ব্যবহার দেখানো উদাহরণ
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
class SharedData {
private int data = 0; // শেয়ারড ডেটা
private final ReadWriteLock lock = new ReentrantReadWriteLock();
// ডেটা পড়ার জন্য
public int read() {
lock.readLock().lock(); // Read lock নিন
try {
System.out.println(Thread.currentThread().getName() + " is reading: " + data);
return data;
} finally {
lock.readLock().unlock(); // Read lock ছেড়ে দিন
}
}
// ডেটা লেখার জন্য
public void write(int value) {
lock.writeLock().lock(); // Write lock নিন
try {
System.out.println(Thread.currentThread().getName() + " is writing: " + value);
this.data = value;
} finally {
lock.writeLock().unlock(); // Write lock ছেড়ে দিন
}
}
}
public class ReadWriteLockExample {
public static void main(String[] args) {
SharedData sharedData = new SharedData();
// Reader Threads
Runnable readerTask = () -> {
for (int i = 0; i < 5; i++) {
sharedData.read();
try {
Thread.sleep(100); // সামান্য বিরতি
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
// Writer Thread
Runnable writerTask = () -> {
for (int i = 0; i < 5; i++) {
sharedData.write(i);
try {
Thread.sleep(200); // সামান্য বিরতি
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
// থ্রেড তৈরি
Thread reader1 = new Thread(readerTask, "Reader 1");
Thread reader2
Read more