Java ReadWriteLock
ReadWriteLock Nədir?
ReadWriteLock oxuma və yazma əməliyyatları üçün ayrı-ayrı lock-lar təqdim edən synchronization mexanizmidir. Bir neçə thread eyni vaxtda oxuya bilər, amma yazma zamanı eksklüziv lock alınır.
Xüsusiyyətlər:
- Read lock - Bir neçə thread eyni vaxtda oxuya bilər
- Write lock - Yalnız bir thread yaza bilər (eksklüziv)
- Çox oxuma, az yazma olan ssenarilərdə performans artımı
- ReentrantReadWriteLock ən çox istifadə olunan implementasiyadır
Basic Usage
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
class SharedResource {
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
private String data = "initial";
// Oxuma metodu - bir neçə thread eyni vaxtda çağıra bilər
public String read() {
rwLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " oxuyur");
Thread.sleep(1000); // Oxuma əməliyyatı
return data;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
} finally {
rwLock.readLock().unlock();
}
}
// Yazma metodu - yalnız bir thread çağıra bilər
public void write(String newData) {
rwLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " yazır");
Thread.sleep(1000); // Yazma əməliyyatı
data = newData;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
rwLock.writeLock().unlock();
}
}
}
Cache Implementation
class ThreadSafeCache<K, V> {
private final Map<K, V> cache = new HashMap<>();
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
public V get(K key) {
rwLock.readLock().lock();
try {
return cache.get(key);
} finally {
rwLock.readLock().unlock();
}
}
public void put(K key, V value) {
rwLock.writeLock().lock();
try {
cache.put(key, value);
} finally {
rwLock.writeLock().unlock();
}
}
public void remove(K key) {
rwLock.writeLock().lock();
try {
cache.remove(key);
} finally {
rwLock.writeLock().unlock();
}
}
public int size() {
rwLock.readLock().lock();
try {
return cache.size();
} finally {
rwLock.readLock().unlock();
}
}
public void clear() {
rwLock.writeLock().lock();
try {
cache.clear();
} finally {
rwLock.writeLock().unlock();
}
}
}
Statistics Tracker
class StatisticsTracker {
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
private long totalRequests = 0;
private long successfulRequests = 0;
private long failedRequests = 0;
// Oxuma - bir neçə thread eyni vaxtda
public long getTotalRequests() {
rwLock.readLock().lock();
try {
return totalRequests;
} finally {
rwLock.readLock().unlock();
}
}
public double getSuccessRate() {
rwLock.readLock().lock();
try {
if (totalRequests == 0) return 0.0;
return (double) successfulRequests / totalRequests * 100;
} finally {
rwLock.readLock().unlock();
}
}
public Map<String, Long> getStats() {
rwLock.readLock().lock();
try {
Map<String, Long> stats = new HashMap<>();
stats.put("total", totalRequests);
stats.put("successful", successfulRequests);
stats.put("failed", failedRequests);
return stats;
} finally {
rwLock.readLock().unlock();
}
}
// Yazma - eksklüziv
public void recordSuccess() {
rwLock.writeLock().lock();
try {
totalRequests++;
successfulRequests++;
} finally {
rwLock.writeLock().unlock();
}
}
public void recordFailure() {
rwLock.writeLock().lock();
try {
totalRequests++;
failedRequests++;
} finally {
rwLock.writeLock().unlock();
}
}
public void reset() {
rwLock.writeLock().lock();
try {
totalRequests = 0;
successfulRequests = 0;
failedRequests = 0;
} finally {
rwLock.writeLock().unlock();
}
}
}
Lock Downgrading (Lock Upgrade dəstəklənmir)
class LockDowngradingExample {
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
private String data = "initial";
// Lock downgrading: write -> read
public void updateAndRead() {
rwLock.writeLock().lock();
try {
// Yazma əməliyyatı
data = "updated";
// Write lock tutarkən read lock al (downgrade)
rwLock.readLock().lock();
} finally {
rwLock.writeLock().unlock(); // Write lock burax
}
try {
// İndi read lock var
System.out.println("Data: " + data);
} finally {
rwLock.readLock().unlock();
}
}
// YANLIŞ - Lock upgrade (read -> write) dəstəklənmir!
public void wrongUpgrade() {
rwLock.readLock().lock();
try {
// Oxuma
if (needsUpdate(data)) {
// Read lock-u burax
rwLock.readLock().unlock();
// Write lock al
rwLock.writeLock().lock();
try {
// Yenidən yoxla (double-check)
if (needsUpdate(data)) {
data = "updated";
}
// Downgrade
rwLock.readLock().lock();
} finally {
rwLock.writeLock().unlock();
}
// Read lock yenidən əldə edildi
rwLock.readLock().lock();
}
} finally {
rwLock.readLock().unlock();
}
}
private boolean needsUpdate(String data) {
return data.equals("initial");
}
}
Fair vs Non-Fair
class FairnessExample {
// Non-fair (default) - daha sürətli
private ReadWriteLock nonFairLock = new ReentrantReadWriteLock(false);
// Fair - FIFO sırası, amma daha yavaş
private ReadWriteLock fairLock = new ReentrantReadWriteLock(true);
public void demonstrateFairness() {
ReadWriteLock lock = new ReentrantReadWriteLock(true); // Fair
// 5 reader
for (int i = 1; i <= 5; i++) {
new Thread(() -> {
lock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() +
" oxuyur");
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.readLock().unlock();
}
}, "Reader-" + i).start();
}
// 1 writer
new Thread(() -> {
lock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() +
" yazır");
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.writeLock().unlock();
}
}, "Writer").start();
}
}
tryLock() with ReadWriteLock
class TryLockExample {
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
private List<String> data = new ArrayList<>();
public String readWithTryLock() {
if (rwLock.readLock().tryLock()) {
try {
if (data.isEmpty()) {
return null;
}
return data.get(0);
} finally {
rwLock.readLock().unlock();
}
} else {
return "Read lock əldə edilmədi";
}
}
public boolean writeWithTimeout(String item) {
try {
if (rwLock.writeLock().tryLock(1, TimeUnit.SECONDS)) {
try {
data.add(item);
return true;
} finally {
rwLock.writeLock().unlock();
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return false;
}
}
Configuration Manager
class ConfigurationManager {
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Map<String, String> config = new HashMap<>();
public String getProperty(String key) {
rwLock.readLock().lock();
try {
return config.get(key);
} finally {
rwLock.readLock().unlock();
}
}
public Map<String, String> getAllProperties() {
rwLock.readLock().lock();
try {
return new HashMap<>(config); // Defensive copy
} finally {
rwLock.readLock().unlock();
}
}
public void setProperty(String key, String value) {
rwLock.writeLock().lock();
try {
config.put(key, value);
System.out.println("Config updated: " + key + " = " + value);
} finally {
rwLock.writeLock().unlock();
}
}
public void loadFromFile(String filename) {
rwLock.writeLock().lock();
try {
config.clear();
// Load from file
System.out.println("Config loaded from: " + filename);
} finally {
rwLock.writeLock().unlock();
}
}
}
Read-Heavy Workload
class ProductCatalog {
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Map<Long, Product> products = new HashMap<>();
// Çox tez-tez çağırılır (read-heavy)
public Product getProduct(Long id) {
rwLock.readLock().lock();
try {
return products.get(id);
} finally {
rwLock.readLock().unlock();
}
}
public List<Product> getAllProducts() {
rwLock.readLock().lock();
try {
return new ArrayList<>(products.values());
} finally {
rwLock.readLock().unlock();
}
}
public List<Product> searchProducts(String query) {
rwLock.readLock().lock();
try {
return products.values().stream()
.filter(p -> p.getName().contains(query))
.collect(Collectors.toList());
} finally {
rwLock.readLock().unlock();
}
}
// Nadir çağırılır
public void addProduct(Product product) {
rwLock.writeLock().lock();
try {
products.put(product.getId(), product);
} finally {
rwLock.writeLock().unlock();
}
}
public void updateProduct(Product product) {
rwLock.writeLock().lock();
try {
products.put(product.getId(), product);
} finally {
rwLock.writeLock().unlock();
}
}
}
class Product {
private Long id;
private String name;
private double price;
// constructor, getters, setters
public Long getId() { return id; }
public String getName() { return name; }
}
Performance Comparison
class PerformanceTest {
private static final int THREADS = 10;
private static final int OPERATIONS = 10000;
// synchronized istifadə edən versiya
static class SynchronizedCounter {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int get() {
return count;
}
}
// ReadWriteLock istifadə edən versiya
static class RWLockCounter {
private int count = 0;
private final ReadWriteLock lock = new ReentrantReadWriteLock();
public void increment() {
lock.writeLock().lock();
try {
count++;
} finally {
lock.writeLock().unlock();
}
}
public int get() {
lock.readLock().lock();
try {
return count;
} finally {
lock.readLock().unlock();
}
}
}
// Read-heavy workload-da ReadWriteLock daha sürətlidir
}
Best Practices
-
Read-heavy ssenarilərdə istifadə edin:
// Çox oxuma, az yazma
// ReadWriteLock performans artımı verir
ReadWriteLock lock = new ReentrantReadWriteLock(); -
Həmişə try-finally istifadə edin:
lock.readLock().lock();
try {
// read operation
} finally {
lock.readLock().unlock();
} -
Write lock-u minimuma endirin:
// Əvvəlcə hesablamaları et
Data prepared = prepareData();
// Sonra write lock al
lock.writeLock().lock();
try {
updateSharedState(prepared);
} finally {
lock.writeLock().unlock();
} -
Lock upgrade etməyə çalışmayın:
// YANLIŞ - deadlock riski
lock.readLock().lock();
lock.writeLock().lock(); // Block olacaq!
// DÜZGÜN - read lock burax, write lock al
lock.readLock().unlock();
lock.writeLock().lock(); -
Fair vs non-fair seçin:
// Non-fair (default) - performans
new ReentrantReadWriteLock(false);
// Fair - ədalət lazımsa
new ReentrantReadWriteLock(true);
Nə Zaman İstifadə Etməli?
ReadWriteLock istifadə edin:
- Çox oxuma, az yazma olan ssenarilərdə
- Oxuma əməliyyatları uzun çəkəndə
- Performance kritikdirsə
- Cache, configuration, catalog kimi strukturlar
Sadə synchronized istifadə edin:
- Oxuma və yazma tarazlıdırsa
- Critical section qısadırsa
- Sadəlik vacibdirsə
Limitlər və Alternativlər
// ReadWriteLock - yaxşı, amma daha yaxşısı var
ReadWriteLock rwLock = new ReentrantReadWriteLock();
// StampedLock - Java 8+, daha performanslı
StampedLock stampedLock = new StampedLock();
// ConcurrentHashMap - Map üçün ən yaxşısı
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
// CopyOnWriteArrayList - List üçün read-heavy
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
Özət
ReadWriteLock üstünlükləri:
- Paralel oxuma imkanı
- Read-heavy workload-da performans artımı
- Write əməliyyatları eksklüzivdir
Çatışmazlıqlar:
- synchronized-dən mürəkkəbdir
- Write-heavy ssenarilərdə üstünlük vermir
- Overhead var (lock management)