二十四. 并发实战-ReentrantLock使用

前言

本篇文章将对JUC并发包里提供的ReentrantLock的使用进行说明。

正文

一. 非公平锁的使用

ReentrantLock默认是非公平锁,同时获取锁资源时会存在竞争关系,不能满足先到先获取的原则。示例如下。

public class ReentrantLockTest {

    @Test
    public void 测试非公平等待锁() throws Exception {
        // 创建锁对象,默认是非公平锁
        Lock lock = new ReentrantLock();

        // 创建CoundDownLatch对象,用于阻塞主线程
        CountDownLatch countDownLatch = new CountDownLatch(10);

        // 任务,里面存在同步代码块
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                lock.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + " 获得锁");
                } finally {
                    countDownLatch.countDown();
                    lock.unlock();
                }
            }
        };

        // 创建多个线程来执行同一个任务,会存在并发竞争锁的情况
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(runnable, "线程" + i);
            thread.start();
            // 放弃时间片,确保上一线程已经获取锁或者已经进入阻塞状态
            for (int k = 0; k < 100; k++) {
                Thread.yield();
            }
        }

        // 等待子线程执行完毕
        countDownLatch.await();
    }

}

上述示例中,创建ReentrantLock时使用的是无参构造函数,即创建的锁是非公平锁。构造了十个线程,依次执行同一个任务,在任务中存在同步代码块,因为是非公平锁,所以会出现后运行的线程比先运行的线程先拿到锁的情况。

运行测试程序,打印如下。

在这里插入图片描述

二. 公平锁的使用

通过ReentrantLock的有参构造函数并传入true,可以创建一个公平锁,公平锁一定满足先到先得的原则。示例如下。

public class ReentrantLockTest {

    @Test
    public void 测试公平等待锁() throws Exception {
        // 创建锁对象,默认是非公平锁
        Lock lock = new ReentrantLock(true);

        // 创建CoundDownLatch对象,用于阻塞主线程
        CountDownLatch countDownLatch = new CountDownLatch(10);

        // 任务,里面存在同步代码块
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                lock.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + " 获得锁");
                } finally {
                    countDownLatch.countDown();
                    lock.unlock();
                }
            }
        };

        // 创建多个线程来执行同一个任务,会存在并发竞争锁的情况
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(runnable, "线程" + i);
            thread.start();
            // 放弃时间片,确保上一线程已经获取锁或者已经进入阻塞状态
            for (int k = 0; k < 100; k++) {
                Thread.yield();
            }
        }

        // 等待子线程执行完毕
        countDownLatch.await();
    }

}

运行测试程序,打印如下。

在这里插入图片描述

无论运行多少次,一定是先启动的线程先获取到锁。

三. 重入锁的使用

ReentrantLock是可重入锁,即获取到锁的线程能够重复对锁资源进行获取。示例如下。

public class ReentrantLockTest {

    @Test
    public void 测试锁重入() {
        // 创建锁对象,默认是非公平锁
        Lock lock = new ReentrantLock();

        lock.lock();
        try {
            System.out.println("第一重获取锁");
            lock.lock();
            try {
                System.out.println("第二重获取锁");
            } finally {
                lock.unlock();
            }
        } finally {
            lock.unlock();
        }
    }

}

运行测试程序,打印如下。

在这里插入图片描述

总结

ReentrantLock的使用总结如下。

  1. ReentrantLock默认是非公平锁,即获取锁资源不满足先到先得;
  2. ReentrantLock可以通过构造函数指定为公平锁,即先尝试获取锁资源的线程一定比后尝试获取锁资源的线程先拿到锁;
  3. ReentrantLock是可重入锁,即获取到锁的线程能够重复对锁资源进行获取;
  4. ReentrantLocklock()方法会尝试获取锁,获取失败则进入同步队列等待;
  5. ReentrantLocktryLock()方法会尝试获取锁,获取成功返回true,获取失败立即返回false而不会进入同步队列等待;
  6. 获取到锁的线程,一定要在finally块中调用ReentrantLockunlock()方法来释放锁。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

樱花祭的约定

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

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

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

打赏作者

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

抵扣说明:

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

余额充值