//阅读学习《Java并发编程的艺术》笔记,第二章
目录
synchronized修饰方法和代码块。(修饰变量会使变量既不能读也不能写)
锁住方法:是指不让拷贝该方法进行压栈操作了。只能有一个拷贝执行该方法,这个执行完下一个才能拷贝执行。


□ 对于普通同步方法,锁是当前实例对象。
□ 对于静态同步方法,锁是当前类的Class 对象。
□ 对于同步方法块,锁是Synchonized 括号里配置的对象。

运行结果:线程1执行结束释放锁,线程2才能调用m3执行

示意图:因为是静态方法,所以m1在方法区


运行结果:线程1执行结束,线程2才能执行。

示意图:静态方法在方法区,非静态方法伴随每个对象,都有一份。


非静态的是对象锁,静态的是类锁;静态的加锁方法互斥;非静态的加锁方法互斥;不同类类型的不互斥
1、synchronized修饰静态方法-类锁
调用加锁的静态方法,锁住的是一个类。
其他的带锁的静态方法都不可以被调用。
静态方法只有一份,属于类,不管通过类还是对象,调用的都是那一份。
2、synchronized修饰非静态方法-对象锁
调用对象a加锁的非静态方法,锁住的是这个方法的对象,即对象a。
其他的对象a带锁的非静态方法都不可以被调用。
其他对象b、对象c不受影响。
3、synchronized修饰代码块
4、加锁和不加锁的方法调用互不干扰,对象锁和类锁互不干扰
凡是被synchronized修饰的方法,都必须排队使用
JVM 基于进入和退出Monitor 对象来实现
代码块同步是使用monitorenter 和monitorexit 指令。
monitorenter 指令是在编译后插入到同步代码块的开始位置,而monitorexit 是插入到方法结束处和异常处, JVM 要保证每个monitorenter 必须有对应的monitorexit 与之配对。任何对象都有一个monitor 与之关联,当且一个monitor 被持有后,它将处千锁定状态。线程执行到monitorenter 指令时,将会尝试获取对象所对应的monitor 的所有权,即尝试获得对象的锁。
Mark Word,对象头中用了32bit存储对象的hashCode 或锁信息等。

访问对象的时候去判断对象头锁标志位。
偏向、轻量、重量说的是synchronized的三种状态。
无锁状态、偏向锁状态(可以设置为没有)、轻量级锁状态和重量级锁状态
这几个状态会随着竞争情况逐渐升级,锁可以升级但不能降级。
偏向锁:
场景:没有竞争,没有并发的情况下,比较快。
加锁过程简单,直接在对象头增加自己线程的ID;线程下次再次调用时,去查看对象头中的线程ID,如果是自己的,直接调用执行。
轻量级锁(自旋锁):
场景:最多两三个,小于5个的线程竞争。
在竞争少时,如果依靠等待通知才能来竞争是比较慢的,所以通过死循环自旋查看,这样速度很快,一释放就能感知到。
自旋锁能够在别的线程释放锁之后立马知道,然后去竞争。(反应快)
自旋只适用于少量线程低并发,在高并发情况下对CPU的开销太大了;因为一个线程持有锁,其余的线程都需要一直死循环访问,即占用CPU自旋。
重量级锁:
场景:两位数以上竞争。
所以在高并发情况下,轻量级锁需要升级为重量级锁。
竞争失败的线程进入阻塞队列,不额外消耗CPU,等待执行完的线程通知唤醒,再进入就绪队列竞争。
//没有并发偏向锁最快,低并发轻量级锁最快,高并发重量级锁最快。
//偏向锁用于无竞争情况下,轻量级锁个位数竞争,重量级锁两位数以上竞争。