前言
当今互联网应用普遍需要支持高并发访问,而Java作为一种广泛使用的编程语言,其并发编程能力对于实现高性能的应用非常重要。而Java的JUC(java.util.concurrent)并发工具就提供了许多实用的工具类和接口,可以让Java应用轻松实现高效的并发编程。
ReetrantLock
ReentrantLock是Java提供的一个可重入锁,也是Java并发编程中最常用的一种锁。与synchronized关键字相比,ReentrantLock具有更大的灵活性和功能,可以更好地支持并发编程的实现。
特点
- 可重入性:与synchronized一样,ReentrantLock也支持可重入锁,即同一个线程可以重复获得该锁,而不会出现死锁。
- 公平锁:ReentrantLock可以创建公平锁,即按照线程请求的顺序分配锁,确保等待时间最长的线程最先获得锁,避免了线程饥饿问题。
- 中断响应:当线程等待获取锁的过程中,可以通过调用interrupt()方法中断等待,避免线程无限等待。
- 条件变量:ReentrantLock可以创建多个Condition对象,用于控制线程等待和唤醒,从而实现更灵活的线程协作。
- 性能优越:在高度竞争的多线程环境中,ReentrantLock相比synchronized有更好的性能表现,特别是在多处理器系统中。
简单使用
模拟秒杀商品场景
public class SecKillDemo {
private static int stock = 1;
// 秒杀锁
private static final ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
// 模拟多个用户抢购
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
// 加锁
lock.lock();
try {
// 判断库存是否足够
if (stock > 0) {
// 模拟生成订单
System.out.println(Thread.currentThread().getName() + "抢购成功,生成订单");
// 减少库存
stock--;
} else {
System.out.println(Thread.currentThread().getName() + "抢购失败,库存不足");
}
} finally {
// 解锁
lock.unlock();
}
}
}).start();
}
}
}
加锁结果:最先进来的线程抢购成功其余线程抢购失败
不加锁结果:4个线程抢购成功出现超卖现象
可重入示例
当一个线程获得了ReentrantLock锁之后,如果该线程继续请求获得这个锁,那么该线程可以继续获得这个锁,这种情况就是ReentrantLock锁的可重入性。下面是一个表现出ReentrantLock锁的可重入性的例子:
public class ReentrantLockExample {
private final ReentrantLock lock = new ReentrantLock();
public void outer() {
lock.lock(); // 第一次获取锁
try {
inner();
} finally {
lock.unlock(); // 释放锁
}
}
public void inner() {
lock.lock(); // 第二次获取锁
try {
System.out.println("第二次获取锁");
} finally {
lock.unlock(); // 释放锁
}
}
public static void main(String[] args) {
ReentrantLockExample example = new ReentrantLockExample();
example.outer();
}
}
在这个例子中,我们定义了一个ReentrantLock锁,并创建了一个outer方法和一个inner方法。在outer方法中,我们首先通过调用lock方法获取锁,并在try块中调用inner方法,然后在finally块中释放锁。在inner方法中,我们再次获取锁,并输出一条信息。
可以看到,在outer方法中,我们第一次获取锁,然后调用inner方法,inner方法中又通过lock方法获取了锁,但这次获取锁是成功的,并且能够正常输出信息,说明ReentrantLock锁具有可重入性。
Condition
当使用ReentrantLock时,可以使用Condition对象来进行线程的协调和等待。
public class ConditionDemo {
private ReentrantLock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
private int count = 0;
public void increment() {
lock.lock();
try {
while (count ==