JAVA每日面经——并发编程(一)必看

👩🏽‍💻个人主页:阿木木AEcru

🔥 系列专栏:《Docker容器化部署系列》 《Java每日面筋》

💹每一次技术突破,都是对自我能力的挑战和超越。

目录

    • 一、并发编程之AQS
    • 二、并发编程之CAS
    • 三、java中常用的锁有哪些?
      • 1. Synchronized锁
      • 2. ReentrantLock锁
      • 3. ReadWriteLock读写锁
    • 四、结尾

在这里插入图片描述

一、并发编程之AQS

AQS(AbstractQueuedSynchronizer)是 Java 并发编程中的一个重要组件,作为多线程同步器,它在 Java 并发包(java.util.concurrent)多个组件的底层实现。如 Lock、CountDownLatch、Semaphore 等都用到了它。

在 AQS 的设计中,它主要提供了两种锁机制:排它锁和共享锁。

  • 排它锁(Exclusive Lock):也称为独占锁,它确保在同一时刻只有一个线程可以访问共享资源。这意味着当多个线程竞争同一资源时,只有一个线程能够获得锁,并且其他线程必须等待。比如,ReentrantLock 中的重入锁就是排它锁的一种实现,它利用 AQS 实现了这种独占的锁机制。
  • 共享锁(Shared Lock):也称为读锁,它允许多个线程同时访问共享资源,从而提高了并发性。多个线程可以同时获得锁资源,这在某些场景下是非常有用的。比如,CountDownLatch 和 Semaphore 就是利用 AQS 中的共享锁实现的。

它主要由以下几个组成部分构成:

  1. 节点(Node): 用于封装等待获取同步状态的线程。每个节点都包含了线程的引用和状态信息,以双向链表的形式组织在一起,构成等待队列。
  2. 状态(State): 表示共享资源的状态,可以是任意的整数值,代表不同的含义,比如锁的状态或信号量的剩余资源数量。
  3. 等待队列(Wait Queue): 存放等待获取同步状态的线程节点的双向链表。
  4. 同步器方法(Sync Methods): 定义了 AQS 的抽象方法,子类通过实现这些方法来控制同步状态的获取和释放行为,比如tryAcquire()、tryRelease()等。
  5. 条件对象(Condition): 支持精确线程等待和通知机制,用于在满足特定条件之前等待,并在条件满足时被唤醒。
    下面的cas它也有用到,继续往下看吧。

二、并发编程之CAS

CAS(Compare and Swap)它的全称是 CompareAndSwap,比较并交换的意思。它的主要功能是能够保证在多线程环境下,对于共享变量的修改的原子性。CAS 主要用在并发场景中,比较典型的使用场景有两个。

  • 第一个是 J.U.C 里面 Atomic 的原子实现,比如 AtomicInteger,AtomicLong。
  • 第二个是实现多线程对共享资源竞争的互斥性质,比如在 AQS、 ConcurrentHashMap、ConcurrentLinkedQueue 等都有用到。

而CAS操作包含三个操作数:内存地址(或变量)、期望值和新值。其主要逻辑如下:

  1. 比较内存地址处的值和期望值是否相等。
  2. 如果相等,则将内存地址处的值更新为新值。
  3. 如果不相等,则不做任何操作。

CAS通常用于实现一些基本的同步原语,如自旋锁、乐观锁等。相比synchronized来说,CAS具有更低的开销,因为它避免了线程的阻塞和唤醒操作,而是通过轮询的方式来实现同步。
在这里插入图片描述
而平时在做一些业务时,也是可以参考这一块逻辑作为一个乐观锁的实现。例如最简单的就是在mysql中加一个版本号 version,在更新这一条数据之前,先查询这条旧数据,获取到当前版本号,再更新的时候,将旧的版本号作为条件( where version = 获取到的版本号 ),更新的时候加上(set version = version+1) , 只要修改的行数大于1则证明修改成功,如果修改失败的话,可以进行一个轮询重试,间隔由你自己把控,直到更新成功为止。

UPDATE <表名> SET column1 = 'new_value', version = version + 1 WHERE id = <通过id修改> AND version = <旧版本号>;

三、java中常用的锁有哪些?

在这里插入图片描述
常用的锁机制包括Synchronized锁、ReentrantLock锁和ReadWriteLock读写锁。下面分别介绍这三种锁。

