浅析JAVA Lock锁原理

 更新时间:2020年07月23日 11:14:57   作者:呼噜葫芦  
这篇文章主要介绍了JAVA Lock锁原理的相关资料,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下

同样是锁,先说说synchronized和lock的区别:

  1. synchronized是java关键字,是用c++实现的;而lock是用java类,用java可以实现
  2. synchronized可以锁住代码块,对象和类,但是线程从开始获取锁之后开发者不能进行控制和了解;lock则用起来非常灵活,提供了许多api可以让开发者去控制加锁和释放锁等等。

写个Demo

static Lock lock = new ReentrantLock();public static void main(String[] args) throws InterruptedException {


    lock.lock();//其他没拿到锁的卡住不动

    Thread thread = new Thread(new Runnable() {
      @Override
      public void run() {
        System.out.println("start to get lock Interruptibly");
        lock.unlock(); //看看会发生什么,注释掉再看看
        lock.lock();
        System.out.println("拿到锁");
        lock.unlock();
        System.out.println("释放锁");
      }
    });
    thread.start();

    Thread.sleep(3000);
    lock.unlock();
  }

我们自己来手写一下lock接口的tryLock()、lock()和unLock()方法,实现我们自己的myLock。

public class MyLock implements Lock {
  //多并发调用 0-未占用 大于0-占用
  AtomicInteger state = new AtomicInteger();

  Thread ownerThread = new Thread();

  //等待锁的队列
  LinkedBlockingQueue<Thread> waiters = new LinkedBlockingQueue();

  @Override
  public void lock() {
    if (!tryLock()) { //先抢锁,所以是非公平锁
      //没拿到锁,放到队列中去进行排队
      waiters.add(Thread.currentThread());
      //等待被唤醒
      for (; ; ) {
        if (tryLock()) { //非公平锁情况下,唤醒过来继续获取锁
          waiters.poll(); //获取锁成功把自己从队列中取出来
          return;
        } else  //获取锁失败
          LockSupport.park(); //线程阻塞
      }
    }
  }


  @Override
  public boolean tryLock() {
    if (state.get() == 0) { //如果锁没被占用
      if (state.compareAndSet(0, 1)) { //如果成功拿到锁
        ownerThread = Thread.currentThread();  //占用锁线程改为当前线程
        return true;
      }
    }
    return false;
  }

  @Override
  public void unlock() {

    if (ownerThread != Thread.currentThread()) //占用锁线程不是当前线程无法释放锁
      throw new RuntimeException("非法调用,当前锁不属于你");

    if (state.decrementAndGet() == 0) //如果成功释放锁
      ownerThread = null; //占用锁线程置空
    //通知其他线程
//    Thread thread = null;
//
//    while ((thread = waiters.peek()) != null)
//      LockSupport.unpark(thread);
    Thread thread = waiters.peek(); //获取队列头部线程,线程还留在队列中
    if (thread != null) {
      LockSupport.unpark(thread); //取消阻塞
    }
  }



  @Override
  public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
    return false;
  }


  @Override
  public Condition newCondition() {
    return null;
  }

  @Override
  public void lockInterruptibly() throws InterruptedException {

  }
}

几个注意点:

  • 锁的占用状态state是AtomicInteger类型,底层原理是CAS,这是为了保证在多并发情况下线程安全问题;
  • 当线程1释放锁成功时,获取队列头部线程但并不取出,因为非公平锁模式下,队列头部线程不一定能获取到锁;
  • LockSupport的park()和unPark()方法是native方法,可以阻塞,唤醒线程;

Lock默认是非公平锁,上面实现的也是非公平锁,小伙伴们可以试一试。

公平锁和非公平锁区别:

先等待先获取锁是公平锁;先等待也不一定先获取锁,可能被突然到来的线程获取到是非公平锁;

公平锁的实现:

@Override
  public void lock() {
    checkQueue();//线程来的时候先不获取锁,而是先检查队列中有没有等待的线程,如果有,直接放入队列,如果没有,再去获取锁
    if (!tryLock()) { //先抢锁,所以是非公平锁
      //没拿到锁,放到队列中去进行排队
      waiters.add(Thread.currentThread());
      //等待被唤醒
      for (; ; ) {
        if (tryLock()) { //非公平锁情况下,唤醒过来继续获取锁
          waiters.poll(); //获取锁成功把自己从队列中取出来
          return;
        } else  //获取锁失败
          LockSupport.park(); //线程阻塞
      }
    }
  }

看完的小伙伴可以去看JDK提供的Lock源码啦。。

以上就是浅析JAVA Lock锁原理的详细内容,更多关于JAVA Lock锁原理的资料请关注脚本之家其它相关文章!

相关文章

  • Java十大经典排序算法的实现图解

    Java十大经典排序算法的实现图解

    Java常见的排序算法有:插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等。本文详解介绍Java十大十大经典排序算法的实现以及图解,需要的可以参考一下
    2022-03-03
  • java中char类型转换成int类型的2种方法

    java中char类型转换成int类型的2种方法

    这篇文章主要给大家介绍了关于java中char类型转换成int类型的2种方法,因为java是一门强类型语言,所以在数据运算中会存在类型转换,需要的朋友可以参考下
    2023-07-07
  • Springboot中加入druid连接池

    Springboot中加入druid连接池

    这篇文章主要介绍了Springboot中加入druid连接池,Druid是目前最好的数据库连接池。在功能、性能、扩展性方面,都超过其他数据库连接池,同时加入了日志监控,下面来看看文章的具体内容吧
    2022-01-01
  • Java如何使用JSR303校验数据与自定义校验注解

    Java如何使用JSR303校验数据与自定义校验注解

    这篇文章主要介绍了Java如何使用JSR303校验数据与自定义校验注解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • Spring如何基于注解配置使用ehcache

    Spring如何基于注解配置使用ehcache

    这篇文章主要介绍了Spring如何基于注解配置使用ehcache,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-10-10
  • Mybatis高级映射、动态SQL及获得自增主键的解析

    Mybatis高级映射、动态SQL及获得自增主键的解析

    MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis。这篇文章主要介绍了Mybatis高级映射、动态SQL及获得自增主键的相关资料,需要的朋友可以参考下
    2016-11-11
  • SpringMVC中的@ControllerAdvice使用场景详解

    SpringMVC中的@ControllerAdvice使用场景详解

    这篇文章主要介绍了SpringMVC中的@ControllerAdvice使用场景详解,在Spring MVC进行调用的过程中,会有很多的特殊的需求,比如全局异常,分页信息和分页搜索条件,请求时带来返回时还得回显页面,需要的朋友可以参考下
    2024-01-01
  • 基于String和List<String>间的相互转换方式

    基于String和List<String>间的相互转换方式

    这篇文章主要介绍了基于String和List间的相互转换方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-05-05
  • 解决SpringBoot使用devtools导致的类型转换异常问题

    解决SpringBoot使用devtools导致的类型转换异常问题

    这篇文章主要介绍了解决SpringBoot使用devtools导致的类型转换异常问题,具有很好的参考价值,希望对大家有所帮助。 一起跟随小编过来看看吧
    2020-08-08
  • 深入理解MyBatis中的一级缓存与二级缓存

    深入理解MyBatis中的一级缓存与二级缓存

    这篇文章主要给大家深入的介绍了关于MyBatis中一级缓存与二级缓存的相关资料,文中详细介绍MyBatis中一级缓存与二级缓存的工作原理及使用,对大家具有一定的参考性学习价值,需要的朋友们下面来一起看看吧。
    2017-06-06

最新评论