锁( ReentrantLock,Synchronized)

1.lock和synchronized

  • 语法层面

synchronized 是关键字,源码在 jvm 中,用 c++ 语言实现;

Lock 是接口,源码由 jdk 提供,用 java 语言实现;

使用 synchronized 时,退出同步代码块锁会自动释放,而使用 Lock 时,需要手动调用 unlock 方法释放锁

  • 功能层面

二者均属于悲观锁、都具备基本的互斥、同步、锁重入功能;

Lock 提供了许多 synchronized 不具备的功能,例如公平锁、可打断、可超时、多条件变量

Lock 有适合不同场景的实现,如 ReentrantLock, ReentrantReadWriteLock(读写锁)

  • 性能层面

在没有竞争时,synchronized 做了很多优化,如偏向锁、轻量级锁,性能不赖

在竞争激烈时,Lock 的实现通常会提供更好的性能

2.ReentrantLock的代码实现

对于ReentrantLock来说,它既可以使用乐观锁思想,也可以使用悲观锁思想,具体取决于如何使用它的不同方法。

  1. 悲观锁思想: 在使用ReentrantLock时,可以使用它的lock()和unlock()方法来实现悲观锁思想。在使用lock()方法获取锁之前,它会一直等待直到获取到锁,如果其他线程已经持有锁,则当前线程会被阻塞。这种方式与传统的悲观锁思想相似,它假设并发访问会导致冲突,因此在访问共享资源之前先获取锁。

示例代码:

ReentrantLock lock = new ReentrantLock();
​
lock.lock(); // 获取锁
try {// 访问共享资源
} finally {lock.unlock(); // 释放锁
}
  1. 乐观锁思想: 在使用ReentrantLock时,可以使用它的tryLock()方法来实现乐观锁思想。tryLock()方法尝试获取锁,如果获取成功则返回true,否则返回false,不会一直等待。这种方式与乐观锁思想相似,它假设并发访问不会导致冲突,因此直接进行操作而不获取锁。

示例代码:

ReentrantLock lock = new ReentrantLock();
​
if (lock.tryLock()) { // 尝试获取锁try {// 访问共享资源} finally {lock.unlock(); // 释放锁}
} else {// 锁被其他线程持有,处理逻辑
}

需要注意的是,ReentrantLock的乐观锁思想并不是基于CAS机制实现的,而是基于AQS(AbstractQueuedSynchronizer)实现的。因此,它的乐观锁并不是真正意义上的无锁操作,而是一种基于线程等待/唤醒机制的乐观策略。

3.ReentrantLock构造原理

ReentrantLock主要利用CAS+AQS队列来实现。它支持公平锁和非公平锁,两者的实现类似

构造方法接受一个可选的公平参数(默认非公平锁),当设置为true时,表示公平锁,否则为非公平锁。公平锁的效率往往没有非公平锁的效率高,在许多线程访问的情况下,公平锁表现出较低的吞吐量。

拓展延申

1)AQS

关键时FIFO双向队列和属性state

  • 是多线程中的队列同步器。是一种锁机制,它是做为一个基础框架使用的,像ReentrantLock、Semaphore都是基于AQS实现的

  • AQS内部维护了一个先进先出的双向队列,队列中存储的排队的线程

  • 在AQS内部还有一个属性state,这个state就相当于是一个资源,默认是0(无锁状态),如果队列中的有一个线程修改成功了state为1,则当前线程就相等于获取了资源

  • 在对state修改的时候使用的cas操作,保证多个线程修改的情况下原子性

2)了解AQS与Synchronized的区别

3)CAS

CAS的全称是: Compare And Swap(比较再交换),它体现的一种乐观锁的思想,在无锁情况下保证线程操作共享数据的原子性。

4)乐观锁与悲观锁

CAS 是基于乐观锁的思想:最乐观的估计,不怕别的线程来修改共享变量,就算改了也没关系,我吃亏点再重试呗。

synchronized 是基于悲观锁的思想:最悲观的估计,得防着其它线程来修改共享变量,我上了锁你们都别想改,我改完了解开锁,你们才有机会。

在Java中,synchronized关键字ReentrantLock类都是悲观锁的实现。

在Java中,Atomic类和CAS(Compare and Swap)机制都是乐观锁的实现。

4.Java中synchronized的代码实例

下面是Java中使用synchronized关键字的几种代码示例:

  1. 同步方法:

public synchronized void synchronizedMethod() {// 同步的代码块
}
  1. 同步代码块:

