ReentrantLock

目录

一.ReentrantLock 简介

二.可重入

三.可打断

四.锁超时

五.条件变量


一.ReentrantLock 简介

相对于 synchronized 它具备如下特点:

(1)可中断 : lock.lockInterruptibly 与 thread.interrupt() 
(2)可以设置超时时间 :lock.tryLock(long timeout, TimeUnit unit)
(3)可以设置为公平锁/非公平锁 :new ReentrantLock(boolean fair)
        公平锁(FairSync):线程获取锁的顺序按照线程加锁的顺序来分配(先来先得)
        非公平锁(默认,NonfairSync):获取锁的抢占机制,随机
(4)支持多个条件变量
(5)与 synchronized 一样,都支持可重入
        线程再次获取锁:所需要去识别获取锁的线程是否为当前占据锁的线程,如果是,则再次获取成功;
        锁的最终释放:线程重复n次获取了锁,随后在第n次释放该锁后,其它线程能够获取到该锁。锁的最终释放要求锁对于获取进行计数自增,计数表示当前线程被重复获取的次数,而被释放时,计数自减,当计数为0时表示锁已经成功释放。

基本语法:

        // 获取锁
        reentrantLock.lock();
        try {
            // 临界区
        } finally {
            // 释放锁
            reentrantLock.unlock();
        }

二.可重入

        可重入是指同一个线程如果首次获得了这把锁,那么因为它是这把锁的拥有者,因此有权利再次获取这把锁 如果是不可重入锁,那么第二次获得锁时,自己也会被锁挡住。
    static ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) {
        method1();
    }

    private static void method1() {
        lock.lock();
        try {
            System.out.println("execute method1");
            method2();
        } finally {
            lock.unlock();
        }
    }

    private static void method2() {
        lock.lock();
        try {
            System.out.println("execute method2");
            method3();
        } finally {
            lock.unlock();
        }
    }

    private static void method3() {
        lock.lock();
        try {
            System.out.println("execute method3");
        } finally {
            lock.unlock();
        }
    }

输出:

三.可打断

    static ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + " 启动...");
            try {
                lock.lockInterruptibly();
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println(Thread.currentThread().getName() + " 等锁的过程中被打断");
                return;
            }
            try {
                System.out.println(Thread.currentThread().getName() + " 获得了锁");
            } finally {
                lock.unlock();
            }
        }, "t1");

        lock.lock();
        System.out.println(Thread.currentThread().getName() + " 获得了锁");
        t1.start();
        try {
            Thread.sleep(1000);
            t1.interrupt();
            System.out.println(Thread.currentThread().getName() + " 执行了打断");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

输出:

四.锁超时

    static ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + " 启动...");
            try {
                if (!lock.tryLock(1, TimeUnit.SECONDS)) {
                    System.out.println(Thread.currentThread().getName() + " 获取等待 1s 后失败,返回");
                    return;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {
                System.out.println(Thread.currentThread().getName() + " 获得了锁");
            } finally {
                lock.unlock();
            }
        }, "t1");

        lock.lock();
        System.out.println(Thread.currentThread().getName() + " 获得了锁");
        t1.start();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

输出:

五.条件变量

        synchronized 中也有条件变量,就是  waitSet 休息室,当条件不满足时进入 waitSet 等待。
        ReentrantLock 的条件变量比 synchronized 强大之处在于,它是支持多个条件变量的,这就好比
        synchronized 是那些不满足条件的线程都在一间休息室等消息
        而 ReentrantLock 支持多间休息室,唤醒时也是按休息室来唤醒
使用要点:
(1)await 前需要获得锁
(2)await 执行后,会释放锁,进入 conditionObject 等待
(3)await 的线程被唤醒(或打断、或超时)取重新竞争 lock
(4)竞争 lock 锁成功后,从 await 后继续执行
    static ReentrantLock lock = new ReentrantLock();

    static Condition waitCigaretteQueue = lock.newCondition();

    static Condition waitbreakfastQueue = lock.newCondition();

    static volatile boolean hasCigrette = false;

    static volatile boolean hasBreakfast = false;

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            try {
                lock.lock();
                while (!hasCigrette) {
                    try {
                        waitCigaretteQueue.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName() + " 等到了他的烟");
            } finally {
                lock.unlock();
            }
        }, "t1").start();

        new Thread(() -> {
            try {
                lock.lock();
                while (!hasBreakfast) {
                    try {
                        waitbreakfastQueue.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName() + " 等到了他的早餐");
            } finally {
                lock.unlock();
            }
        }, "t2").start();

        Thread.sleep(1000);
        sendBreakfast();
        Thread.sleep(1000);
        sendCigarette();
    }

    private static void sendCigarette() {
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + " 送烟来了");
            hasCigrette = true;
            waitCigaretteQueue.signal();
        } finally {
            lock.unlock();
        }
    }

    private static void sendBreakfast() {
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + " 送早餐来了");
            hasBreakfast = true;
            waitbreakfastQueue.signal();
        } finally {
            lock.unlock();
        }
    }

输出:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值