一、同步问题
概念
多个线程在同一时间请求访问共享资源时产生的问题
未解决同步问题,使用synchronized(内建锁)实现同步处理(加锁操作)
1)同步代码块
a、锁任意对象
Object obj = new Object(); synchronized(obj){}
b、锁类对象
synchronized(类名称.class){}
c、锁当前对象
synchronized(obj){}
2)同步方法
a、普通方法
用synchronized修饰方法,锁的是当前对象
b、静态方法
用static 和 synchronized修饰方法,锁的是类
synchronized底层实现
I、 同步代码块底层实现
执行同步代码块后首先要执行moniterenter指令,退出时执行monterexit指令,使用synchronized实现同步关键点就是获取对象的监视器monitor对象,当线程获取到monitor对象后,才可以执行同步代码块,否则就只能等待,同一时刻只有一个获取到该对象的monitor监视器
通常一个monitorenter指令会同时包含多个monitorexit指令,因为JVM要确保所获得的锁无论在正常执行路径还是异常执行路径都能正确解锁
II、同步方法底层实现
当使用synchronized标记方法时,字节码会出现访问标记ACC_SYNCHRONIZED。该标记表示进入该方法时,JVM需要进行monitorenter操作,在退出该方法时,无论是否正常返回,JVM均需要进行monitorexit操作
当JVM执行monitorenter时,如果目标对象monitor的计数器为0,表示此时该对象没有被其他线程所持有,此时JVM会将该锁对象的持有线程设置成当前线程,并且将monitor计数器+1;
在目标锁的计数器不为0的情况下,如果锁对象的持有线程是当前线程,JVM可以将计数器再次+1(可重入锁);否则等待,直到持有线程释放锁
当执行monitorexit时,JVM需将锁对象计数器-1,当计算器减为0时,代表该锁已经被释放掉,唤醒所有正在等待的线程去竞争该锁
对象锁(monitor)机制
JDK1.6之前synchronized底层原理,又称为JDK1.6重量锁,线程的阻塞以及唤醒均需要操作系统由用户状态切换到内核态,开销非常大,因此效率很低
二、内建锁的优化
内建锁在优化之前性能较低,最大的问题是:在存在线程竞争的情况下会出现线程的阻塞以及唤醒带来的性能问题,这是一种互斥同步(阻塞同步)因此在JDK1.6时进行了优化
1、CAS机制
悲观锁:线程获取锁(JDK1.6之前)是一种悲观锁的策略,假设每一次执行的是临界区代码(访问共享资源)都会发生冲突,所以当前线程获取到锁的同时也会阻塞其他未获得到锁的线程
乐观锁:(CAS操作,无锁操作):假设所有线程访问共享资源时不会发生冲突,由于并不会发生冲突自然就不会阻塞其他线程,因此线程就不会出现阻塞停顿的状态。出现冲突时无锁操作使用CAS(比较交换)来鉴别线程是否出现冲突,出现冲突就重试当前操作,直到没有冲突为止锁等待的时间变短
1)CAS操作过程
CAS可以理解成CAS(V、O、N)
V:当前内存中实际存放的值O:预期值N:更新值
当V==O时,期望值与内存实际值相等,该值没有被别的线程修改过,即只O就是目前最新的值,因此可以将新值N付给V;反之,如果V!=O,表明该值已经被其他线程修改过了,因此O值不是最新值,返回V,无法修改。当多个线程使用CVS操作时,只有一个线程能成功,其余线程均失败。失败的线程会重新尝试(自旋)或挂起线程(阻塞).
内建锁在优化前,最大的问题是:在存在线程竞争的情况下会出现线程的阻塞以及唤醒带来的性能问题,这是一种互斥同步(阻塞同步);而CAS不是将线程挂起,当CAS操作失败后会进行一定的尝试操作并非耗时的将线程挂起,也叫非阻塞同步。
2)CAS存在的问题
1、ABA问题
解决:使atomic AtomicStampedReference类来解决添加版本号1A->2B->3A
2、自旋会浪费大量的CPU资源
与线程阻塞相比,自旋会浪费大量的处理器资源。因为当前线程仍处于运行状态,只不过跑的是无用指令,解决:自适应自旋:根据以往自旋时能否获取锁,来动态调整自旋的时间(循环次数)。如果在自旋时获得锁,则会稍微增加下一次自旋的时间,否则就会减少下次自旋的时长
2)锁状态
Java SE 1.6中,锁一共有4种状态,级别从低到高依次是:无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态,这几个状态会随着竞争情况逐渐升级。锁可以升级但不能降级,意味着偏向锁升级成轻量级锁后不能降级成偏向锁。这种锁升级却不能降级的策略,目的是为了提高获得锁和释放锁的效率。
锁 | 标志位 |
---|---|
无锁 | 0 01 |
偏向锁 | 1 01 |
轻量级锁 | 00 |
重量级锁 | 10 |