浅析JAVA Lock锁原理

所属分类: 软件编程 / java 阅读数: 98
收藏 0 赞 0 分享

同样是锁,先说说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锁原理的资料请关注脚本之家其它相关文章!

更多精彩内容其他人还在看

JavaWeb项目部署到服务器详细步骤详解

这篇文章主要介绍了JavaWeb项目如何部署到服务器,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

IDEA基于支付宝小程序搭建springboot项目的详细步骤

这篇文章主要介绍了IDEA基于支付宝小程序搭建springboot项目的详细步骤,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

详解SpringBoot应用服务启动与安全终止

这篇文章主要介绍了SpringBoot应用服务启动与安全终止,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

Spring Boot启动及退出加载项的方法

这篇文章主要介绍了Spring Boot启动及退出加载项的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

Spring Data Jpa 自动生成表结构的方法示例

这篇文章主要介绍了Spring Data Jpa 自动生成表结构的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

IDEA中osgi的开发应用指南详解

这篇文章主要介绍了IDEA中osgi的开发应用指南详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

详解用maven将dubbo工程打成jar包运行

这篇文章主要介绍了详解用maven将dubbo工程打成jar包运行,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

详解Java合并数组的两种实现方式

这篇文章主要介绍了Java合并数组的两种实现方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

使用Jenkins Pipeline自动化构建发布Java项目的方法

这篇文章主要介绍了使用Jenkins Pipeline自动化构建发布Java项目的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

使用Maven配置Spring的方法步骤

这篇文章主要介绍了使用Maven配置Spring的方法步骤,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享
查看更多