Java - 各种锁的理解与实现-2

2 篇文章 0 订阅

1. 公平锁与非公平锁

 1)公平锁

  当多个线程按照申请锁的顺序排队获取锁,获取不到锁的进入阻塞队列,按照顺序依次获取锁

Lock lock= new ReentrantLock(true);

 2)非公平锁

        多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程先获得锁,在高并发的场景下,有可能造成优先级反转或者某个线程一直得不到锁

 synchronized 是非公平锁,Synchronized 是通过对象内部的叫一个监视器锁(monitor)来实现的。这种依赖于操作系统的 mutex lock 所实现的锁称之为重量级锁

 ReentrantLock 可以进行选择设置,默认是非公平锁,ReentrantLock 是基于AQS的

        其原理大致为:当某一线程获取锁后,将state+1,并记录下当前持有锁的线程,再有线程来获取锁时,判断这个线程与持有锁的线程是否是同一个线程,如果是,将state值再+1,如果不是,阻塞线程。 当线程释放锁时,将state-1,当state值减为0时,表示当前线程彻底释放了锁,然后将记录当前持有锁的线程的那个字段设置为null,并唤醒其他线程,使其重新竞争锁

Lock lock= new ReentrantLock(false);
// 默认是 false
Lock lock= new ReentrantLock();

2. 可重入锁

        可重入锁:当已获取锁的线程,在访问该锁资源的其余代码时,无需再获取锁,可直接进入,称之为可重入锁;可重入锁能有效避免死锁的情况

 public class  Phone {
    // 类锁
    public static synchronized void sendEmail(){
        sendSMS(Thread.currentThread().getName());
        System.out.println("-----sendEmail");
    }
    // 类锁
    public static synchronized void sendSMS(String threadName){
        System.out.println(threadName + "-----sendSMS");
    }
    public void sendHello(){
        System.out.println("-----sendHello");
    }
     public static void main(String[] args) {
         Phone phone = new Phone();

         new Thread(()->{
             phone.sendEmail();
         },"t1").start();

         new Thread(()->{
             phone.sendSMS(Thread.currentThread().getName());
         },"t2").start();

         new Thread(()->{
             phone.sendHello();
         },"t3").start();
     }
}

执行结果:

         当 t1 线程获得类锁之后,去调用 sendSMS 需要获得该方法的类锁,但是之前在执行 sendEmail 时候已经获得该类锁,所以此时无需再次获得,直接执行,这个就叫可重入锁;synchronized 和 ReentrantLock 都是可重入锁,当 t1 执行完毕后,释放了类锁,t2 线程才能进入其执行方法 sendSMS

ReentrantLock 和 synchronized 都是悲观锁,非公平锁,可重入锁

3. Lock 接口及其实现类 ReentrantLock

  Java 中默认对资源上锁使用 synchronized 关键字,但是 synchronized 关键字功能有限,Java 1.5以后又在 JUC 包下设计了一个新的一套对资源上锁和解锁的代码

Lock 接口以及其实现类

 使用方式:

// 获取ReentrantLock对象
private ReentrantLock lock = new ReentrantLock();

// 加锁 获取不到锁会阻塞
lock.lock();

try {
	System.out.println("this a thread lock");
}finally {

	// 释放锁 如果不释放其他线程就获取不到锁
	lock.unlock();
}

synchronized 和 ReentrantLock区别:

  • synchronized 是Java的关键字,基于jvm实现,ReentrantLock 是juc包下面的类库,是api层面的锁
  • synchronized 会自动加锁和释放锁,ReentrantLock 需要手动调用 lock() 方法和 unlock() 方法加锁和释放锁
  • synchronized 可以用在普通方法上、使用在静态方法上、使用在代码块中,ReentrantLock 只能在代码块中使用

  • ReentrantLock 支持可响应中断synchronized 不支持响应中断

  • synchronized 只能支持非公平锁,ReentrantLock 支持公平锁和非公平锁

  •  ReentrantLock 配合 condition 可以绑定多个条件,实现多个阻塞队列,能够更加精准的加锁和释放锁

   

        

       

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值