Java并发之ReentrantLock

本文详细介绍ReentrantLock的特点及使用方式,包括手动释放锁、指定尝试申请锁时间、中断响应、公平锁设定及Condition条件等功能,并提供了示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ReentrantLock 可以替代synchrozied,可以完成同样的功能, 更灵活 手动上锁,手动释放锁

主要有以下几个特点:

  1. 必须手动释放锁
  2. 可以指定时间,要是时间段内没有申请到,就可以自己做相应处理
  3. 中断响应,锁定之后,别人可以打断
  4. 还可以把锁指定为公平锁,谁等的时间长,谁就会优先得到锁
  5. Condition条件

方法整理:

  • lock():获取锁,如果已被占用,则等待
  • lockInterruptibly():获取锁,优先响应中断
  • tryLock():尝试获取锁,如果成功,返回true;失败,返回false。该方法不等待,立即返回
  • tryLock(long time, TimeUnit unit):在给定时间内获取锁
  • unLock():释放锁

1、Reentrantlock 必须要手动释放锁

使用 synchrozied 锁定的话如果遇到异常,jvm会自动释放锁,但是lock必须手动释放锁,因此经常在finally中进行锁的释放

    Lock lock = new ReentrantLock();
    void m1() {
        try {
            lock.lock(); //synchronized(this)
            for (int i = 0; i < 10; i++) {
                TimeUnit.SECONDS.sleep(1);
                System.out.println(i);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

2、指定尝试申请锁时间

使用 tryLock 可以进行“尝试锁定”,如果无法锁定,或者在指定时间内无法锁定,线程可以决定是否继续等待

    /**
     * 使用tryLock进行尝试锁定,不管锁定与否,方法都将继续执行
     * 可以根据tryLock的返回值来判定是否锁定
     * 也可以指定tryLock的时间,由于tryLock(time)抛出异常,所以要注意unclock的处理,必须放到finally中
     */
    void m2() {
        /*
        boolean locked = lock.tryLock();
        System.out.println("m2 ..." + locked);
        if(locked) lock.unlock();
        */

        boolean locked = false;

        try {
            locked = lock.tryLock(5, TimeUnit.SECONDS);
            System.out.println("m2 ..." + locked);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if(locked) lock.unlock();
        }   
    }

3、中断响应

lock.lockInterruptibly() 对线程中断 interrupt() 做出响应
使用 lockInterruptibly() 则该线程在等待锁的过程中,如果被中断,则直接抛出中断异常来立即响应中断,由上层调用者处理中断。最后线程结束等锁
而使用 lock() ,则不会响应中断,默认自己处理中断,继续获取锁直到成功。

        Thread t1 = new Thread(()->{
            try {
                lock.lock();
                System.out.println("t1 start");
                TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
                System.out.println("t1 end");
            } catch (InterruptedException e) {
                System.out.println("t1 interrupted!");
            } finally {
                lock.unlock();
            }
        });
        t1.start();

        Thread t2 = new Thread(()->{
            try {
                    //可以对interrupt()方法做出响应,然后结束等锁
                lock.lockInterruptibly(); 
                System.out.println("t2 start");
                TimeUnit.SECONDS.sleep(5);
                System.out.println("t2 end");
            } catch (InterruptedException e) {
                System.out.println("t2 interrupted!");
            } finally {
                lock.unlock();
            }
        });
        t2.start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //打断线程2的等待
        t2.interrupt(); 

4、可以指定为公平锁

公平锁:谁等的时间长谁就先得到锁

//参数为true表示为公平锁
private static ReentrantLock lock = new ReentrantLock(true); 

5、Condition条件

Condition对象和Object.wait()/notify()的作用是大致相同的。wait/notify和synchronized合作使用,而condition和ReentrantLock相关联。通过Lock接口的newCondition可以生产与当前ReentrantLock绑定的Condition实例。

// 使当前线程等待,同时释放锁。
// 使用signal/signalAll重新获取锁。
// 当线程被中断时,也可以跳出等待
void await() throws InterruptedException
// 与await基本相同,只是不响应中断
void awaitUniterrutibly()
long awaitNanos(long nanosTimeout) throws InterruptedException
boolean await(long time, TimeUnit unit) throws InterruptedException
boolean awaitUtil(Date deadline) throws InterruptedException
// 唤醒等待线程
void signal()
void signalAll()

演示说明

ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
//子线程中
public void run{
    try {
        lock.lock();
        condition.await();
        System.out.println("Thread is going on");
    } catch(InterruptedException e) {
        e.printStackTrace();
    } finally {
        lock.unlock();
    }
}

//主线中
lock.lock(); //先获取锁
condition.signal();
lock.unlock(); //释放锁,让给被唤醒的线程,让可以继续执行

和wait/notify 一样,当线程使用 Condition.await() 和 signal() 时必须先获取锁。当调用condition.await() 后,会释放这把锁;当调用condition.signal()后,会从当前Condition对象的等待队列中唤醒一个线程,唤醒后,会重新尝试获取与之绑定的重入锁,一旦成功,就可以继续执行了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值