IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> JUC并发编程-Lock锁 -> 正文阅读

[数据结构与算法]JUC并发编程-Lock锁

Lock详解

简介

java.util.concurrent.locks包下常用的类与接口(lock是jdk 1.5后新增的)

LockReadWriteLock两大锁的根接口

  • Lock代表实现类是ReentrantLock可重入锁
  • ReadWriteLock(读写锁)的代表实现类是ReentrantReadWriteLock

img

同步实现原理

lock只能被一个线程获取,当一个线程执行lock.lock()后其他线程再尝试获取会进入lock对象中的等待队列,从而达到同步效果,ReenTrantLock的实现是一种自旋锁,通过循环调用CAS操作来实现加锁。它的性能比较好也是因为避免了使线程进入内核态的阻塞状态。

img

  • lock的存储结构:一个int类型状态值(用于锁的状态变更),一个双向链表(用于存储等待中的线程)
  • lock获取锁的过程:本质上是通过CAS(两次)来修改锁状态值,如果当场没获取到,会将该线程放在线程等待链表中自旋+CAS尝试获取锁。应该不是所有线程都自旋吧???(只有head才会自旋尝试加锁,并且自旋执行也不是无限自旋,对于head节点来说只会尝试3次获取锁为什么,而对于非head节点来说只会尝试获取一次为什么,获取失败则lcoksupport.park ,而CAS仅仅是针对尝试获取锁
  • lock释放锁的过程:CAS修改状态值,调整等待链表。因为无竞争所以没有使用CAS。

Lock接口实现类的使用

Lock接口有6个方法:

// 获取锁  
void lock()   

// 释放锁  
void unlock()  

// 如果当前线程未被中断,则获取锁,可以响应中断  
void lockInterruptibly()   

// 返回绑定到此 Lock 实例的新 Condition 实例  
Condition newCondition()   

// 仅在调用时锁为空闲状态才获取该锁,可以响应中断  
boolean tryLock()   

// 如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁  
boolean tryLock(long time, TimeUnit unit)   

获取释放锁

Lock lock=new ReentrantLock();
lock.lock();
try{
    //处理任务
}catch(Exception ex){
     
}finally{
    lock.unlock();   //释放锁
}

Synchronized与Lock

构成

synchronized是关键字属于JVM层面

  • monitorenter(底层通过monitor对象来完成,其实wait/notify等方法也依赖于monitor对象只有在同步块或方法中调用wait/notify等方法)
  • monitorexit

Lock是具体类(java.util.concurrent.Locks.lock)是api层面的锁

使用方法
  • synchronized 不需要手动释放锁,当synchronized代码执行完后系统会自动让线程释放对锁的占用
  • ReentrantLock需要手动释放锁若没有主动释放锁,就有可能导致出现死锁现象。需要Lock()和unlock()方法配合try/finally语句块来完成
等待是否可中断
  • synchronized不可中断,除非抛出异常或者正常运行完成
  • ReentrantLock 可中断
    • 设置超时方法tryLock(long timeout,TimeUnit unit)
    • lockInterruptibly()放代码块中,调用interrupt()方法可中断
加锁是否公平
  • synchronized非公平锁
  • ReentrantLock两者都可以,默认非公平锁,构造方法可以传入boolean值,true为公平锁,false为非公平锁
锁绑定多个条件Condition
  • synchronized没有,要么随机唤醒一个线程要么唤醒全部线程
  • ReentrantLock用来实现分组唤醒需要的线程们,可以实现精确唤醒

synchronized的缺陷

  • 效率低:锁的释放情况少,只有代码执行完毕或者异常结束才会释放锁;试图获取锁的时候不能设定超时,不能中断一个正在使用锁的线程,相对而言,Lock可以中断和设置超时
  • 不够灵活:加锁和释放的时机单一,每个锁仅有一个单一的条件(某个对象),相对而言,读写锁更加灵活
  • 无法知道是否成功获得锁,相对而言,Lock可以拿到状态,如果成功获取锁,…,如果获取失败,…

Lock解决相应问题

Lock类这里不做过多解释,主要看里面的4个方法:

  • lock(): 加锁
  • unlock(): 解锁
  • tryLock(): 尝试获取锁,返回一个boolean值
  • tryLock(long,TimeUtil): 尝试获取锁,可以设置超时

Synchronized只有锁只与一个条件(是否获取锁)相关联,不灵活,后来Condition与Lock的结合解决了这个问题。

多线程竞争一个锁时,其余未得到锁的线程只能不停的尝试获得锁,而不能中断。高并发的情况下会导致性能下降。ReentrantLock的lockInterruptibly()方法可以优先考虑响应中断。 一个线程等待时间过长,它可以中断自己,然后ReentrantLock响应这个中断,不再让这个线程继续等待。有了这个机制,使用ReentrantLock时就不会像synchronized那样产生死锁了。

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-01-28 12:10:13  更:2022-01-28 12:12:49 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 19:39:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码