【多线程与高并发】ReentrantLock示例讲解

ReentrantLock 是 Java 提供的显式锁(明确地进行锁定和解锁操作),相对于 synchronized 隐式锁而言,ReentrantLock 提供了更多的功能和灵活性。

例如,它可以支持公平锁、非公平锁、尝试获取锁、可中断锁等。

示例代码
import java.util.concurrent.locks.ReentrantLock;

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

    public void increment() {
        lock.lock();  // 获取锁
        try {
            count++;
            // 模拟一些耗时操作
            Thread.sleep(100);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            lock.unlock();  // 释放锁
        }
    }

    public int getCount() {
        lock.lock();  // 获取锁
        try {
            return count;
        } finally {
            lock.unlock();  // 释放锁
        }
    }

    public static void main(String[] args) {
        Counter counter = new Counter();

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });

        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Final count: " + counter.getCount());
    }
}
讲解
  1. 1. 创建锁

    private final ReentrantLock lock = new ReentrantLock();

    这里我们创建了一个 ReentrantLock 实例,作为计数器操作的锁。

  2. 2. 获取锁和释放锁

    lock.lock();
    try {
        // 临界区代码
    } finally {
        lock.unlock();
    }

    在 increment 和 getCount 方法中,我们首先调用 lock.lock() 方法获取锁,然后在 finally 块中调用 lock.unlock() 方法释放锁。这样可以确保在临界区代码执行完毕后,锁一定会被释放,防止死锁。

  3. 3. 处理中断

    try {
        count++;
        // 模拟一些耗时操作
        Thread.sleep(100);
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }

    在临界区代码中,我们模拟了一些耗时操作,并捕获 InterruptedException,重新设置中断状态。这是因为如果一个线程在等待、睡眠或者尝试获取锁时被中断,中断异常会被抛出,但中断状态(Thread.interrupted())会被清除,所以需要重新设置中断状态。

  4. 4. 多线程操作

    Thread t1 = new Thread(() -> {
        for (int i = 0; i < 1000; i++) {
            counter.increment();
        }
    });
    
    Thread t2 = new Thread(() -> {
        for (int i = 0; i < 1000; i++) {
            counter.increment();
        }
    });
    
    t1.start();
    t2.start();

    我们创建了两个线程 t1 和 t2,每个线程都会调用 increment 方法 1000 次,以模拟多线程环境下的计数器操作。

  5. 5. 等待线程完成

    try {
        t1.join();
        t2.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    使用 join 方法等待两个线程执行完毕,确保主线程在两个工作线程结束后才继续执行,并最终输出计数器的值。

高级功能
  • • 公平锁与非公平锁:默认情况下,ReentrantLock 是非公平锁,但可以通过构造函数指定为公平锁。

    private final ReentrantLock lock = new ReentrantLock(true); // 公平锁

    公平锁意味着等待时间最长的线程将获得对锁的访问。

  • • 可中断锁:线程在等待锁的过程中可以被中断。

    try {
        lock.lockInterruptibly();
    } catch (InterruptedException e) {
        // 处理中断
    }
  • • 尝试获取锁:可以尝试获取锁,如果失败则不会等待,立即返回。

    if (lock.tryLock()) {
        try {
            // 临界区代码
        } finally {
            lock.unlock();
        }
    } else {
        // 获取锁失败,做其他事情
    }
  • • 条件变量: ReentrantLock 可以配合 Condition 使用,实现更加复杂的线程同步。

    Condition condition = lock.newCondition();
    condition.await();
    condition.signal();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

这孩子叫逆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值