重入锁ReentrantLock

1:概览

  • 重入锁完全可以代替synchronized
  • lock()方法显示加锁
  • unlock()方法显示释放锁
  • 要注意的是lock()获取锁的方法无法响应中断

可以指定合适加锁和合适释放锁,比较灵活

支持重入

重入锁也是支持重入的,但是仅限于已获得该锁的那一个线程

lock.lock();
lock.lock();
	一些操作
lock.unlock();
lock.unlock();

注意加锁了几次就要释放锁几次

  • 如果释放的次数少了
    • 相对于当前线程还持有该锁,其他线程无法获得该锁
  • 如果释放次数多了
    • 相对于没有获得锁就释放锁,会抛出异常

2:中断响应

这是比起synchronized来说一个比较独特的功能。

使用synchronized时,如果等待一个锁就必须一直等待下去。如果发生死锁等等就无法解决。

但是重入锁在等待获得锁的时候提供了可以被中断的能力

  • lockInterruptibly()方法:这是一个可以对中断进行响应的锁申请操作,即在锁等待的过程中,可以响应中断。会将中断标志位复位
import java.util.Scanner;
import java.util.concurrent.locks.ReentrantLock;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        th t=new th();
        Thread t1=new Thread(t, "t1");
        Thread t2=new Thread(t, "t2");
        t1.start();
        Thread.sleep(1000);
        t2.start();
        t2.interrupt();
        Thread.sleep(1000);
        System.out.println(t2.isInterrupted());
    }
}

class th implements Runnable{
    ReentrantLock lock=new ReentrantLock();
    @Override
    public void run() {
        try {
            lock.lockInterruptibly();

            System.out.println(Thread.currentThread().getName()+"获得锁了,");
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            lock.unlock();
            System.out.println(Thread.currentThread().getName()+"释放锁");
        } catch (InterruptedException e) {
            System.out.println(Thread.currentThread().getName()+"申请锁等待的时候响应中断,不执行了。");
        }


    }

}
》》》》》》》》》》》》
t1获得锁了,
t2申请锁等待的时候响应中断,不执行了。
false
t1释放锁

t1先获得该锁,并且持有一段时间,这时候t2线程开启也去申请该锁,由于t1申请,就只能等待该锁,这时候对t2进行中断,由于使用的是lockInterruptibly()方法,等待锁的时候可以被中断,这时候t2被中断了就响应中断,而不会再去等待该锁了

3:锁申请等待限时

  • 锁等待的时候有一个时间限制,超过了这个时间就不再申请锁了
  • 使用tryLock()方法,在时间限制内获得锁返回true,否则返回false
  • 如果不带参数,等待时间就是0,尝试获取锁失败就不再等待锁
  • 而且也是可以响应中断的!
import java.sql.Timestamp;
import java.util.Scanner;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        th t=new th();
        Thread t1=new Thread(t, "t1");
        Thread t2=new Thread(t, "t2");
        Thread t3=new Thread(t, "t3");

        t1.start();
        Thread.sleep(1000);
        t2.start();
        t3.start();
        Thread.sleep(1000);
        t3.interrupt();
    }
}

class th implements Runnable{
    ReentrantLock lock=new ReentrantLock();
    @Override
    public void run() {
        try {
            if(lock.tryLock(5, TimeUnit.SECONDS)){
                System.out.println(Thread.currentThread().getName()+"获取锁成功");
                Thread.sleep(10000);
                lock.unlock();
                System.out.println(Thread.currentThread().getName()+"释放锁");
            }else{
                System.out.println(Thread.currentThread().getName()+"没有获取到该锁");
            }
        } catch (InterruptedException e) {
            System.out.println(Thread.currentThread().getName()+"被中断了");
        }


    }

}
---------------
t1获取锁成功
t3被中断了
t2没有获取到该锁
t1释放锁

这段代码很好地展示了限时等待锁的情况,而且也说明了这种方法去申请锁也是能在等待过程中被中断的。

4:公平锁

  • 重入锁默认是非公平锁
  • 但是可以设置为公平锁new ReentrantLock(true);
  • 公平锁就是==按照时间地顺序,先到先得
  • 公平锁很好地避免了饥饿
  • 但是公平锁要维护一个有序队列,开销大,性能低下
  • 当锁可用时,几个线程都在申请该锁,非公平锁会随机让一个线程获得该锁,而公平锁是让有序对列排头地线程获得锁。注意公平锁与i非公平锁针对地是请求锁,而不是线程间通信的等待和唤醒

5:重入锁的好搭档-Condition

  • object.wait()与object.notify()是与synchronized配合使用
  • condition与重入锁相配合使用
  • 通过一个重入锁lock,调用lock.newCondition()可以得到一个与该重入锁相关联的condition对象
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值