Замок в Java
Интерфейс Lock из java.util.concurrent.locks
даёт явный захват и освобождение. Метод lock()
блокирует поток, пока замок занят, unlock()
передает его ожидающим.
Если исключение вылетит внутри участка, монитор всё
равно нужно отпустить. Парой try и
finally вызывают unlock() даже
при ошибке:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Tickets {
private final Lock gate = new ReentrantLock();
private int sold = 0;
void sellOne() {
gate.lock();
try {
sold++;
} finally {
gate.unlock();
}
}
int count() {
gate.lock();
try {
return sold;
} finally {
gate.unlock();
}
}
}
Два потока по пятьсот продаж и проверка суммы:
public class Main {
public static void main(String[] args) throws InterruptedException {
Tickets desk = new Tickets();
Runnable work = () -> {
for (int i = 0; i < 500; i++) {
desk.sellOne();
}
};
Thread a = new Thread(work);
Thread b = new Thread(work);
a.start();
b.start();
a.join();
b.join();
System.out.println(desk.count());
}
}
Тот же каркас подходит, когда между приращениями
есть пауза: замок удерживается только на время
изменения, а Thread.sleep выполняется
снаружи:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Main {
private static final Lock gate = new ReentrantLock();
private static int slot = 0;
static void bumpWithPause() throws InterruptedException {
Thread.sleep(10);
gate.lock();
try {
slot++;
} finally {
gate.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
Thread a = new Thread(() -> {
try {
bumpWithPause();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
Thread b = new Thread(() -> {
try {
bumpWithPause();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
a.start();
b.start();
a.join();
b.join();
System.out.println(slot);
}
}
Общий ReentrantLock и переменная
coins. Две фоновые задачи по
300 приращений под ручным замком
с finally. После ожидания обеих
выведите итог.