java并发编程的艺术(五)——五花八门的锁

多线程编程的很多实现是依靠锁完成的。

锁在操作系统层面通过test and set 或者 compare and set等汇编指令实现的

Java通过一些native的compareAndSet方法(每次看到native就蠢蠢欲动要去看native背后又是什么东西…)

可以说Java所有的锁以及Java.util.concurrent包都是基于compareAndSet方法的各式组合构建出来的。接下来就是对于Java中锁的一些功能进行总结。

  1. 轻量与重量级锁

偏向锁:偏向于第一个访问锁的线程,因为该线程很有可能下次继续获取锁

轻量级锁:由偏向锁升级得到,当有多个线程访问锁的时候,偏向锁将会升级成普通的轻量级锁

重量级锁:直接将内存总线锁住的,比如synchronized关键字等

  1. 公平与非公平锁

公平锁:线程按照先来后到的顺序排队进行运行。

按照先来后到的顺序,每次都只有一个线程执行,其他线程必须等待,效率比较低

非公平锁:线程通过不断竞争,谁抢到锁谁就运行。

可能会造成“饥饿”问题,有些线程一直抢夺不到锁那就会处于始终运行不到的状态

  1. 重入与不可重入锁

可重入锁:一个线程可以多次获得的锁(A获取锁之后,在A未被释放的情况下B也可以获取锁)

不可重入锁:A获取到锁后B必须等A释放锁才能进一步获取锁

  1. 死锁与活锁

死锁:两个线程互相控制着彼此的资源,A需要获得B的结果才能继续进行,而B需要获得A的结果才能继续进行

活锁:两个线程都不抢夺资源,导致两个线程始终处于不使用资源的情况。

  1. 悲观与乐观锁

悲观锁:对于线程的正确运行持“悲观”态度,只要有对线程的操作,都进行上锁操作从而确保线程安全。

线程的安全被确保了,但是效率降低了。

乐观锁:

对线程的运行保持“乐观”态度,即默认线程不会对数据进行修改操作,而是通过CAS或者版本号等方式去判断之前有没有人修改数据,若发现了修改且修改有效后再更新拿到的旧值。

  1. 读写锁

定义:把对共享资源的访问划分为读与写,多读者不存在矛盾,而写锁必须与其他互斥,即只能有一个线程去进行写。

共享锁:又可以被称作“读锁”,只支持对数据的读取操作但不支持修改操作。

排他锁:又被称为“写锁”,支持对于数据的读取和修改操作,拥有排他锁的线程不允许其他线程读取和修改。

  1. 其他

自旋锁:如果一个线程占用锁的时间比较短,那么其它的线程不需要内核态和用户态切换进入阻塞状态,而是通过无限循环反复检查锁变量是否可用(所谓的稍微等一等),直到获取到锁。

互斥锁:一次最多只能有一个线程持有这把锁。

分段锁:concurrentHashMap中使用到segment,通过把要存放的数据分成一段一段,每一段都给一个锁,确保该段数据的线程安全。

闭锁:countDownLatch, 可以用来确保一个线程等到其他线程完成后开始执行。就像一扇门,等所有的人都到齐了再打开让所有人一起进去。

信号量:n条线程访问m个资源(m<n)统一时刻只允许m条线程访问资源。

同步屏障:线程阻塞在屏障处,等所有线程都到了屏障的位置之后,屏障再打开让所有线程都开始运行。

喜欢的话转发分享,点亮“在看”噢~
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值