【JUC基础】04. Lock锁

news2024/11/15 19:59:56

1、前言

java.util.concurrent.locks为锁定和等待条件提供一个框架的接口和类,说白了就是锁所在的包。

2、什么是Lock

Lock是一种锁机制,比同步块(synchronized block)更加灵活,同时也更加复杂的线程同步机制。在JDK1.5就已存在Lock接口了。

其中有三个实现类:

  1. ReentrantLock:可重入锁
  2. ReentrantReadWriteLock.ReadLock:读锁
  3. ReentrantReadWriteLock.WriteLock:写锁

3、Lock的API

Lock接口只提供了6个方法:

其中lock()和unlock()是配对的。lock()是加锁,而unlock()是解锁。lockInterruptibly()与lock()类似,区别在于lock()如果无法获取到锁,线程一直被阻塞,直到锁释放。而lockInterruptibly()允许线程被中断,并抛出java.lang.InterruptedException。

tryLock()只有在调用时才可以获得锁。如果可用,则获取锁定,并返回true,反之返回false。相应的还有重载方法tryLock(long time, TimeUnit unit)表示在给定的等待时间内空闲,则可以获取锁。如果到了超时时间,还没获取到就放弃获取。

4、ReentrantLock的基本使用

Lock是一个接口,官方文档其实也给了如何使用的说明:

  1. 声明Lock对象。Lock lock = new XXXLock();
  2. 方法执行加锁lock.lock();
  3. 在方法块执行完毕后,需要释放锁:lock.unlock();

 

由于LocK是一个接口,需要使用具体的实现。典型的实现如ReentrantLock。示例代码如下:

public class ReentrantLockDemo {

    public static void main(String[] args) {
        Phones phones = new Phones();

        new Thread(() -> {
            for(int i = 0; i< 50; i++) {
                phones.sale();
            }
        }, "销售员小王").start();

        new Thread(() -> {
            for(int i = 0; i< 50; i++) {
                phones.sale();
            }
        }, "销售员小红").start();
    }

}

class Phones {
    // 库存10部手机
    private int total = 50;

    // 1、 声明锁的实例
    ReentrantLock lock = new ReentrantLock();

    public void sale(){
        try {
            // 2、加锁,代码规约检测会提示你加载try的第一行
            lock.lock();
            if(total > 0){
                System.out.println(Thread.currentThread().getName() + "卖出了一部手机,当前库存剩余:" + (--total));
            }
        } finally {
            // 3、释放锁
            lock.unlock();
        }
    }
}

执行结果:

ReentrantLock是个可重入锁,其中可以执行公平锁和非公平锁。如new ReentrantLock(true),默认是非公平锁(false)。

4.1、公平锁和非公平锁

  • 公平锁:每个线程获取锁的顺序按照先后顺序获取。关键字眼:先到先得。
    • 优点:能保证所有的线程都得到资源,不会产生线程饥饿现象。
    • 缺点:吞吐量低,除了第一个线程以外,其余的都处于排队阻塞的状态,cpu需要每次唤醒线程,开销较大。
  • 非公平锁:多个线程同时尝试获取,哪个线程优先获取到锁取决于系统分配策略。关键字眼:无需排队。
    • 优点:吞吐量高,cpu无需唤醒所有的线程,开销低。
    • 缺点:会产生线程饥饿现象,可能后到的线程先获取到锁,而前面的线程永远都获取不到

5、读写锁ReadWriteLock

ReadWriteLock是一个读写锁接口。什么是读写锁呢?看下官方文档说明:

 

ReadWriteLock分为一个读锁和一个写锁。读锁可以被多个线程持有,而写锁只能被一个线程持有。典型的实现类有ReentrantReadWriteLock。

读锁:就是我们常说的共享锁。

写锁:就是常说的独占锁。

示例代码:

public class ReadWriteLock {

    public static void main(String[] args) {
        MyMap map = new MyMap();

        // 写操作
        for (int i = 0; i < 5; i++) {
            int finalI = i;
            new Thread(() -> map.put(String.valueOf(finalI), String.valueOf(finalI))).start();
        }

        // 读操作
        for (int i = 0; i < 5; i++) {
            int finalI = i;
            new Thread(() -> map.get(String.valueOf(finalI))).start();
        }
    }

}

// 模拟公共资源类
class MyMap extends HashMap<String, String> {

    @Override
    public String get(Object key) {
        System.out.println(Thread.currentThread().getName() + "获取key:" + key);
        return super.get(key);
    }

    @Override
    public String put(String key, String value) {
        System.out.println(Thread.currentThread().getName() + "写入key:" + key);
        String put = super.put(key, value);
        System.out.println(Thread.currentThread().getName() + "写入key:" + key + "完成");
        return put;
    }
}

如果不加入任何的锁限制,我们直到结果肯定是很随机的。在写入操作时会被其他读线程插队。

加入读写锁后:

public class ReadWriteLock {

