Lock 锁
是一个接口,有三个实现类,分别是常用的可重入锁,读锁、写锁。
常用的可重入锁,默认一般创建的是非公平锁,就是允许线程插队,而不是按先来后到顺序。
非公平锁的目的:是为了更加公平。
lock 加锁,调用的是 lock() 方法,解锁,调用 unlock() 方法。
lock 锁 和 Synchronized 的区别:
1、Synchronized 是一个关键字,修饰符,而 lock 是一个 接口,有具体的实现类
2、因为Synchronized 是一个关键字,它无法判断锁的状态,而lock 可以判断是否拿到锁;
还有 Synchronized 也无法中断线程的执行,而lock 可以通过设置中断。
3、Synchronized 会自动释放锁,而 lock 必须手动释放锁,否则会死锁。
4、在生产者-消费者模型的问题上,和Synchronized 比较, lock 可以做到更加精准的通知
线程通信(生产者、消费者):判断等待、业务、通知
syn:加锁,直接添加到方法上,调用this.wait() 等待; this.notifyAll() 通知;
lock: 需要 condition, condition.await(); condition.signlAll()
Volatile
保证可见性、禁止指令重排、但是不保证原子性
原子性问题的解决:可以使用原子类
,比如整型,可以使用AtomicInteger
原子类的底层实现是 Unsafe 类,是和操作系统挂钩。
volatile可以避免指令重排: 内存屏障
。
CAS
底层也是使用了Unsafe 类
比较当前线程的工作内存中的值和主内存中的值,如果这个值是期望的,那么则执行操作!如果不是就 一直循环!(涉及到自旋锁
思想)
缺点:
循环会耗时
ABA问题
解决ABA 问题,引入原子引用
! 对应的思想:乐观锁
!
即添加一个版本号