带你了解JAVA中的一些锁概念
目录
- 乐观锁和悲观锁
- 读写锁
- 重量解锁和轻量级锁
- 自旋锁
- 公平锁和非公平锁
- 可重入锁和不可重入锁
- 死锁
- CAS(compare and swap)比较并交换
- synchronized的锁升级过程
- 总结
乐观锁和悲观锁
乐观锁:这个锁认为出现锁竞争的概率比较低(当前线程中,线程数量较少,不太涉及竞争,就偶尔竞争一下)
悲观锁:这个所认为出现锁竞争的概率比较大(当前场景中,线程数目比较多,可能涉及竞争)
读写锁
普通的锁提供两个操作:加锁,解锁
读写锁提供三个操作:读加锁,写加锁,解锁。
读加锁和读加锁:不需要互斥
写加锁和写加锁之间:需要互斥
读加锁和写加锁之间:需要互斥
主要适用于读多写少的场景
重量解锁和轻量级锁
从工作量来区分:
重量级锁,工作量更多,消耗资源更多,锁更慢
轻量级锁,工作量更少,消耗资源少,锁更快
操作系统中的mutex就是一个重量级锁(也是悲观锁),这个锁在加锁的时候就会遇到冲突,就会产生内核态和用户态的切换,以及线程的调度和阻塞。
自旋锁
在加锁的时候遇到冲突,不会涉及到用户态和内核态的切换,直接尝试重新获取锁。
会一直在循环中尝试获取锁,直到获取成功,这个过程中没有放弃cpu,不涉及线程调度。
公平锁和非公平锁
什么叫公平?
就是先来先服务。
如果不是按照先来后到的方式获取锁,就是非公平锁。
可重入锁和不可重入锁
一个线程对于相同的一把锁连续加锁两次。
对于不可重入锁:就会有问题
对于可重入锁:可以充入
例如:我们常用的synchronized就是可重入锁
因为synchronized的底层有一个计数器,当你对同一个对象连续加锁几次后,它的计数器就会加几次,解锁的时候,计数器就会–。
死锁
当产生死锁之后,就无法继续往下工作了(严重BUG)
死锁产生的原因:产生环路等待。
死锁的危害:线程无法继续工作。
避免死锁:1.不要在加锁的代码中在尝试获取其他锁;2.约定一定的顺序获取其他锁。
CAS(compare and swap)比较并交换
java中AtomicInteger中的自增方法就可以看出来,如果Var1对象中的值和var2是相等的,就可以将var1的值更新。如果不是,就会一直自旋。
随着CAS的出现就会有ABA问题
什么是ABA问题呢?
举个栗子:ABA问题就是你买了个新手机你不知道这个手机是新机还是翻新机。
画个抽象一点图在解释一下:
那怎么解决ABA问题呢?
答案是加个版本号!!!
synchronized的锁升级过程
具体逻辑是这样的:
无锁状态-偏向锁-轻量级锁-重量级锁
第一个线程加锁的时候,并不是真正意义上的加锁,而是设置了一个标记位。
当第二个线程也来访问同一个变量的时候,第一个线程才是真正意义上的加锁,第二个线程也会加锁。这就从偏向锁转向了轻量级锁,随着相乘越来越多,因为轻量级锁内部是自旋锁,多个线程的情况下也不容易立马获取到锁,这时吃cup就越来越严重,慢慢的就转变成了重量级锁,此时没获取到锁的线程转变为内核态,进行阻塞。
总结
本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注我们的更多内容!
相关推荐
-
java基于mongodb实现分布式锁的示例代码
目录 原理 实现 使用 原理 通过线程安全findAndModify 实现锁 实现 定义锁存储对象: /** * mongodb 分布式锁 */ @Data @NoArgsConstructor @AllArgsConstructor @Document(collection = "distributed-lock-doc") public class LockDocument { @Id private String id; private long expireAt; privat
-
深入理解Java显式锁的相关知识
目录 一.显式锁 二.Lock的常用api 三.Lock的标准用法 四.ReentrantLock(可重入锁) 五.ReentrantReadWriteLock(读写锁) 六.Condition 一.显式锁 什么是显式锁? 由自己手动获取锁,然后手动释放的锁. 有了 synchronized(内置锁) 为什么还要 Lock(显示锁)? 使用 synchronized 关键字实现了锁功能的,使用 synchronized 关键字将会隐式地获取锁,但是它将锁的获取和释放固化了,也就是先获取再释放.
-
Java检测死锁案例
导致死锁的程序 package com.study.train; import java.io.IOException; import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; import java.lang.reflect.Field; import java.util.*; import j
-
三道java新手入门面试题,通往自由的道路--锁+Volatile
目录 1. 你知道volatile是如何保证可见性吗? 小结: 2. 悲观锁和乐观锁可以讲下你的理解吗? 3. 你还知道什么其他的锁吗? 总结 1. 你知道volatile是如何保证可见性吗? 我们先看一组代码: public class VolatileVisibleDemo { public static boolean initFlag = false; public static void main(String[] args) { new Thread(new Runnable() {
-
Java基础之线程锁相关知识总结
一. synchronized关键字 1.对象锁 a.当使用对象锁的时候,注意要是相同的对象,并且当有线程正在访问对象锁内部的代码的时候,其他线程无法访问.(注意无法访问的范围). b.但是并不影响没有使用对象锁的部分的代码的运行. 对象锁分为两类一个叫做synchronized代码块(圆括号内是普通类的对象),另外一个是sybchronized修饰普通成员方法.它们二者其实可以通过this关键字进项转化. 2.类锁 a. 当使用类锁的时候,只要是同一个类的对象.当有线程正在访问类锁内部的代码的
-
带你了解JAVA中的一些锁概念
目录 乐观锁和悲观锁 读写锁 重量解锁和轻量级锁 自旋锁 公平锁和非公平锁 可重入锁和不可重入锁 死锁 CAS(compare and swap)比较并交换 synchronized的锁升级过程 总结 乐观锁和悲观锁 乐观锁:这个锁认为出现锁竞争的概率比较低(当前线程中,线程数量较少,不太涉及竞争,就偶尔竞争一下) 悲观锁:这个所认为出现锁竞争的概率比较大(当前场景中,线程数目比较多,可能涉及竞争) 读写锁 普通的锁提供两个操作:加锁,解锁 读写锁提供三个操作:读加锁,写加锁,解锁. 读加锁和读
-
一起聊聊Java中13种锁的实现方式
目录 1.悲观锁 2.乐观锁 3.分布式锁 加锁 4.可重入锁 5.自旋锁 6.独享锁 7.共享锁 8.读锁/写锁 9.公平锁/非公平锁 10.可中断锁/不可中断锁 11.分段锁 12.锁升级(无锁|偏向锁|轻量级锁|重量级锁) 无锁 偏向锁 轻量级锁 重量级锁 13.锁优化技术(锁粗化.锁消除) 最近有很多小伙伴给我留言,分布式系统时代,线程并发,资源抢占,"锁" 慢慢变得很重要.那么常见的锁都有哪些? 今天Tom哥就和大家简单聊聊这个话题. 1.悲观锁 正如其名,它是指对数据修改时
-
一篇文章轻松搞懂Java中的自旋锁
前言 锁作为并发共享数据,保证一致性的工具,在JAVA平台有多种实现(如 synchronized 和 ReentrantLock等等 ) .这些已经写好提供的锁为我们开发提供了便利. 在之前的文章<一文彻底搞懂面试中常问的各种"锁" >中介绍了Java中的各种"锁",可能对于不是很了解这些概念的同学来说会觉得有点绕,所以我决定拆分出来,逐步详细的介绍一下这些锁的来龙去脉,那么这篇文章就先来会一会"自旋锁". 正文 出现原因 在我们的
-
带你了解Java中的异常处理(下)
今天继续讲解java中的异常处理机制,主要介绍Exception家族的主要成员,自定义异常,以及异常处理的正确姿势. Exception家族 一图胜千言,先来看一张图. Exception这是一个父类,它有两个儿子,IOException和RuntimeException,每个儿子都很能生,所以它有着一堆的孙子,但其实,Exception家族还有一个大家伙,那就是Throwable,这是一个接口,看名字就知道意思,就是"可被抛出"嘛,它还有一个同父异母的哥哥,那就是Error,这家伙可
-
Java中的悲观锁与乐观锁是什么
乐观锁对应于生活中乐观的人总是想着事情往好的方向发展,悲观锁对应于生活中悲观的人总是想着事情往坏的方向发展.这两种人各有优缺点,不能不以场景而定说一种人好于另外一种人. 悲观锁 总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程).传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁.Java中sy
-
带你了解Java中的异常处理(上)
当当当当当当,各位看官,好久不见,甚是想念. 今天我们来聊聊Java里的一个小妖精,那就是异常. 什么是异常?什么是异常处理? 异常嘛,顾名思义就是不正常,(逃),是Java程序运行时,发生的预料之外的事情,它阻止了程序按照程序员的预期正常执行. 异常处理,应该说异常处理机制,就是专门用来制服这个小妖精的法宝.Java中的异常处理机制能让程序在异常发生时,按照代码的预先设定的异常处理逻辑,针对性地处理异常,让程序尽最大可能恢复正常并继续执行,且保持代码的清晰. 简而言之,Java异常处理就是能让
-
详解Java中的ReentrantLock锁
ReentrantLock锁 ReentrantLock是Java中常用的锁,属于乐观锁类型,多线程并发情况下.能保证共享数据安全性,线程间有序性 ReentrantLock通过原子操作和阻塞实现锁原理,一般使用lock获取锁,unlock释放锁, 下面说一下锁的基本使用和底层基本实现原理,lock和unlock底层 lock的时候可能被其他线程获得所,那么此线程会阻塞自己,关键原理底层用到Unsafe类的API: CAS和park 使用 java.util.concurrent.locks.R
-
详解Java中的悲观锁与乐观锁
一.悲观锁 悲观锁顾名思义是从悲观的角度去思考问题,解决问题.它总是会假设当前情况是最坏的情况,在每次去拿数据的时候,都会认为数据会被别人改变,因此在每次进行拿数据操作的时候都会加锁,如此一来,如果此时有别人也来拿这个数据的时候就会阻塞知道它拿到锁.在Java中,Synchronized和ReentrantLock等独占锁的实现机制就是基于悲观锁思想.在数据库中也经常用到这种锁机制,如行锁,表锁,读写锁等,都是在操作之前先上锁,保证共享资源只能给一个操作(一个线程)使用. 由于悲观锁的频繁加锁,
-
详细介绍Java中的各种锁
一.一张图了解21种锁 二.乐观锁 应用 CAS 思想 一种乐观思想,假定当前环境是读多写少,遇到并发写的概率比较低,读数据时认为别的线程不会正在进行修改 实现 写数据时,判断当前 与期望值是否相同,如果相同则进行更新(更新期间加锁,保证是原子性的) 三.悲观锁 应用 synchronized.vector.hashtable 思想: 一种悲观思想 ** ,即认为写多读少,遇到并发写的可能性高 实现 每次读写数据都会认为其他线程会修改,所以每次读写数据时都会上锁 缺点 他线程想要读写这个数据时,
-
Java中双重检查锁(double checked locking)的正确实现
目录 前言 加锁 双重检查锁 错误的双重检查锁 隐患 正确的双重检查锁 总结 前言 在实现单例模式时,如果未考虑多线程的情况,就容易写出下面的错误代码: public class Singleton { private static Singleton uniqueSingleton; private Singleton() { } public Singleton getInstance() { if (null == uniqueSingleton) { uniqueSingleton =
随机推荐
- JSON字符串和JSON对象相互转化实例详解
- 老生常谈MongoDB数据库基础操作
- Nginx 遇到502 Bad Gateway 自动重启的脚本代码
- java实现voctor按指定方式排序示例分享
- iOS客户端本地推送实现代码
- ASP.NET技巧:数据岛出到Excel最为简易的方法
- JavaScript希尔排序、快速排序、归并排序算法
- 谷歌浏览器不支持showModalDialog模态对话框的解决方法
- ASP.NET MVC5验证系列之服务端验证
- php实现监听事件
- Android控件之ScrollView用法实例分析
- C++重载运算符的规则详解
- Javascript中获取出错代码所在文件及行数的代码
- 手动清除AV终结者的方法与相关软件
- SQL server 2008 数据库优化常用脚本
- Windows下通过DOS命令登录MYSQL的方法
- 使用Javascript监控前端相关数据的代码
- Linux中find命令的用法汇总
- Android基于反射技术实现的加减乘除运算示例
- Centos7安装和卸载Mongodb数据库的方法