    public static void main(String[] args) {
        MyMap map = new MyMap();

        // 写操作
        for (int i = 0; i < 5; i++) {
            int finalI = i;
            new Thread(() -> map.put(String.valueOf(finalI), String.valueOf(finalI))).start();
        }

        // 读操作
        for (int i = 0; i < 5; i++) {
            int finalI = i;
            new Thread(() -> map.get(String.valueOf(finalI))).start();
        }
    }

}

// 模拟公共资源类
class MyMap extends HashMap<String, String> {

    private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();

    @Override
    public String get(Object key) {
        try{
            rwLock.readLock().lock();

            System.out.println(Thread.currentThread().getName() + "获取key:" + key);
            return super.get(key);

        } finally {
            rwLock.readLock().unlock();
        }
    }

    @Override
    public String put(String key, String value) {
        try {
            rwLock.writeLock().lock();

            System.out.println(Thread.currentThread().getName() + "写入key:" + key);
            String put = super.put(key, value);
            System.out.println(Thread.currentThread().getName() + "写入key:" + key + "完成");
            return put;
        } finally {
            rwLock.writeLock().unlock();
        }
    }
}

 

我们可以看到在写入的时候,并不会有读的线程插队操作。

6、小结

关于Lock锁大概就讲这些,主要讲了ReentrantLock和ReadWriteLock的基本使用,也是通常比较常用的。其中Locks中还有一个接口Condition,这个等后面讲生产者和消费者的时候在细说。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/505141.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Node.js,多环境配置

目录 1、多环境简介 2、多环境配置 3、命令运行 1、多环境简介 在前端项目的开发过程中&#xff0c;我们需要把项目发布到不同服务器环境中&#xff0c;例如&#xff0c;测试&#xff0c;生产&#xff0c;开发&#xff0c;预生产等环境。在这个我们需要对不同的环境设置不同…

函数的运用

函数的运用 一、函数的定义二、简单函数实验两个数字的运算&#xff1a;调用位置变量函数变量的作用范围 三、函数的递归阶乘递归目录 四、函数库 一、函数的定义 shell函数是经常使用的&#xff0c;因为有些命令序列是需要反复调用执行的&#xff0c;将命令序列按格式写在一起…

三分钟教你Mac下安装VmWare虚拟机

大数据课程课前环境准备&#xff1a;mac中安装三台linux服务器 一、课前准备 准备一台内存最少8G&#xff08;建议16G&#xff09;、cpu i7 4核的电脑 二、课堂主题 安装虚拟化软件VMware准备3台linux虚拟机 三、课堂目标 完成mac下3个虚拟机的安装 四、知识要点 文档说…

洗稿用什么软件-洗稿软件免费

洗稿文章的主要优势 洗稿文章的主要优势在于提高文章的质量和效率。以下是洗稿文章的几个主要优势&#xff1a; 优化结构和语言 洗稿可以删除冗余、无用和重复的内容&#xff0c;同时对文章的结构和语言进行优化&#xff0c;提高文章的可读性和吸引力。这可以使文章更加专业…

探索自然语言处理领域的最新进展与挑战

自然语言处理&#xff08;NLP&#xff09;是人工智能领域中最受关注的领域之一&#xff0c;它涉及计算机和人类语言之间的交互。NLP的应用范围非常广泛&#xff0c;包括机器翻译、语音识别、文本分类、情感分析等等。本文将介绍NLP的基本概念和入门知识&#xff0c;以帮助初学者…

一键安装k8s脚本

服务器配置 节点(华为云服务器)配置master 2vCPUs | 4GiB | s6.large.2 CentOS 7.8 64bit node1 2vCPUs | 8GiB | s6.large.4 CentOS 7.8 64bit node2 2vCPUs | 8GiB | s6.large.4 CentOS 7.8 64bit 1.master节点安装脚本&#xff1a;install_k8s_master.sh。 sh文件上传到…

Windows基于Docker安装Elasticsearch和 kibana笔记

Windows基于Docker安装Elasticsearch和 kibana笔记 一、Windows安装Docker1、Windows安装Docker要求2、Docker安装 二、基于Docker安装Elasticsearch1、安装Elasticsearch2、Elasticsearch的XPACK验证2.1、什么是Xpack2.2、Xpack相关安全配置介绍2.2.1、xpack.security.enabled…

系统分析师之系统测试与维护(十六)

目录 一、 测试与评审 1.1 测试类型 1.2 测试阶段 1.3 面向对象的测试 1.4 测试自动化 1.5 软件调试 1.6 软件评审 1.7 验收与确认 二、软件质量管理 2.1 软件过程改进-CMMI 2.2 软件开发环境与工具 三、系统运行与评价 3.1 系统转换计划 3.1.1 遗留系统演化策略…

C++——C/C++内存管理

