浅析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锁原理的资料请关注我们其它相关文章!

时间: 2020-07-23

详解Java多线程编程中互斥锁ReentrantLock类的用法

0.关于互斥锁 所谓互斥锁, 指的是一次最多只能有一个线程持有的锁. 在jdk1.5之前, 我们通常使用synchronized机制控制多个线程对共享资源的访问. 而现在, Lock提供了比synchronized机制更广泛的锁定操作, Lock和synchronized机制的主要区别: synchronized机制提供了对与每个对象相关的隐式监视器锁的访问, 并强制所有锁获取和释放均要出现在一个块结构中, 当获取了多个锁时, 它们必须以相反的顺序释放. synchronized机制对锁的释放是

Java多线程 ReentrantLock互斥锁详解

加锁和解锁 我们来看下ReentrantLock的基本用法 ThreadDomain35类 public class ThreadDomain35 { private Lock lock = new ReentrantLock(); public void testMethod() { try { lock.lock(); for (int i = 0; i < 2; i++) { System.out.println("ThreadName = " + Thread.curre

java并发编程专题(四)----浅谈(JUC)Lock锁

首先我们来回忆一下上一节讲过的synchronized关键字,该关键字用于给代码段或方法加锁,使得某一时刻它修饰的方法或代码段只能被一个线程访问.那么试想,当我们遇到这样的情况:当synchronized修饰的方法或代码段因为某种原因(IO异常或是sleep方法)被阻塞了,但是锁有没有被释放,那么其他线程除了等待以外什么事都做不了.当我们遇到这种情况该怎么办呢?我们今天讲到的Lock锁将有机会为此行使他的职责. 1.为什么需要Lock synchronized 是Java 语言层面的,是内置的关

java同步之如何写一个锁Lock

问题 (1)自己动手写一个锁需要哪些知识? (2)自己动手写一个锁到底有多简单? (3)自己能不能写出来一个完美的锁? 简介 本篇文章的目标一是自己动手写一个锁,这个锁的功能很简单,能进行正常的加锁.解锁操作. 本篇文章的目标二是通过自己动手写一个锁,能更好地理解后面章节将要学习的AQS及各种同步器实现的原理. 分析 自己动手写一个锁需要准备些什么呢? 首先,在上一章学习synchronized的时候我们说过它的实现原理是更改对象头中的MarkWord,标记为已加锁或未加锁. 但是,我们自己是无

Java Lock锁多线程中实现流水线任务

下面程序代码通过使用Lock锁执行简单的流水线任务: import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @author lzq * @data 2020/4/29 0029 - 下午 9:48 */ public class TestLock { public stat

Javas使用Redlock实现分布式锁过程解析

一.redlock简介 在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段.实现高效的分布式锁有三个属性需要考虑: 安全属性:互斥,不管什么时候,只有一个客户端持有锁 效率属性A:不会死锁 效率属性B:容错,只要大多数redis节点能够正常工作,客户端端都能获取和释放锁. Redlock是redis官方提出的实现分布式锁管理器的算法.这个算法会比一般的普通方法更加安全可靠.关于这个算法的讨论可以看下官方文档. 二.怎么用java使用 redlock 在pom文件引入redis和

详解java并发之重入锁-ReentrantLock

前言 目前主流的锁有两种,一种是synchronized,另一种就是ReentrantLock,JDK优化到现在目前为止synchronized的性能已经和重入锁不分伯仲了,但是重入锁的功能和灵活性要比这个关键字多的多,所以重入锁是可以完全替代synchronized关键字的.下面就来介绍这个重入锁. 正文 ReentrantLock重入锁是Lock接口里最重要的实现,也是在实际开发中应用最多的一个,我这篇文章更接近实际开发的应用场景,为开发者提供直接上手应用.所以不是所有方法我都讲解,有些冷门

Java lock同步锁使用实例解析

这篇文章主要介绍了Java lock同步锁使用实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1)Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现,synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就

Java多线程编程之读写锁ReadWriteLock用法实例

读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,这是由jvm自己控制的,你只要上好相应的锁即可.如果你的代码只读数据,可以很多人同时读,但不能同时写,那就上读锁:如果你的代码修改数据,只能有一个人在写,且不能同时读取,那就上写锁.总之,读的时候上读锁,写的时候上写锁! 三个线程读数据,三个线程写数据示例: 可以同时读,读的时候不能写,不能同时写,写的时候不能读. 读的时候上读锁,读完解锁:写的时候上写锁,写完解锁. 注意finally解锁. package com.ljq.test.th

深入理解java内置锁(synchronized)和显式锁(ReentrantLock)

synchronized 和 Reentrantlock 多线程编程中,当代码需要同步时我们会用到锁.Java为我们提供了内置锁(synchronized)和显式锁(ReentrantLock)两种同步方式.显式锁是JDK1.5引入的,这两种锁有什么异同呢?是仅仅增加了一种选择还是另有其因?本文为您一探究竟. // synchronized关键字用法示例 public synchronized void add(int t){// 同步方法 this.v += t; } public stati

Java锁机制Lock用法示例

本文实例讲述了Java锁机制Lock用法.分享给大家供大家参考,具体如下: package com.expgiga.JUC; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * 一.用于解决多线程安全问题的方式: * 1.同步代码块 synchronized 隐式锁 * 2.同步方法 synchronized 隐式锁 * 3.同步锁Lock (jdk1.5以后

java基于jedisLock—redis分布式锁实现示例代码

分布式锁是啥? 单机锁的概念:我们正常跑的单机项目(也就是在tomcat下跑一个项目不配置集群)想要在高并发的时候加锁很容易就可以搞定,java提供了很多的机制例如:synchronized.volatile.ReentrantLock等锁的机制. 为啥需要分布式锁:当我们的项目比较庞大的时候,单机版的项目已经不能满足吞吐量的需求了,需要对项目做负载均衡,有可能还需要对项目进行解耦拆分成不同的服务,那么肯定是做成分布式的项目,分布式的项目因为是不同的程序控制,所以使用java提供的锁并不能完全保

java语言描述Redis分布式锁的正确实现方式

分布式锁一般有三种实现方式:1.数据库乐观锁:2.基于Redis的分布式锁:3.基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介绍Redis分布式锁实现的博客,然而他们的实现却有着各种各样的问题,为了避免误人子弟,本篇博客将详细介绍如何正确地实现Redis分布式锁. 可靠性 首先,为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件: 互斥性.在任意时刻,只有一个客户端能持有锁. 不会发生死锁.即使有一个客户端在持有锁的期间

基于Redis分布式锁的实现代码

概述 目前几乎很多大型网站及应用都是分布式部署的,分布式场景中的数据一致性问题一直是一个比较重要的话题.分布式的CAP理论告诉我们"任何一个分布式系统都无法同时满足一致性(Consistency).可用性(Availability)和分区容错性(Partition tolerance),最多只能同时满足两项."所以,很多系统在设计之初就要对这三者做出取舍.在互联网领域的绝大多数的场景中,都需要牺牲强一致性来换取系统的高可用性,系统往往只需要保证"最终一致性",只要这

scala+redis实现分布式锁的示例代码

1.redis的底层是单例模式,意思是同一个脚本同一时刻只能有一个线程来执行,利用redis的这个特性来实现分布式锁. 首先实现工具类 package utils import CacheManager /** * redis分布式锁 */ object RedisTool { //加锁是否成功标志 val LOCK_SUCCESS:String = "OK" //即当key不存在时,我们进行set操作:若key已经存在,则不做任何操作: val SET_IF_NOT_EXIST:St

Python实现的redis分布式锁功能示例

本文实例讲述了Python实现的redis分布式锁功能.分享给大家供大家参考,具体如下: #!/usr/bin/env python # coding=utf-8 import time import redis class RedisLock(object): def __init__(self, key): self.rdcon = redis.Redis(host='', port=6379, password="", db=1) self._lock = 0 self.lock

Java注解如何基于Redission实现分布式锁

这篇文章主要介绍了Java注解如何基于Redission实现分布式锁,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.定义注解类 @Target({ ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DistributedLock { //锁名称 String lockName() default ""; /

Java Redis分布式锁的正确实现方式详解

前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介绍Redis分布式锁实现的博客,然而他们的实现却有着各种各样的问题,为了避免误人子弟,本篇博客将详细介绍如何正确地实现Redis分布式锁. 可靠性 首先,为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件: 互斥性.在任意时刻,只有一个客户端能持有锁. 不会发生死锁.即使有一个客户端在

Java编程redisson实现分布式锁代码示例

最近由于工作很忙,很长时间没有更新博客了,今天为大家带来一篇有关Redisson实现分布式锁的文章,好了,不多说了,直接进入主题. 1. 可重入锁(Reentrant Lock) Redisson的分布式可重入锁RLock Java对象实现了java.util.concurrent.locks.Lock接口,同时还支持自动过期解锁. public void testReentrantLock(RedissonClient redisson){ RLock lock = redisson.getL

浅谈Java(SpringBoot)基于zookeeper的分布式锁实现

通过zookeeper实现分布式锁 1.创建zookeeper的client 首先通过CuratorFrameworkFactory创建一个连接zookeeper的连接CuratorFramework client public class CuratorFactoryBean implements FactoryBean<CuratorFramework>, InitializingBean, DisposableBean { private static final Logger LOGG

浅谈Redis分布式锁的正确实现方式

前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介绍Redis分布式锁实现的博客,然而他们的实现却有着各种各样的问题,为了避免误人子弟,本篇博客将详细介绍如何正确地实现Redis分布式锁. 可靠性 首先,为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件: 1.互斥性.在任意时刻,只有一个客户端能持有锁. 2.不会发生死锁.即使有一个