lock-中

fengzhong_yaoye_fengling-007

悲观锁

​ 总是假设最坏的情况,每次去拿数据都会认为别人会修改,所以每次拿数据的时候都会上锁。这样别人拿这个数据就会阻塞直到它拿到共享锁(共享锁每次只给一个线程使用,其他线程阻塞,用完后再把资源转让给其他线程)。传统的关系型数据库里边就用到了很多类似的锁机制,比如行锁,表锁等,读锁,写锁等,都是在操作之前先上锁。Java中Synchronized和ReentrantLock等独占锁j就是悲观锁思想的实现。

乐观锁

​ 总假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但更新的时候会判断一下在此期间别人有没有更新这个数据,可以使用版本号机制和CAS算法实现。

​ 乐观锁适用于多读的应用类型,可以提高吞吐量,就像数据库提供的类似write_condition机制,其实都是提供乐观锁。在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的

分段锁

​ 分段锁其实是一种锁的设计,并非具体实现。对于concurrentHashMap而言,其并发的实现就是通过分段锁的形式来实现高效并发操作

​ 并发容器类的加锁机制是基于更小粒度的分段锁,分段锁也是提升多并发程序性能的重要手段之一。

​ 在并发程序中,串行操作会降低可伸缩性,并且上下文的切换也会降低性能。在锁上发生竞争时,将同时导致这两种问题,使用独占锁时保护受限资源,基本采用串行方式,每次只能有一个线程访问它。所以对于可伸缩性来说最大的威胁就是独占锁

一般有三种降低锁的竞争程度的方式:

1,减少锁的持有时间;2,降低锁的请求频率;3,使用带协调机制的独占锁,这些机制允许更高的并发性。

在某些情况下,我们可以将锁分解技术进一步扩展为一组独立对象上的锁进行分解,这称为分段锁。

简单讲解:

​ 容器内有多把锁,每把锁用于锁容器中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效的提高并发访问效率,这就是concurrentHashMap所使用的锁分段技术,首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问

举例:

​ 在concurrentHashMap中使用一个包含16个锁的数组,每个锁保护散列桶的1/16,其中第N个散列桶由第(N mod 16)个锁来保护。假设使用合适的散列算法使关键字均匀分布,那么这大约能使对锁的请求减少1/16,正是这项技术使concurrentHashMap支持的并发写入达到16个

xiaochouyu-011

锁的状态:

1,无锁状态

2,偏向锁状态

3,轻量级锁状态

4,重量级锁状态

锁的状态会通过对象监视器在对象头部中的字段表明。

四种状态会随着竞争的升级而升级,且不可逆,不可降级

四种锁并非Java语言中的锁,而是jvm为了提高锁的获取与释放效率而做的优化(用Synchronized时

偏向锁

​ 指一段同步代码一直被一个线程所访问,那么该线程会自动获取锁,降低获取锁的代价

轻量级锁

​ 当锁是偏向锁时,被另一个线程访问,偏向锁会升级为轻量级锁,其他线程会通过自选形式尝试获取,不会阻塞,提高性能

重量级锁

​ 指当前锁为轻量级锁时,另一个线程虽然自旋,但不会一直持续下去,当达到一定次数还没得到,就会进入阻塞,该锁膨胀为重量级锁。重量级锁会让其他申请的线程进入阻塞,性能降低

参考文章

你知道Java里有多少种锁吗?(15种锁最全总结)

posted @ 2022-04-28 16:58  lifelikeplay  阅读(14)  评论(0编辑  收藏  举报