0.关注博主有更多知识 C知识合集 目录 1.C/C内存分布 2.C内存管理方式 2.1new和delete操作内置类型 2.2new和delete对自定义类型操作 2.3new和delete一定要配套使用 2.4new和malloc对错误的处理方式 3.operator new和operator delete函数 3.1new和delete的实现原理 …

如何实现PLC为主站的开关量自组网无线通信?

本方案是基于Modbus RTU协议下实现的1主多从自组网无线通信形式&#xff0c;主站为S7-1200 PLC&#xff0c;DTD433H作为从站。DTD433H具备输入和输出开关量信号功能&#xff0c;信号传输方向由用户原系统主从设备所实现的功能决定。方案中采用无线开关量信号测控终端DTD433H与欧…

JAVA+SpringBoot框架+SaaS模式云HIS源码

HIS分系统&#xff08;HIS子系统&#xff09; 1、医院业务子系统功能 ▶门诊医生站主模块&#xff1a;包括门诊业务、家庭医生、公共卫生、医疗协同等子模块 &#xff08;1&#xff09;门诊业务功能简介&#xff1a; ①统计门诊收费明细、用药情况&#xff1b; ②可管理患…

UOS获取ROOT权限

UOS获取ROOT权限 1. 设置里可以看到开发者选项2. 设置里无法看到开发者选项 1. 设置里可以看到开发者选项 这个就按照网上的流程申请就好了 2. 设置里无法看到开发者选项 一般而言就是系统被修改过了&#xff0c;或者定制化了&#xff0c;可以通过下载一个uos的正常镜像来获…

维也纳国际酒店11家门店陆续开业,加速布局中高端酒店市场

2023年&#xff0c;中国旅游业迎来飞速复苏。据弗若斯特沙利文报告预计&#xff0c;2021至2025年&#xff0c;中高端连锁酒店将是整个酒店行业增长最快的细分市场。如何抓住市场复苏和行业增长双重机遇&#xff0c;成为酒店投资者和从业者面临的重要课题。 过去几年里&#xff…

基础语法——笔记一

一、基础语法 编码 源码文件以UTF-8编码&#xff0c;所有字符串都是Unicode字符串标识符 第一个字符必须是字母表中的字母或下划线_ 标识符的其他部分由字母、数字、下划线组成 标识符对大小写敏感python保留字&#xff08;关键字&#xff09; 不能用于任何标识符输出python标…

【Redis高级应用】多级缓存

文章目录 什么是多级缓存JVM进程缓存初识Caffeine实现JVM进程缓存需求实现 Lua语法入门初识LuaHelloWorld变量和循环Lua的数据类型声明变量循环 条件控制、函数函数条件控制案例 实现多级缓存安装OpenRestyOpenResty快速入门反向代理流程OpenResty监听请求编写item.lua 请求参数…

ES+Redis+MySQL,这个高可用架构设计太顶了

会员系统是一种基础系统&#xff0c;跟公司所有业务线的下单主流程密切相关。如果会员系统出故障&#xff0c;会导致用户无法下单&#xff0c;影响范围是全公司所有业务线。所以&#xff0c;会员系统必须保证高性能、高可用&#xff0c;提供稳定、高效的基础服务。 一、背景 二…

【最终截稿 | Springer 独立出版 | EI稳定检索】 2023年绿色建筑国际会议(ICoGB 2023)

会议简介 Brief Introduction 2023年绿色建筑国际会议(ICoGB 2023) 会议时间&#xff1a;2023年5月21日-23日 召开地点&#xff1a;瑞典斯德哥尔摩 大会官网&#xff1a;www.icogb.org ICoGB 2023将围绕“绿色建筑”的最新研究领域而展开&#xff0c;为研究人员、工程师、专家学…

进程(一)

进程&#xff08;一&#xff09; 2.1 进程的定义、组成、组织方式、特征2.1.1 定义2.1.2 组成2.1.3 组织方式2.1.4 特征2.1.5 本小节总结 2.2 进程的状态与转换2.2.1 进程的状态2.2.3 进程状态的转换2.2.4 本小节总结 2.3 进程控制2.3.1 基本概念2.3.2 进程控制相关的原语2.3.3…

BetaFlight Mark4之“妖怪”声音

BetaFlight Mark4之“妖怪”声音 1. 源由2. 分析3. 数据3.1 配置一3.1.1 “妖怪”声音 黑匣子分析 3.2 配置二3.2.1 仅配置调整&#xff08;其他不变&#xff09;3.2.2 配置调整 整体螺丝锁紧 4. 总结5. 附录5.1 Betaflight filter tuning. The easy way to get a perfect fil…

防雷接地网施工综合方案

防雷接地网是一种用于防止雷击的重要设施&#xff0c;其主要作用是将雷电击中建筑物或设备后的电流引入地下&#xff0c;以保护人员和设备的安全。防雷接地网的施工方案是非常重要的&#xff0c;它直接关系到工程质量和安全。 防雷接地网的施工方案需要考虑很多因素&#xff0…