寒假打卡15-1月30日
Java ReentrantLock——高级锁机制详解
在 Java 并发编程中,synchronized
关键字提供了一种简单的锁机制来保护共享资源,但它具有一些局限性,例如不支持公平锁、无法中断等待锁的线程等。Java 提供了 ReentrantLock
类来克服这些局限性,并提供更高级的锁机制。
ReentrantLock 的基本概念
ReentrantLock
是 java.util.concurrent.locks 包中的一个类,它实现了 Lock 接口。与 synchronized
不同,ReentrantLock
提供了更多的锁操作选项,如公平锁、可重入锁、可中断锁和定时锁等。
ReentrantLock 的主要特性
- 可重入性:与
synchronized
类似,ReentrantLock
也支持可重入性,即同一个线程可以多次获取同一个锁。 - 公平锁:
ReentrantLock
支持公平锁和非公平锁,公平锁按线程请求锁的顺序获取锁,非公平锁则可能导致线程饥饿。 - 可中断锁:
ReentrantLock
提供了可以中断的锁获取操作,允许线程在等待锁时响应中断。 - 定时锁:
ReentrantLock
提供了定时锁获取操作,允许线程在等待锁时设置超时时间。
ReentrantLock 的使用方法
基本使用
下面是一个使用 ReentrantLock
保护共享资源的简单示例:
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockDemo {
private final ReentrantLock lock = new ReentrantLock();
private int counter = 0;
public void increment() {
lock.lock();
try {
counter++;
} finally {
lock.unlock();
}
}
public int getCounter() {
lock.lock();
try {
return counter;
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
ReentrantLockDemo demo = new ReentrantLockDemo();
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
demo.increment();
}
};
Thread thread1 = new Thread(task);
Thread thread2 = new Thread(task);
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Counter: " + demo.getCounter());
}
}
在上述代码中,lock.lock()
和 lock.unlock()
用于获取和释放锁,以确保 counter
的递增操作是线程安全的。
公平锁
ReentrantLock
构造函数可以接受一个布尔参数来指定是否启用公平锁:
ReentrantLock fairLock = new ReentrantLock(true);
公平锁按线程请求锁的顺序获取锁,避免了线程饥饿。
可中断锁
ReentrantLock
提供了 lockInterruptibly()
方法,可以在等待锁时响应中断:
public void incrementInterruptibly() throws InterruptedException {
lock.lockInterruptibly();
try {
counter++;
} finally {
lock.unlock();
}
}
定时锁
ReentrantLock
提供了 tryLock(long timeout, TimeUnit unit)
方法,可以在等待锁时设置超时时间:
public boolean tryIncrement(long timeout, TimeUnit unit) throws InterruptedException {
if (lock.tryLock(timeout, unit)) {
try {
counter++;
return true;
} finally {
lock.unlock();
}
} else {
return false;
}
}
ReentrantLock 的高级用法
条件变量
ReentrantLock
提供了条件变量(Condition)来实现线程间的通信和协作。条件变量类似于 Object
的 wait
和 notify
方法,但提供了更强大的功能。
示例代码
下面是一个使用条件变量实现生产者-消费者模式的示例:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.LinkedList;
import java.util.Queue;
public class ProducerConsumerDemo {
private final ReentrantLock lock = new ReentrantLock();
private final Condition notFull = lock.newCondition();
private final Condition notEmpty = lock.newCondition();
private final Queue<Integer> queue = new LinkedList<>();
private final int capacity = 10;
public void produce(int value) throws InterruptedException {
lock.lock();
try {
while (queue.size() == capacity) {
notFull.await();
}
queue.offer(value);
notEmpty.signalAll();
} finally {
lock.unlock();
}
}
public int consume() throws InterruptedException {
lock.lock();
try {
while (queue.isEmpty()) {
notEmpty.await();
}
int value = queue.poll();
notFull.signalAll();
return value;
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
ProducerConsumerDemo demo = new ProducerConsumerDemo();
Runnable producerTask = () -> {
for (int i = 0; i < 20; i++) {
try {
demo.produce(i);
System.out.println("Produced: " + i);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
};
Runnable consumerTask = () -> {
for (int i = 0; i < 20; i++) {
try {
int value = demo.consume();
System.out.println("Consumed: " + value);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
};
Thread producerThread = new Thread(producerTask);
Thread consumerThread = new Thread(consumerTask);
producerThread.start();
consumerThread.start();
try {
producerThread.join();
consumerThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在上述代码中,生产者线程和消费者线程通过条件变量 notFull
和 notEmpty
实现线程间的通信和协作。生产者在队列满时等待,消费者在队列空时等待。
总结
ReentrantLock
提供了一种灵活且功能强大的锁机制,克服了 synchronized
的一些局限性。它支持公平锁、可中断锁、定时锁和条件变量,适用于多种并发编程场景。通过合理使用 ReentrantLock
,我们可以编写出更加高效和健壮的多线程程序。
希望通过本篇文章,大家对 Java ReentrantLock
有了更深入的了解。在接下来的文章中,我们将继续探讨更多关于 Java 并发编程的知识点,敬请期待!