Java中的Lock锁

Lock锁介绍:

在java中可以使用 synchronized 来实现多线程下对象的同步访问,为了获得更加灵活使用场景、高效的性能,java还提供了Lock接口及其实现类ReentrantLock和读写锁 ReentrantReadWriteLock。

相比synchronized来实现同步,使用Lock实现同步主要有以下差异性:

1、使用synchronized关键字时,锁的控制和释放是在synchronized同步代码块的开始和结束位置。而在使用Lock实现同步时,锁的获取和释放可以在不同的代码块、不同的方法中。这一点是基于使用者手动获取和释放锁的特性。

2、Lock接口提供了试图获取锁的tryLock()方法,在调用tryLock()获取锁失败时返回false,这样线程可以执行其它的操作 而不至于使线程进入休眠。tryLock()方法可传入一个long型的时间参数,允许在一定的时间内来获取锁。

3、Lock接口的实现类ReentrantReadWriteLock提供了读锁和写锁,允许多个线程获得读锁、而只能有一个线程获得写锁。读锁和写锁不能同时获得。实现了读和写的分离,这一点在需要并发读的应用中非常重要,如lucene允许多个线程读取索引数据进行查询但只能有一个线程负责索引数据的构建。

4、基于以上3点,lock来实现同步具备更好的性能。

Lock锁与条件同步:

与synchronized类似,Lock锁也可以实现条件同步。在java的concurrent包中提供了 Condition 接口及其实现类ConditionObject。

当满足一定条件时,调用Condition的await()方法使当前线程进入休眠状态进行等待。调用Condition的signalAll()方法唤醒因await()进入休眠的线程。

synchronized与条件同步博文中,我们使用synchronized实现了一个生产者-消费者模型,在这里,来试试使用Lock锁及其同步条件来实现同样的一个生产者-消费者模型:

public class MessageStorageByLock {
    private int maxSize;
    private List messages;

