浅析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实现生成PDF文件

    如何利用java实现生成PDF文件

    前段时间因为相关业务需求需要后台生成pdf文件,下面这篇文章主要给大家介绍了关于如何利用java实现生成PDF文件的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-10-10
  • Springboot项目参数校验方式(Validator)

    Springboot项目参数校验方式(Validator)

    本文介绍了如何在Spring Boot项目中使用`spring-boot-starter-validation`包和注解来实现请求参数校验,主要介绍了校验注解的使用方法、校验失败的异常捕获以及`@Validated`的分组功能
    2025-02-02
  • Spring Boot整合Elasticsearch实现全文搜索引擎案例解析

    Spring Boot整合Elasticsearch实现全文搜索引擎案例解析

    ElasticSearch作为基于Lucene的搜索服务器,既可以作为一个独立的服务部署,也可以签入Web应用中。SpringBoot作为Spring家族的全新框架,使得使用SpringBoot开发Spring应用变得非常简单,在本案例中我们给大家介绍Spring Boot整合Elasticsearch实现全文搜索引擎
    2017-11-11
  • java 实现黄金分割数的示例详解

    java 实现黄金分割数的示例详解

    这篇文章主要介绍了java 实现黄金分割数的示例详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • ES修改字段类型的操作方式

    ES修改字段类型的操作方式

    ES修改字段类型是指在已有的索引中,通过特定的操作方式将某个字段的类型修改为其它类型,这篇文章主要介绍了ES修改字段类型的相关知识,感兴趣的朋友跟随小编一起看看吧
    2023-10-10
  • MyBatis类型转换模块的实现

    MyBatis类型转换模块的实现

    MyBatis是一个持久层框架ORM框架,实现数据库中数据和Java对象中的属性的双向映射,那么不可避免的就会碰到类型转换的问题,本文主要介绍了MyBatis类型转换模块的实现,感兴趣的可以了解一下
    2023-09-09
  • mybatis如何使用注解实现一对多关联查询

    mybatis如何使用注解实现一对多关联查询

    这篇文章主要介绍了mybatis如何使用注解实现一对多关联查询的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • Springboot实例讲解实现专业材料认证管理系统流程

    Springboot实例讲解实现专业材料认证管理系统流程

    这是一个基于java的毕业设计项目,毕设课题为springboot框架的知识产权服务平台系统,是一个采用b/s结构的javaweb项目,需要的朋友可以参考下
    2022-06-06
  • redis redisson 限流器的实例(RRateLimiter)

    redis redisson 限流器的实例(RRateLimiter)

    这篇文章主要介绍了redis redisson 限流器的实例(RRateLimiter),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • java 中链表的定义与使用方法

    java 中链表的定义与使用方法

    这篇文章主要介绍了java 中链表的定义与使用方法的相关资料,需要的朋友可以参考下
    2017-03-03

最新评论