锁机制及synchronized和Lock

锁实现的模型有CAS和AQS

公平锁

ReentrantLock的底层实现为AbstractQueuedSynchronizer,其中的同步器有NonfairSync和FairSync两种

public ReentrantLock(boolean fair) {
	sync = fair ? new FairSync() : new NonfairSync(); 3	}
public ReentrantLock() {
	sync = new NonfairSync();	//默认使用非公平的同步器,非公平锁优势在于比公平锁具有更大的吞吐量,但是会造成优先级反转和饥饿现象
}

synchronized关键字使用的非公平锁

可重入锁

递归锁,ReentrantLock和synchronized都是可重入锁,可在一定程度上避免出现死锁

ReentrantReadWriteLock其中包含readLock读锁和writeLock写锁,读和读可以并发,但是写不能并 发;在同一个线程中读不能再申请写,但是写可以申请读

独享锁

读锁属于共享锁,写锁属于独享读

  • 读锁可以保证并发读的高效性,多线程中只有读读是允许的,但是读写、写读、写写都是不允许的

  • 在一个线程中读读、写写都不互斥【可重入性】,读不能再申请写,但是写可以申请读

synchronized和ReentrantLock属于独享锁

乐观锁

针对同步处理的方案

AQS是悲观锁;CAS是乐观锁

悲观锁就是利用各种锁机制;乐观锁就是无锁编程,常见的样例就是CAS

偏向锁、轻量级锁和重量级锁

是针对synchronized锁的三种状态。这三种锁状态是通过对象在对象头中的特定字段来表示的,实际上就是使用Object Minitor控制多线程的工作过程并进行协调处理

  • 偏向锁

  • 轻量锁

  • 重量级锁
    请添加图片描述

  • 只有一个线程进入临界区使用偏向锁

  • 多个线程交替进入临界区使用轻量级锁

  • 多个线程同时进入临界区使用重量级锁

锁状态优点缺点适用场景
偏向锁加锁和解锁无需额外的消耗, 和非同步方法相差很小如果竞争临界资源的线程多,那么会带来的额外的锁撤销的消耗基本用于没有线程竞争的同步场景下
轻量级锁竞争的线程不会阻塞,而是适用自旋的方式,可以提高程序的相应速度如果一直不能获取锁,则长时间运行自旋处理会造成CPU的消耗一般用于少量线程竞争锁对象,而且线程持有锁的时间较短
重量级锁线程竞争中不适用CPU自旋, 不会导致CPU空转消耗线程阻塞,响应时间变长一般用于多线程竞争锁, 且锁持有的时间较长

自旋锁

执行几个空方法,稍微等一会再无尝试加锁

自适应自旋锁

线程等待锁释放时执行的自旋次数不是固定值

synchronized和Lock

  • synchronized和Lock都是可重入锁,但是处于竞争阻塞状态时synchronized不可中断,但是lock可以中断
  • synchronized源码实现使用了对象头中Mark word标识对象加锁状态,当处于重量级锁时编译成为2个指令码monitorenter和mointorexit指令获取和释放锁;synchronized语义底层是monitor对象来完成的;sychronized方法的同步并没有依赖指令码实现,使用常量ACC_SYNCHRONIZED标识 符。Lock的底层实现是通过CAS乐观锁和AQS类来实现的,它把所有的请求线程构建成一个自旋锁队列,当队列中的操作通过CAS实现。
  • synchronized是关键字,内置语言实现,Lock是接口,常见实现类为ReentrantLock
  • synchronized在线程发生异常时自动释放锁,所以不会产生死锁,但是Lock异常不会自动释放 锁,需要在finally中实现锁的释
  • Lock有读写锁,可以提供多线程并发度的效率

synchronized特点

优势:实现简单,语义清晰,便于JVM堆栈跟踪,加锁和解锁过程由JVM自动控制,同时提供了多种优化方案,使用更为广泛

缺点:属于悲观的排他锁,不能进行高级功能

锁类型

  • 对象锁,非静态方法类锁,静态方法
  • 私有锁,同步代码块

锁特性

  • 锁具有可重入性,不需要多次释放
  • 当前线程获取到一个对象的锁之后,允许继续申请其它对象的锁锁属于排他锁
  • 每个类只有一个类锁,但是类可以实例化为对象,每个对象对应一个锁类锁和对象锁不会产生竞争,私有锁和对象锁也不会产生竞争
  • 一般建议使用私有锁,以减少锁的颗粒度,减少由锁产生的开销

*Lock接口特点*

优势:lock是一个可定时的、可轮询的和可中断的锁操作,提供了重入锁、重入读写锁、公平锁和非公平锁

缺点:需要手动释放锁,不适合JVM进行堆栈跟踪

锁类型:

  • 可重入锁ReentrantLock
  • 读写锁ReentrantReadWriteLock,注意ReentrantReadWriteLock不是具体的锁实现,其中包含了readLock读锁和writeLock写锁

特点:

  • 需要显式的进行锁的释放,特别是出现异常时,synchronized会自动释放锁,而ReentrantLock不 会自动释放锁,所以必须使用try/finally结构保证释放操作unlock
  • 公平锁,默认使用非公平锁,可以构建对象时使用true参数标识使用公平锁可重入,重入多次释放多次
  • 可中断
  • 超时机制,超时后不能获取锁不会造成死锁
  • ReentrantLock时很多类的实现基础,例如JDK1.7的ConcurrentHashMap的分段锁Segment就是 继承ReentrantLock,在CopyOnWriteArray中也使用了ReentrantLock

*使用锁的总结*

在JDK1.5中,synchronized是一个重量级操作,性能比较低效,对系统的并发性带来了很大的压力,相 比之下,一般建议使用性能更好一些的Lock。

到JDK1.6时,java对synchronized加入了很多的优化措施,例如自适应自旋锁、锁的消除、锁的粗化, 导致synchronized性能和Lock差不多

官方推荐支持synchronized的使用,在未来版本中可能还会有进一步的优化,所以提倡在synchronized 能满足需求的情况下优先考虑使用synchronized进行同步,但是从编程的角度上来说个人还是比较喜欢使用灵活方便的Lock

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值