    private final ReentrantLock lock;
    private final Condition conditionWrite;//声明两个锁条件
    private final Condition conditionRead;
    public MessageStorageByLock(int maxSize) {
        this.maxSize = maxSize;
        messages = new LinkedList();
        lock = new ReentrantLock(true);//true修改锁的公平性,为true时,使用lifo队列来顺序获得锁
        conditionWrite = lock.newCondition();//调用newCondition()方法,即new ConditionObject();
        conditionRead = lock.newCondition();

    }
    public void set(String message){
        //使用锁实现同步,获取所得操作,当锁被其他线程占用时,当前线程将进入休眠
        lock.lock();
        try{
            while(messages.size() == maxSize){
                    System.out.print("the message buffer is full now,start into wait()\n");
                    conditionWrite.await();//满足条件时,线程休眠并释放锁。当调用 signalAll()时。线程唤醒并重新获得锁
            }
            Thread.sleep(100);
            messages.add(message);
            System.out.print("add message:"+message+" success\n");
            conditionRead.signalAll();//唤醒因conditionRead.await()休眠的线程
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
    public String get(){
        String message = null;
        lock.lock();
        try{
            while(messages.size() == 0){
                conditionRead.await();
                System.out.print("the message buffer is empty now,start into wait()\n");
            }
            Thread.sleep(100);
            message = ((LinkedList)messages).poll();
            System.out.print("get message:"+message+" success\n");
            conditionWrite.signalAll();
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        return message;
    }
}

不管是synchronized关键字还是Lock锁,都是用来在多线程的环境下对资源的同步访问进行控制,用以避免因多个线程对数据的并发读写造成的数据混乱问题。与synchronized不同的是,Lock锁实现同步时需要使用者手动控制锁的获取和释放,其灵活性使得可以实现更复杂的多线程同步和更高的性能,但同时,使用者一定要在获取锁后及时捕获代码运行过程中的异常并在finally代码块中释放锁。

Original: https://www.cnblogs.com/cl1024cl/p/6205013.html
Author: 代码王子
Title: Java中的Lock锁

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/538728/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 突破

    象棋的目标是赢棋,而不是谋子。突破了「谋子」这一认知的棋手,招式中就多了欲擒故纵。甚至棋手心里都没想着招式,只是在朝着目标布局。 象棋的目标是赢棋,而不是谋子。突破了「谋子」这一认…

    Java 2023年6月16日
    090
  • 制作JavaCV应用依赖的基础Docker镜像(CentOS7+JDK8+OpenCV4)

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java、Docker、Kuberne…

    Java 2023年6月8日
    085
  • Windows下安装kubectl及Node和Pod操作常用命令

    kubernetes通过kube-apiserver作为整个集群管理的入口。Apiserver是整个集群的主管理节点,用户通过Apiserver配置和组织集群,同时集群中各个节点同…

    Java 2023年6月7日
    088
  • [开源项目]可观测、易使用的SpringBoot线程池

    在开发spring boot应用服务的时候,难免会使用到异步任务及线程池。spring boot的线程池是可以自定义的,所以我们经常会在项目里面看到类似于下面这样的代码 @Bean…

    Java 2023年6月15日
    084
  • resultMap的用法以及关联结果集映射

    resultTyperesultType可以把查询结果封装到pojo类型中,但必须pojo类的属性名和查询到的数据库表的字段名一致。如果sql查询到的字段与pojo的属性名不一致,…

    Java 2023年6月5日
    085
  • Java异常

    1.异常引入 package exception; @SuppressWarnings({"all"}) /** * @Author Blueshadow * …

    Java 2023年6月8日
    083
  • Java 知识积累方便以后随时查看

    一、Java数据类型 8种基本数据类型:字符型char,布尔型boolean,数值型(整型和浮点型) 其中整型包括(byte,short,int,long),浮点型(float,d…

    Java 2023年5月29日
    073
  • mybatis中resultMap嵌套list的写法(两种)

    方式一:代码复用性高, 主表分页查询正确(主表分页查询时,子表会将所有的数据查询出来) QuestionMapper.xml SELECTpq.id, pq.content, pq…

    Java 2023年5月30日
    082
  • 图解Tire树+代码实现

    简介 Trie又称为前缀树或字典树,是一种有序树,它是一种专门用来处理串匹配的数据结构,用来解决一组字符中快速查找某个字符串的问题。Google搜索的关键字提示功能相信大家都不陌生…

    Java 2023年6月9日
    086
  • 【实战】利用多线程优化查询百万级数据

    前言 日常开发中,难免会遇到需要查询到数据库所有记录的业务场景,在索引完善的情况下,当数据量达到百万级别或者以上的时候,全表查询就需要耗费不少的时间,这时候我们可以从以下几个方向着…

    Java 2023年6月5日
    088
  • SpringBoot-Learning

    本项目内容为Spring Boot教程程序样例。 作者博客:http://blog.didispace.com Spring Boot系列博文:http://blog.didisp…

    Java 2023年5月30日
    055
  • java集合框架07——Map架构与源代码分析

    前几节我们对Collection以及Collection中的List部分进行了分析,Collection中还有个Set,因为Set是基于Map实现的,所以这里我们先分析Map,后面…

    Java 2023年5月29日
    079
  • Jenkins持续集成入门到精通(进阶篇)

    视频参考:https://www.bilibili.com/video/BV1Vp4y1b7ZN?p=51 Jenkins+Docker+SpringCloud持续集成流程说明 大…

    Java 2023年6月8日
    098
  • 转摘:Spring、SpringMVC和Springboot的区别

    一、概念 1、Spring Spring是一个开源容器框架,可以接管web层,业务层,dao层,持久层的组件,并且可以配置各种bean,和维护bean与bean之间的关系。其核心就…

    Java 2023年5月30日
    078
  • Lambda表达式

    1.常见单方法接口 Comparator Runnable Callable @FunctionalInterface 只定义了单方法的接口称之为 FunctionalInterf…

    Java 2023年6月13日
    0103
  • java-面向对象三大特征

    面向对象编程的三大特征:继承、封装、多态 继承是面向对象编程的三大特征之一。继承让我们更加容易实现类的扩展。实现代码的重用,不用再重新发明轮子(don’t reinve…

    Java 2023年6月15日
    090
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球