java中的12种锁
java中很多地方会涉及到锁,比如java代码并发场景,DB中的并发场景,分布式中的锁....你知道几种呢?下面来看看常见的11种锁
1. 乐观锁/悲观锁
这两个概念是人们对java中各种锁总结提出的模型,不是特指某种类型的锁。 乐观锁预期数据的并发操作不会发生修改而不需要进行加锁的操作,悲观锁则相反。在java中的乐观锁一般采用CAS算法或者版本控制,典型的应用如原子类操作。悲观锁则应用的比较广泛如Synchronized等等。
综上:
乐观锁适用于读操作比较多的场景,
悲观锁适用于写操作比较多的场景。
2.独享锁/共享锁
独享锁也称独占锁,是指该锁每次只能被一个线程占有,共享锁则可以被多个线程使用。
例如ReentrantReadWriteLock里的读锁是共享的,但是它的写锁是独享的。锁的共享可保证并发读是非常高效的,但是读写和写写,写读都是互斥的。
3.互斥锁/读写锁
互斥锁:
互斥意味着一个锁某一时刻只能被一个线程持有,其它试图获取锁的线程都会被阻塞,直至当前锁释放,该锁上的其它线程进入就绪状态,准备抢占锁,例如synchronized, 在jdk1.5版本之后又出现了Lock锁,它提供了比synchronized机制更加广泛的锁操作,后续将会单独开篇文章详细介绍这两种锁
读写锁:
包含了上文提到的独享锁/共享锁,写既是独享锁,读是共享锁,读远远大于写的场景非常需要用到它。相比于传统的锁,读读是不互斥的只有涉及到写才会互斥,这样就比传统锁提高了cpu资源利用率,可以说读写锁就是为了优化这种场景而设计的。
在DB中:一般读锁也叫共享锁,写锁称为独占锁。
4.行锁/表锁/页锁
MySQL的锁机制比较简单,其最显著的特点是不同的存储引擎支持不同的锁机制。行锁,表锁,页锁主要是从锁的粒度上来进行划分的.
MySQL大致可归纳为以下3种锁:
表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般
5.间隙锁
MySQL中当我们用范围条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做"间隙(GAP)"。InnoDB也会对这个"间隙"加锁,这种锁机制就是所谓的间隙锁(Next-Key锁)。
6.公平锁/非公平锁
公平锁:是指多个线程按照申请锁的顺序来获取锁。
非公平锁:不是按照顺序来获取锁,这意味着它存在这线程饥饿或优先级反转问题。
这里有第一个问题 ?为什么sychronizied的实现采用的是非公平锁且lock默认的锁机制也是非公平锁呢?
因为 非公平锁的效率更高。
这里有第二个问题?为什么说公平锁的性能比非公平锁的性能低
在没有深入了解内部机制及实现之前,先了解下为什么会存在公平锁和非公平锁。公平锁保证一个阻塞的线程最终能够获得锁,因为是有序的,所以总是可以按照请求的顺序获得锁。不公平锁意味着后请求锁的线程可能在其前面排列的休眠线程恢复前拿到锁,这样就有可能提高并发的性能。这是因为通常情况下挂起的线程重新开始与它真正开始运行,二者之间会产生严重的延时。因此非公平锁就可以利用这段时间完成操作。这是非公平锁在某些时候比公平锁性能要好的原因之一。
这里有第三个问题? 网上很多说法说非公平锁获取锁时各线程的的概率是随机的,非公平锁真的是随机的吗?
非公平锁并非真正随机,其获取锁还是有一定顺序的
参照:公平锁与非公平锁
https://blog.csdn.net/zhilinboke/article/details/83104597
查看ReentrantLock源码实现
7.偏向锁/轻量级锁/重量级锁
这几个概念是jdk1.5版本提出的,为了优化synchronized提升效率,这三种锁的状态是通过对象监视器在对象头中的字段来表明的。
偏向锁:
是指锁一直被一个线程持有,再没有其它线程竞争该锁的情况下,当前线程可自由获取该锁,降低了获取锁的代价。
轻量级锁:
当锁处于偏向锁状态时,这时候有其它线程来尝试获取该锁,则发生了竞争态势,该锁会从偏向升级为轻量级锁,其它线程会通过自旋来尝试获取锁,不会阻塞从而提高效率。不过需要注意的是,轻量级锁并不是用来代替重量级锁的,它是状态的一种过渡。
重量级锁:
当锁处于轻量状态的时候,其它线程虽然是自旋,但自旋不会一直持续下去,当自旋一定次数的时候,还没有获取到锁,就会进入阻塞,该锁膨胀为重量级锁。重量级锁会让其他申请的线程进入阻塞,性能降低。这就是jdk1.5之前为什么称synchronized为重量级锁的原因,它会使其它线程直接进入阻塞状态,从而非常影响性能,1.5版本开始提出这些锁的状态,改变了synchronized重量级的包袱。
8.可重入锁
所谓重入锁,指的是以线程为单位,当一个线程获取对象锁之后,这个线程可以再次获取本对象上的锁,而其他的线程是不可以的,它的意义在于防范死锁
9.分段锁
分段锁是一种锁的设计,而并不是指某一具体的锁,比如我们常见的ConcurrentHashMap,它是并发安全高效的集合。 分段锁的目的是细化锁的粒度,尽量避免资源的竞争使线程阻塞。
10.自旋锁
是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。
对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,”自旋”一词就是因此而得名。java中如何实现自旋,我们后面会详细介绍
11.死锁
死锁产生的原因是等待需要的资源而一直拿不到,就会导致线程一直处于等待中。比较专业的定义是:一组互相竞争资源的线程因互相等待,导致“永久”阻塞的现象。
并发程序一旦死锁,一般没有特别好的方法,很多时候我们只能重启应用。因此,解决死锁问题最好的办法还是规避死锁。
12.分布式锁
很多时候我们需要保证一个方法在同一时间内只能被同一个线程执行。在单机环境中可以很容易解决,但是在分布式环境下就比较复杂了。分布式锁有三种方式:数据库,redis,zk
db设计思路:新建一张有method字段的表,method字段创建唯一索引,作插入操作以尝试获取锁,作删除操作以释放锁
redis设计思路:用到 setnx命令,expire,dtt命令。setnx (set if it not exist)的唯一性。
zk设计思路:利用zk的一个根目录下不能有重命子结点去获取锁,释放锁。
还有其它的锁吗?敬请留言!
java中的12种锁的更多相关文章
- 5000字 | 24张图带你彻底理解Java中的21种锁
本篇主要内容如下: 本篇文章已收纳到我的Java在线文档. Github 我的SpringCloud实战项目持续更新中 帮你总结好的锁: 序号 锁名称 应用 1 乐观锁 CAS 2 悲观锁 synch ...
- 全面了解Java中的15种锁概念及机制!
在读很多并发文章中,会提及各种各样锁如公平锁,乐观锁等等,这篇文章介绍各种锁的分类.介绍的内容如下: 1.公平锁 / 非公平锁 2.可重入锁 / 不可重入锁 3.独享锁 / 共享锁 4.互斥锁 / 读 ...
- Java中的五种单例模式实现方法
[代码] Java中的五种单例模式实现方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 2 ...
- JAVA基础学习之throws和throw的区别、Java中的四种权限、多线程的使用等(2)
1.throws和throw的区别 throws使用在函数外,是编译时的异常,throw使用在函数内,是运行时的异常 使用方法 public int method(int[] arr) throws ...
- Java中的双重检查锁(double checked locking)
最初的代码 在最近的项目中,写出了这样的一段代码 private static SomeClass instance; public SomeClass getInstance() { if (nul ...
- JAVA中的四种引用以及ReferenceQueue和WeakHashMap的使用示例
简介: 本文主要介绍JAVA中的四种引用: StrongReference(强引用).SoftReferenc(软引用).WeakReferenc(弱引用).PhantomReference(虚引用) ...
- Java中的四种引用
引用定义 实际上,Java中存在四种引用,它们由强到弱依次是:强引用.软引用.弱引用.虚引用.下面我们简单介绍下这四种引用: 强引用(Strong Reference):通常我们通过new来创建一个新 ...
- java中的几种架构对象(PO,VO,DAO,BO,POJO)
java中的几种对象(PO,VO,DAO,BO,POJO) 一.PO :(persistant object ),持久对象 可以看成是与数据库中的表相映射的java对象.使用Hibernate来生 ...
- java中的几种内部类
Java中的几种内部类 内部类,听名字就可以知道是什么意思,就是类里面的类.有成员内部类,静态内部类,局部内部类和匿名内部类. 下面说一个每种内部类的的使用. 一. 成员内部类
随机推荐
- rabbitmq 的安装配置使用
前言: 对于消息队列中间件: #redis: 功能比较全,但是如果突然停止运行或断电会造成数据丢失 #RabbitMQ:功能比较齐全.稳定.便于安装,在生产环境来说是首选的 1.下载软件[下载较慢,请 ...
- python中reversed()函数的用法
reversed(a) # 返回一个反转的迭代器 举例 a = [1, 2, 3, 4, 5] b = reversed(a) # b是一个迭代器 # print(list(b)) = [5, 4, ...
- 免费馅饼~-~ (hdu 1176
当我准备要写这个随笔的时候是需要勇气的. 掉馅饼嘛,肯定是坑. (hdu1176 话说,gameboy人品太好,放学回家路上有馅饼可捡.还就在0~10这11个位置里,当馅饼开始掉的时候,gameboy ...
- js 获取地址栏信息,可以传递多个参数
//获取多个地址栏信息,name为地址栏参数名,可以传递多个参数 // 形式为 .html?id=12&a=2 function getQueryString(name){ var reg = ...
- Centos-Redhat下远程桌面的方法 & Redhat改Centos源
折腾了好几天才搞定,Redhat下远程桌面的方法,首先保证本身已经装了桌面,并且可以ssh访问 由于系统中自带python2环境,装了anaconda以及它带的python3环境,这个必须存在(前提) ...
- easyUI的datagrid控件日期列格式化
转自:https://blog.csdn.net/idoiknow/article/details/8136093 EasyUI是一套比较轻巧易用的Jquery控件,在使用过程中遇到一个问题,它的列表 ...
- [心得]暑假DAY 5
好久没更新博客了 最近事情太多太多 tarjan进阶,点双边双 T2压力 最大坑点:点双缩点 它不是直接把割点连成树(割点会有环) 而是用割点作”中介“,联接点双构成一颗树(所谓圆方树) 接着在上面进 ...
- 哨兵模式java实例
/** * 测试Redis哨兵模式 * @author liu */ public class TestSentinels { @SuppressWarnings("resource&quo ...
- kernel hacking的一些网站
很全面的网站,下面的网站基本都可以从该地址找到. 新手必备 subscrible/unsubscrible mail list mail list archive kernel git mainlin ...
- [Python]切换工作目录|python将目录切换为脚本所在目录
Python使用os.chdir命令切换python工作目录 代码示例: In []: import os In []: os.system("pwd") /home/wangju ...