1. Synchronized锁

Synchronized是Java中最基本的锁机制之一,通过对代码块或方法添加synchronized关键字来实现同步。Synchronized锁是一种悲观锁,它会在进入代码块之前获取锁,并在退出代码块时释放锁。

示例代码:


import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * SynchronizedExample示例演示了使用Synchronized关键字实现对共享资源的并发访问控制。
 */
public class SynchronizedExample {
    private int count = 0; // 共享资源计数器

    /**
     * 同步方法increment,通过synchronized关键字实现对共享资源的加锁。
     * 每次调用该方法时,只允许一个线程进入,确保对count变量的操作是原子性的。
     */
    public synchronized void increment() {
        count++; // 增加计数器的值
    }

    /**
     * 同步代码块incrementSyncBlock,通过对this对象进行加锁实现对共享资源的保护。
     * 与同步方法相比,同步代码块可以更灵活地控制锁的范围,避免不必要的锁竞争。
     */
    public void incrementSyncBlock() {
        synchronized (this) {
            count++; // 增加计数器的值
        }
    }

    /**
     * 获取计数器的当前值。
     *
     * @return 计数器的当前值
     */
    public int getCount() {
        return count; // 返回计数器的值
    }

    public static void main(String[] args) {
        SynchronizedExample example = new SynchronizedExample();
        ExecutorService executor = Executors.newCachedThreadPool();

        // 创建多个线程并发执行increment操作
        for (int i = 0; i < 5; i++) {
            executor.execute(() -> {
                for (int j = 0; j < 100; j++) {
                    example.increment(); // 调用increment方法增加计数器的值
                }
            });
        }

        // 关闭线程池
        executor.shutdown();

        // 等待所有线程执行完毕
        while (!executor.isTerminated()) {
        }

        // 输出最终的计数器值
        System.out.println("结果: " + example.getCount());
    }
}

创建了一个线程池ExecutorService来执行多个线程并发调用increment方法,每个线程循环执行100次。通过ExecutorService的shutdown方法关闭线程池,并通过isTerminated方法等待所有线程执行完毕。

2. ReentrantLock锁

ReentrantLock是Java.util.concurrent包中提供的锁机制,它提供了与Synchronized锁类似的功能,但具有更灵活的锁获取和释放方式。ReentrantLock锁是一种可重入锁,允许同一个线程多次获取同一把锁。

示例代码:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockExample {
    private int count = 0;
    private final Lock lock = new ReentrantLock(); // 创建一个可重入锁实例

    public void increment() {
        lock.lock(); // 获取锁
        try {
            count++; // 增加计数器的值
        } finally {
            lock.unlock(); // 释放锁
        }
    }

    public int getCount() {
        lock.lock(); // 获取锁
        try {
            return count; // 返回计数器的值
        } finally {
            lock.unlock(); // 释放锁
        }
    }

    public static void main(String[] args) {
        LockExample example = new LockExample();

        // 创建多个线程并发执行increment操作
        for (int i = 0; i < 5; i++) {
            Thread thread = new Thread(() -> {
                for (int j = 0; j < 100; j++) {
                    example.increment(); // 调用increment方法增加计数器的值
                }
            });
            thread.start(); // 启动线程
        }

        // 等待所有线程执行完毕
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 输出最终的计数器值
        System.out.println("结果: " + example.getCount());
    }
}

通过使用ReentrantLock实现了对计数器的并发访问控制。在increment和getCount方法中,通过lock和unlock方法实现了对共享资源的加锁和解锁操作,确保了线程安全性。同时,在main方法中创建了多个线程并发执行increment操作,通过输出最终的计数器值验证了线程安全性。

3. ReadWriteLock读写锁

ReadWriteLock是一种特殊的锁机制,它将锁分为读锁和写锁两种类型,允许多个线程同时获取读锁,但只允许一个线程获取写锁。读写锁适用于读操作频繁、写操作较少的场景,可以提高并发读取的效率。

