锁实现互斥同步
同步是指多个线程并发访问共享数据时,保证同一时刻只有一个线程使用
java中,最近简单互斥锁实现使用synchronized关键字
synchronized关键字进过编译后,会在代码块前后生成一个monitor enter指令
以及多个monitor exit。保证异常情况下,能正常退出方法块
同时java中的ReentrantLock类也提供了同步功能,但是他同时还提供了很多高级功能例如:
等待可中断,可实现公平锁,以及锁绑定多个条件,锁过期
公平锁:按照申请锁的时间顺序依次获取锁
synchronzied:非公平锁 ReentrantLock:默认非公平锁,可配置公平锁
建议:jdk1.6以后优先考虑使用synchronzied实现互斥同步
非阻塞同步
互斥同步会进行线程阻塞和唤醒,同时带来性能问题,被称为阻塞同步(悲观并发策略)
数据共享产生争用,产生冲突,采取补偿措施,不把线程挂起,被称为非阻塞同步(乐观并发策略)
非阻塞同步实现CAS,CAS指令执行时,只有内存地址值等于旧预期值时,处理才会将内存地址值更新
缺点:会出现ABA问题,java提供了AtomicStampedReference通过版本控制变量值,来保证CAS的正确性。
如果出现ABA问题,传统互斥锁性能可能比原子类性能更好
无同步方案
ThreadLocal:线程本地存储,保证变量的可见性,再同一个线程中,是一种无锁化实现。
使用场景:springmvc中单例模式下,保证高并发线程安全。
重量级锁
重量级锁会阻塞加锁失败的线程,在目标锁被释放后,重新唤醒进程
java线程的阻塞和唤醒,是由操作系统来完成的,涉及用户态与内核态切换,开销非常大
为了避免昂贵的阻塞和唤醒,java引入自适应自旋,其实实质在处理器中空跑一段时间,等待锁释放
轻量级锁
轻量级锁,jdk1.6引入通过CAS操作,当前比较对象锁字段的值是否为当前锁记录的地址,如果成功该线程获取到对象。
CAS不成功,检查锁对象是否指向当前的栈帧
如果是jvm会清除锁,进入该同步块,否则证明锁被其他线程持有,超过2个争用该锁会被膨胀为重量级锁
偏向锁
偏向锁是在在无竞争情况下,去除同步和CAS操作,偏向获得他的第一个线程
jdk1.6开始默认,通过-XX:+UseBaisedLocking设置
锁类型的变化过程如下图: