Əsas məzmuna keçin

Java Lock və ReentrantLock

Lock Interface Nədir?

Lock interface synchronized keyword-ə alternativ olaraq daha çevik lock mexanizmi təqdim edir. java.util.concurrent.locks paketində yerləşir.

synchronized vs Lock

// synchronized ilə
public synchronized void method() {
// critical section
}

// Lock ilə
private final Lock lock = new ReentrantLock();

public void method() {
lock.lock();
try {
// critical section
} finally {
lock.unlock(); // Mütləq finally-də unlock
}
}

ReentrantLock Basic Usage

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

class Counter {
private int count = 0;
private final Lock lock = new ReentrantLock();

public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock(); // Həmişə finally-də
}
}

public int getCount() {
lock.lock();
try {
return count;
} finally {
lock.unlock();
}
}
}

tryLock() - Non-blocking Lock

class BankAccount {
private int balance = 1000;
private final Lock lock = new ReentrantLock();

public boolean withdraw(int amount) {
if (lock.tryLock()) { // Gözləmədən lock almağa çalış
try {
if (balance >= amount) {
balance -= amount;
return true;
}
return false;
} finally {
lock.unlock();
}
}
return false; // Lock əldə edilmədi
}
}

tryLock() with Timeout

class Resource {
private final Lock lock = new ReentrantLock();

public void accessResource() throws InterruptedException {
// 5 saniyə gözlə
if (lock.tryLock(5, TimeUnit.SECONDS)) {
try {
System.out.println("Resource əldə edildi");
// İş görülür
} finally {
lock.unlock();
}
} else {
System.out.println("Resource əldə edilə bilmədi");
}
}
}

Fair Lock

// Fair lock - thread-lər gözləmə sırasına görə lock alır
Lock fairLock = new ReentrantLock(true);

// Non-fair lock (default) - daha sürətli, amma ədalətsiz
Lock nonFairLock = new ReentrantLock(false);

Fair vs Non-Fair Example

class FairLockExample {
private final Lock fairLock = new ReentrantLock(true);

public void fairMethod() {
fairLock.lock();
try {
System.out.println(Thread.currentThread().getName() +
" lock aldı (fair)");
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
fairLock.unlock();
}
}
}

// Fair lock-da thread-lər FIFO sırası ilə lock alır

Deadlock Prevention with tryLock()

class Account {
private int balance;
private final Lock lock = new ReentrantLock();

public Lock getLock() {
return lock;
}

public void withdraw(int amount) {
balance -= amount;
}

public void deposit(int amount) {
balance += amount;
}

public int getBalance() {
return balance;
}
}

class BankTransfer {
public boolean transfer(Account from, Account to, int amount) {
// Deadlock-dan qaçmaq üçün tryLock
if (from.getLock().tryLock()) {
try {
if (to.getLock().tryLock()) {
try {
from.withdraw(amount);
to.deposit(amount);
return true;
} finally {
to.getLock().unlock();
}
}
} finally {
from.getLock().unlock();
}
}
return false; // Transfer uğursuz
}
}

lockInterruptibly()

class InterruptibleLockExample {
private final Lock lock = new ReentrantLock();

public void doWork() throws InterruptedException {
lock.lockInterruptibly(); // Interrupt edilə bilən lock
try {
// Uzun müddətli iş
Thread.sleep(10000);
} finally {
lock.unlock();
}
}
}

// Thread interrupt edilərsə, lockInterruptibly()
// InterruptedException atır

Condition Variables

class BoundedBuffer {
private final Lock lock = new ReentrantLock();
private final Condition notFull = lock.newCondition();
private final Condition notEmpty = lock.newCondition();

private final Object[] items = new Object[10];
private int putIndex, takeIndex, count;

public void put(Object item) throws InterruptedException {
lock.lock();
try {
while (count == items.length) {
notFull.await(); // Buffer dolu, gözlə
}
items[putIndex] = item;
putIndex = (putIndex + 1) % items.length;
count++;
notEmpty.signal(); // Consumer-ə xəbər ver
} finally {
lock.unlock();
}
}

public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0) {
notEmpty.await(); // Buffer boş, gözlə
}
Object item = items[takeIndex];
takeIndex = (takeIndex + 1) % items.length;
count--;
notFull.signal(); // Producer-ə xəbər ver
return item;
} finally {
lock.unlock();
}
}
}

Lock-un Üstünlükləri

  1. tryLock() - Non-blocking lock əldə etmə
  2. tryLock(timeout) - Timeout ilə lock
  3. lockInterruptibly() - Interrupt edilə bilən lock
  4. Fair lock - FIFO sırası
  5. Multiple conditions - Bir lock üçün bir neçə condition
  6. Daha çevik - synchronized-dən daha çox kontrol

Best Practices

  1. Həmişə try-finally istifadə edin:

    lock.lock();
    try {
    // critical section
    } finally {
    lock.unlock(); // Mütləq
    }
  2. tryLock() deadlock prevention üçün:

    if (lock.tryLock()) {
    try {
    // work
    } finally {
    lock.unlock();
    }
    }
  3. Fair lock performans üçün yalnız lazım olduqda:

    // Ədalət vacib deyilsə, default (non-fair) istifadə edin
    Lock lock = new ReentrantLock(); // Non-fair, daha sürətli
  4. Sadə hallarda synchronized istifadə edin:

    // Sadə lock üçün synchronized kifayətdir
    public synchronized void simpleMethod() {
    // work
    }

Nə Zaman Lock, Nə Zaman synchronized?

synchronized istifadə edin:

  • Sadə lock/unlock tələb olunduqda
  • try-finally yazmaq istəmirsizsə
  • Method səviyyəsində lock lazımdırsa

Lock istifadə edin:

  • tryLock() lazımdırsa (deadlock prevention)
  • Timeout lazımdırsa
  • Fair ordering lazımdırsa
  • Multiple condition variables lazımdırsa
  • Interrupt edilə bilən lock lazımdırsa