示例代码:

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockExample {
    private int count = 0;
    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();

    public void increment() {
        rwLock.writeLock().lock(); // 获取写锁
        try {
            count++; // 增加计数器的值
            System.out.println("递增至: " + count);
        } finally {
            rwLock.writeLock().unlock(); // 释放写锁
        }
    }

    public int getCount() {
        rwLock.readLock().lock(); // 获取读锁
        try {
            System.out.println("当前值: " + count);
            return count; // 返回计数器的值
        } finally {
            rwLock.readLock().unlock(); // 释放读锁
        }
    }

    public static void main(String[] args) {
        ReadWriteLockExample example = new ReadWriteLockExample();

        // 创建多个线程并发执行increment操作
        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                example.increment(); // 调用increment方法增加计数器的值
            }).start();
        }

        // 创建多个线程并发执行getCount操作
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                example.getCount(); // 调用getCount方法获取计数器的值
            }).start();
        }
    }
}

在这里创建了一个ReadWriteLockExample类,其中包含increment和getCount两个方法,分别用于增加计数器的值和获取计数器的值。在main方法中创建了多个线程并发执行这两个操作,并通过输出来观察读写锁的效果。

四、结尾

感谢您的观看! 如果本文对您有帮助,麻烦用您发财的小手点个三连吧!您的支持就是作者前进的最大动力!再次感谢!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

广东省30m二级分类土地利用数据(矢量)

广东省&#xff0c;地处中国大陆最南部&#xff0c;属于东亚季风区&#xff0c;从北向南分别为中亚热带、南亚热带和热带气候&#xff0c;是中国光、热和水资源最丰富的地区之一。主要河系为珠江的西江、东江、北江和三角洲水系以及韩江水系。广东省面积为17.977万平方公里&…

【python + Django】Django模板语法 + 请求和响应

前言&#xff1a; 现在现在&#xff0c;我们要开始将变量的值展现在页面上面啦&#xff01; 要是只会显示静态页面&#xff0c;我们的页面也太难看和死板了&#xff0c; 并且数据库的数据也没法展现在页面上。 但是呢&#xff0c;模板语法学习之后就可以啦&#xff01;&…

Halcon 3D 平面拟合(区域采样、Z值过滤、平面拟合、平面移动)

Halcon 3D 平面拟合(区域采样、Z值过滤、平面拟合、平面移动) 链接:https://pan.baidu.com/s/1UfFyZ6y-EFq9jy0T_DTJGA 提取码:ewdi * 1.读取图片 ****************

政安晨:【深度学习实践】【使用 TensorFlow 和 Keras 为结构化数据构建和训练神经网络】(二)—— 深度神经网络

政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: 政安晨的机器学习笔记 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff01; 概述 深度神经网络&#xff08;Deep Neural Network&…

24北京教资认定明日开始,请提前准备证件照

24北京教资认定明日开始&#xff0c;请提前准备证件照哦&#xff01;

KEY ENERGY欧洲意大利能源光伏储能展

3月1号第18届意大利里米尼国际可再生能源展&#xff08;KEY ENERGY&#xff09;由知名主办方ITALIAN EXHIBITION GROUP S.P.A组织举办&#xff0c;每年一届&#xff0c;是欧洲第二大能源展&#xff0c;也是覆盖范围最全知名度最高的可再生能源展览会。 该展会将于2024扩大规模…

EL表达式

一、什么是EL EL&#xff08;Expression Language&#xff09;表达式语言 由两个开发团队共同开发 JSP 标准标签库专家组 JSP 2.0 专家组 EL表达式语言的语法 ${Expression} JSP EL 表达式用于以下情形 在JSP页面中输出静态内容 为标准标签和自定义标签提供属性值 二、作用&am…

排序算法之选择排序介绍

目录 算法简介 算法描述 代码实现 算法简介 选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理&#xff1a;首先在未排序序列中找到最小&#xff08;大&#xff09;元素&#xff0c;存放到排序序列的起始位置&#xff0c;然后&#xff0c;再从剩余未排序元素…

解析服务器出现大量 TIME_WAIT 和 CLOSE_WAIT 状态的原因及排查方法

服务器出现大量 TIME_WAIT 状态的原因有哪些&#xff1f; 首先要知道 TIME_WAIT 状态是主动关闭连接方才会出现的状态&#xff08;别陷入一个误区不是只有客户端才能主动关闭连接的&#xff09;&#xff0c;所以如果服务器出现大量的 TIME_WAIT 状态的 TCP 连接&#xff0c;就是…

MongoDB系列之查询计划

概述 一个查询具体如何被执行的过程&#xff0c;称为查询计划。MongoDB采用自底向上的方式来构造查询计划&#xff0c;每一个查询计划&#xff08;query plan&#xff09;都会被分解为若干个有层次的阶段&#xff08;stage&#xff09;。整个查询计划最终会呈现出一颗多叉树。…

3个Tips,用“AI”开启新生活

相信最近&#xff0c;很多朋友们都回归到了忙碌的生活节奏中。生活模式的切换&#xff0c;或多或少会带来身体或情绪状况的起伏。新技术正在为人们生活的方方面面带来便利。3个小Tips或许能让你也从新技术中获益&#xff0c;从身到心&#xff0c;用“AI”开启新生活。 关”A…

【机器学习】基于正余弦搜索算法优化的BP神经网络分类预测(SCA-BP)

目录 1.原理与思路2.设计与实现3.结果预测4.代码获取 1.原理与思路 【智能算法应用】智能算法优化BP神经网络思路【智能算法】正余弦优化算法&#xff08;SCA&#xff09;原理及实现 2.设计与实现 数据集&#xff1a; 多输入多输出&#xff1a;样本特征24&#xff0c;标签类…

基于深度学习的面部情绪识别算法仿真与分析

声明&#xff1a;以下内容均属于本人本科论文内容&#xff0c;禁止盗用&#xff0c;否则将追究相关责任 基于深度学习的面部情绪识别算法仿真与分析 摘要结果分析1、本次设计通过网络爬虫技术获取了七种面部情绪图片&#xff1a;吃惊、恐惧、厌恶、高兴、伤心、愤怒、自然各若…

Python Qt Designer 初探

代码下载在最下面 #开发环境安装# 本示例在Windows11下, 使用VSCode开发, Python 3.12.2, Qt Designer 5.11 VSCode插件Python、Python Debugger、PYQT Integration、Pylance (准备) VSCode自行官网下载 Visual Studio Code - Code Editing. Redefined (准备) Python 直接…

腾讯和香港中文大学发布文字生成视频AI模型DynamiCrafter

前言 在数字化时代&#xff0c;视觉内容的创造和动态化已成为创意表达和信息传递的重要工具。最近由香港中文大学、腾讯AI Lab联合研发的视频AI模型DynamiCrafter&#xff0c;这一模型能够将静态图像转化为逼真的动态视频&#xff0c;开创了文本到视频生成技术的新纪元。 Hugg…

matlab 将矩阵写入文件

目录 一、概述1、算法概述2、主要函数二、将矩阵写入到文本文件三、将矩阵写入电子表格文件四、将矩阵写入指定的工作表和范围五、将数据追加到电子表格六、将矩阵数据追加到文本文件七、参考链接本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此…

Go微服务实战——服务的监控与链路追踪(监控数据可视化)

链路追踪背景 对于早期系统或者服务来说&#xff0c;开发人员一般通过打日志的方式来进行埋点&#xff08;常用的数据采集方式&#xff09;&#xff0c;然后再根据日志系统和性能监控定位及分析问题。对于单体的应用通过日志系统完全可以定位到问题&#xff0c;从而排查异常。…

MySQL B+树索引 和 Redis 中跳表索引的区别

一、MySQL B树索引 和 Redis 中跳表索引 在 MySQL 中常用的索引是 B树索引&#xff0c;而 Redis 中&#xff0c;例如 zset 使用的的是跳表索引&#xff0c;两者有什么区别呢&#xff0c;MySQL 为什么不使用 跳表 呢&#xff1f;或者说 Redis 中为什么不使用 B树 呢&#xff1f…

【Flutter 面试题】Flutter如何进行本地存储和缓存数据?

【Flutter 面试题】Flutter如何进行本地存储和缓存数据&#xff1f; 文章目录 写在前面口述回答补充说明实际案例完整代码示例运行结果详细说明 写在前面 &#x1f64b; 关于我 &#xff0c;小雨青年 &#x1f449; CSDN博客专家&#xff0c;GitChat专栏作者&#xff0c;阿里云…

分布式之Skywalking

Skywalking skywalking是一个apm系统&#xff0c;包含监控&#xff0c;追踪&#xff0c;并拥有故障诊断能力的 分布式系统 一、Skywalking介绍 1.什么是SkyWalking Skywalking是由国内开源爱好者吴晟开源并提交到Apache孵化器的产品&#xff0c;它同时吸收了Zipkin /Pinpoint …