ReentrantLock学习总结

ReentrantLock锁和synchronized锁相比具有以下特点:

  1. 可被中断:即可以设置“可中断锁”,当t1线程获取不到锁对象处于Blocked状态时,可由另一个线程调用t1的interrupt方法将其中断,此时t1会抛出被打断异常。
  2. 可以设置超时时间:如果没有获取到锁对象处于Blocked状态时,t1线程可以自己决定要等待多久。
  3. 可以设置为公平锁。
  4. 支持多个条件变量,即不同线程可以处于不同的waitSet进行等待,唤醒时也可以按照waitSet唤醒。

ReetrantLock的打开方式:

1、可打断锁

//可打断
public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            try {
                //如果没有竞争,此方法就会获取lock对象的锁
                //如果有竞争,就进入阻塞队列,但可以被其他线程用interrupt方法打断
                System.out.println("尝试获得锁ing");
                //获得可打断锁
                lock.lockInterruptibly();
            } catch (InterruptedException e) {
                //如果被锁被打断,就会抛出异常
                System.out.println("我被打断了,没有获得锁");
                e.printStackTrace();
                return;
            }

            try {
                System.out.println("获取到锁");
            } finally {
                lock.unlock();
            }
        }, "t1");


        //主线程先加锁
        lock.lock();
        t1.start();

        Thread.sleep(1000);
        //主线程打断t1,不让他Blocked下去,此时t1抛出异常进入catch块
        System.out.println("打断t1");
        t1.interrupt();


    }

 2、可超时锁

public static void main(String[] args) {
        Thread t1= new Thread(()->{
            //尝试获得锁,如果成功了,返回true,获得锁;失败了返回false
            
            //如果传递时间参数(如下面代码),则会等待1s,如果能获取到,则获取,不能获得则不等待
            try {
                if (!lock.tryLock(1, TimeUnit.SECONDS)) {
                    System.out.println("没有获得锁");
                    return;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //如果顺利走到这里,说明得到了锁
            System.out.println("获得到了锁");
            lock.unlock();


        },"t1");

        lock.lock();
        System.out.println("主线程获得到锁");
        t1.start();
        lock.unlock();
    }

3、多个waitSet

public class TestCondition_04 {
    private static ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) throws InterruptedException {
        //创建两个新的条件变量(即新的休息室)
        Condition condition = lock.newCondition();
        Condition condition1 = lock.newCondition();

        Thread t1 = new Thread(() -> {
            lock.lock();
            try {
                //进入第一间休息室等待
                condition1.await();
                System.out.println("我被唤醒啦 ");
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println("我被打断啦");
            }
            finally {
                lock.unlock();
            }

        }, "t1");
        t1.start();
        //先让主线程睡一会,确保t1线程已经进入waitSet
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //和notify一样,唤醒线程也需要先拿到锁
        lock.lock();
        //唤醒第一个waitSet的线程
        condition1.signal();
        //主线程必须要释放锁后t1才能进入执行后面的指令!
        lock.unlock();

        //测试t1是否释放了锁
        Thread.sleep(1000);
        lock.lock();
        System.out.println("如果看到了我,说明t1线程把锁释放了");
        lock.unlock();


    }
}

切记:使用完ReentrantLock锁后,一定要把锁释放掉!不然线程虽然结束,但是锁并没有被释放。个人认为这是和synchronized的最大的不同,synchronized只要临界区执行完毕就会自动释放锁。

在waitSet中的线程,如果被唤醒或者被interrupt,都会进入entrySet进入Block状态竞争锁。竞争锁成功后,如果是被唤醒则执行后面的指令,如果是被interrupt,则执行catch{},最后一定要释放锁。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值