public void synchronizedBlock() {synchronized (this) {// 同步的代码块}
}
  1. 静态同步方法:

public static synchronized void synchronizedStaticMethod() {// 同步的代码块
}
  1. 同步对象锁:

public class MyClass {private final Object lock = new Object();
​public void synchronizedObjectLock() {synchronized (lock) {// 同步的代码块}}
}

在上述示例中,使用synchronized关键字修饰的方法或代码块被称为同步方法或同步代码块,它们保证了同一时刻只能有一个线程访问被同步的代码块。synchronized关键字可以修饰方法、代码块、静态方法,以及指定的对象锁。

当一个线程进入到一个被synchronized修饰的方法或代码块时,它会尝试获取对象的锁。如果锁没有被其他线程占用,则该线程获取到锁并执行同步代码块;如果锁已经被其他线程占用,则该线程会进入阻塞状态,直到锁被释放。

需要注意的是,synchronized关键字是可重入的,即一个线程可以多次获取同一个锁。当一个线程已经获取到锁时,它可以再次进入被同步修饰的方法或代码块,而不会被阻塞。这种机制可以避免死锁的发生。

另外,synchronized关键字还可以用于实现线程之间的通信,通过wait()、notify()和notifyAll()方法来实现线程的等待和唤醒操作。这些方法必须在synchronized修饰的代码块中调用,并且是针对同一个对象锁的操作。

5.说一下无锁操作?

无锁操作是指在并发编程中,通过使用特定的算法和数据结构,避免使用传统的锁机制(如互斥锁、读写锁等),从而实现对共享资源的并发访问而无需阻塞或等待其他线程释放锁的操作。

无锁操作通常基于原子操作和CAS(Compare and Swap)机制来实现。CAS是一种乐观锁思想的实现方式,它通过比较内存中的值与期望值,如果相等则更新为新值,否则不做任何操作。CAS操作是原子性的,可以保证在多线程环境下的一致性。

无锁操作的优点包括:

  1. 减少线程的阻塞和切换开销:无锁操作不需要等待其他线程释放锁,避免了线程的阻塞和切换开销,提高了系统的并发性能。

  2. 避免死锁和饥饿问题:无锁操作不涉及锁的竞争和资源的争夺,可以避免死锁和饥饿问题。

  3. 提高系统的可伸缩性:无锁操作可以实现更细粒度的并发控制,提高系统的可伸缩性。

然而,无锁操作也存在一些挑战和限制:

  1. 实现复杂度高:无锁操作需要使用特定的算法和数据结构,实现起来较为复杂。

  2. 适用场景有限:无锁操作适用于对共享资源的读操作频繁,写操作较少的场景,对于复杂的写操作,仍然需要使用锁来保证操作的原子性

  3. ABA问题:由于无锁操作不需要获取锁,可能会导致ABA问题,即一个值被修改为另一个值,然后再被修改回原来的值,导致线程无法察觉到值的变化。

总之,无锁操作是一种高效的并发编程方式,可以提高系统的并发性能和可伸缩性,但需要根据具体场景和需求来选择合适的并发控制策略。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java 复习笔记 - 学生管理系统篇

文章目录 学生管理系统一,需求部分需求分析初始菜单学生类添加功能删除功能修改功能查询功能 二,实现部分(一)初始化主界面(二)编写学生类(三)编写添加学生方法(四&#…

Nginx 配置中root和alias的区别分析

root和alias都可以定义在location模块中,都是用来指定请求资源的真实路径,比如: location /i/ { root /data/w3; } 请求 http://foofish.net/i/top.gif 这个地址时,那么在服务器里面对应的真正的资源 是 /data/w3/i/top.gif文…

2023年03月 C/C++(七级)真题解析#中国电子学会#全国青少年软件编程等级考试

C/C编程(1~8级)全部真题・点这里 第1题:走出迷宫 当你站在一个迷宫里的时候,往往会被错综复杂的道路弄得失去方向感,如果你能得到迷宫地图,事情就会变得非常简单。 假设你已经得到了一个n*m的迷宫的图纸&a…

移动零00

题目链接 移动零 题目描述 注意点 将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序必须在不复制数组的情况下原地对数组进行操作 解答思路 采用双指针的思路,左指针指向已移动零的数组的尾部,右指针指向为移动零的数组的头部&…

Android-关于页面卡顿的排查工具与监测方案

作者:一碗清汤面 前言 关于卡顿这件事已经是老生常谈了,卡顿对于用户来说是敏感的,容易被用户直接感受到的。那么究其原因,卡顿该如何定义,对于卡顿的发生该如何排查问题,当线上用户卡顿时,在线…

宝塔面板一键部署Z-Blog博客 - 内网穿透实现公网访问

文章目录 1.前言2.网站搭建2.1. 网页下载和安装2.2.网页测试2.3.cpolar的安装和注册 3.本地网页发布3.1.Cpolar临时数据隧道3.2.Cpolar稳定隧道(云端设置)3.3.Cpolar稳定隧道(本地设置) 4.公网访问测试5.结语 1.前言 Ubuntu系统作…

ceph源码阅读 erasure-code

1、ceph纠删码 纠删码(Erasure Code)是比较流行的数据冗余的存储方法,将原始数据分成k个数据块(data chunk),通过k个数据块计算出m个校验块(coding chunk)。把nkm个数据块保存在不同的节点,通过n中的任意k个块还原出原始数据。EC包含编码和解…

SpringMVC使用

文章目录 一.MVC基础概念1.MVC定义2.SpringMVC和MVC的关系 二.SpringMVC的使用1.RequestMapping2.获取参数1.获取单个参数2.传递对象3.后端参数重命名(后端参数映射)4.获取URL中参数PathVariable5.上传文件RequestPart6.获取Cookie/Session/header 3.返回…

Flink+Paimon多流拼接性能优化实战

目录 (零)本文简介 意外收获: (一)背景 (二)探索梳理过程 (三)源码改造 (四)修改效果 1、JOB状态 2、Level5的dataFile总大小 3、数据延…

企业网络安全:威胁情报解决方案

什么是威胁情报 威胁情报是网络安全的关键组成部分,可为潜在的恶意来源提供有价值的见解,这些知识可帮助组织主动识别和防止网络攻击,通过利用 STIX/TAXII 等威胁源,组织可以检测其网络中的潜在攻击,从而促进快速检测…

OJ练习第160题——LRU 缓存

LRU 缓存 力扣链接:146. LRU 缓存 题目描述 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类: LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存 int get(int key) 如果关键字 key 存在于缓…

用迅为RK3568开发板使用OpenCV处理图像颜色通道提取ROI

本小节代码在配套资料“iTOP-3568 开发板\03_【iTOP-RK3568 开发板】指南教程 \04_OpenCV 开发配套资料\07”目录下,如下图所示: 在计算机的色彩图像中存有三个通道,即 BGR 通道,根据三个颜色通道的亮度值来显示出不同的颜色&…