5.多线程锁机制
1.
synchronized底层实际上是一把锁(互斥锁、悲观锁、同步锁)
synchronized对一个非静态方法上锁,实际上是对当前调用方法的this对象上锁
jdk1.6版本之前默认synchronized,线程加锁,用monitor对象 ,默认的让所有其他线程在队列里阻塞。直到当前线程处理完,释放锁,再唤醒其他阻塞的线程。
中间涉及到各种线程阻塞,上下文切换、操作系统线程调用度。
jdk1.6之后,对锁进行了优化。引入偏向锁。因为在程序执行时,有很多时间其实只有一个线程对资源进行访问无争抢现象,这时每次都要加锁就会很耗时。
偏向锁引入了一个id的概念,向对象中传入一个线程id,再次加锁时判断当前id,如果和对象之前存的id一样,就直接执行。
多个线程竞争资源:可把偏向锁升级成为轻量级锁,优选用cas争抢锁。
如果线程太多,出现大量的线程自旋耗着cpu空转等待,就可以让其进队列,转化为重量级锁。
轻量级锁其实不一定比重量级锁性能高 。
java对象的内部结构:
可以根据如下的对象的位数状态 修改锁的状态。完成锁升级
2.AtomicInteger类
该类底层借助了cas的原理
AtomicInteger 原子操作的类,atomicInteger.incrementAndGet();底层对其中一个val变量作++的操作
AtomicInteger atomicInteger = new AtomicInteger();
atomicInteger.incrementAndGet();
其实整个incrementAndGet()方法可以分为3步,读取旧值,+1,替换旧值。
这3步,其实就是一个cas 的实现
下图即为atomicInteger.incrementAndGet();此语句的具体实现
cas:无锁、自旋锁、乐观锁、轻量级锁
1.原子性问题:在硬件底层汇编又加了把锁 (缓存行锁、总线锁)
2. aba问题
2、什么是”ABA”问题?
比如说一个线程one从内存位置V中取出A,这时候另一个线程two也从内存中取出A,并且two进行了一些操作变成了B,然后two又将V位置的数据变成A,这时候线程one进行CAS操作发现内存中仍然是A,然后one操作成功。
尽管线程one的CAS操作成功,但是不代表这个过程就是没有问题的。
aba解决方法:
可以加入一个版本号,每修改过一次,版本号就会变化一次
java中用AtomicStampedReference来提供一个带版本号的实现
下一篇: java 基础面试题