文章目录
Synchronized
使用:
锁this和锁普通方法针对的是对象,锁class和静态方法针对的是class文件
请看我另一篇文章:synchronized的使用
概念:
-
可重入:
- 如果一个同步方法调用另外一个同步方法,有一个方法加了锁,另外一个方法也需要加锁,加的是同一把锁同一个线程,那这个时候申请仍然会得到该对象的锁
- synchronized的就是锁重入的,比如有一个方法m1是sychronized的,m2也是synchronized的,在m1方法里面调用m2,发现是同一个线程的话,可以直接调用的,不需要去重新获取锁,在举一个例子,比如说父类有一个synchronized的方法,子类重写了这个方法,里面还是会用super调用父类的方法(调用父类是同一把锁),如果synchronized的不支持可重入的话,就会造成死锁
- 所谓的可重入就是你拿到这把锁之后不停的加锁,加一道就state加一,但锁的还是同一个对象,去一道就state减一
-
异常锁:
- 被synchronized修饰的方法,运行时产生了异常,会出现什么情况?
- 默认情况下锁会被释放,会被原来的那些个准备拿到这把锁的程序乱入进来,所以在并发处理的过程有异常要多加小心,不然可能会发生不一致的情况
- 比如:在一个web app处理过程中,多个servlet线程共同访问同一个资源,这时如果异常处理不合适,在第一个线程中抛出异常,其他线程就会进入同步代码区,有可能访问到异常产生时的数据
- 解决方法:在运行过程中产生异常了,可以用catch把异常捕捉起来,然后让代码继续
-
锁升级:
- 1.6之前,这个synchronized的底层实现是重量级的,重要级到这个synchronized都是要去找操作系统去申请锁的地步,这就会造成synchronized的效率非常低
- 1.6开始改进,后来有了锁升级的概念
- 锁级别和过程:
- 无锁:创建一个线程,还未去获取锁
- 偏向锁:只有一个线程去获取锁的时候,实际上并没有给锁对象加锁,而是在锁对象的头markword上记录这个线程ID
- 自旋锁:当有线程去征用锁的话,会先撤销锁,把记录的线程ID撤销,升级为自旋锁,通过CAS竞争,谁先把LR指针放入maekword中,谁先使用,没抢到锁的线程会用一个while循环去获取锁,当达到设定的次数之后会进行锁升级
- 重量级锁:默认自旋锁自旋十次之后,升级为重量级锁,重量级锁就是去操作系统那里去申请资源
锁的升级会把信息记录到markword中:
无锁:markword中后三位001
偏向锁:后三位101
自旋锁:后两位00
重量级锁:后两位10
-
注意:
- 并不是CAS的效率就一定比系统锁要高,这个需要区分实际情况:
执行时间短(加锁代码),线程数少,用自旋
执行时间长,线程数多,用系统锁
原因:CAS会一直自旋争抢锁,占cpu,重量级锁不会去争抢锁,线程待在阻塞队列,由cpu算法调度 - synchronized(object)不能用String常量,Integer,Long
- 偏向锁和自旋锁是用户态锁,不需要去申请操作系统,偏向锁是延时开启的,默认4秒,可通过jvm参数控制
- 重量级锁是内核态,每次会去操作系统申请锁,自旋锁默认10次会升级为重量级锁
- 关于锁的信息,大家可以看我之后的文件,AQS
- 锁只能升级不能降级
- 并不是CAS的效率就一定比系统锁要高,这个需要区分实际情况: