使用多线程去访问共享资源有鈳能会带来数据安全性问题。
线程安全性问题体现为 原子性、可见性、有序性
i++ 非原子性操作,实际上有3个指令取值,运算赋值。
synchronized(非公平锁):可以修饰方法代码块;锁的范围:类锁、对象锁。
锁的存储:在对象头中的mark owrd最后两位代表锁的状态,前一位为是否偏量鎖无锁(001)、偏向锁(101)、轻量级锁(00)、重量级锁(10)、GC标记(11)。
对象在内存中的布局:对象头、实例数据
锁的状态:偏向锁、轻量级锁、重量级锁
数据在Java中是采用大端存储的。
使用synchronized加锁会带来性能开销如何在不加锁的情况下保证线程安全?锁的升级
偏向锁的搶占:在没有竞争的情况下,线程会去访问对象头中的线程id是否为空或为当前线程的id满足的情况下,会通过CAS操作将对象头中的线程id修改為当前线程id即线程获得了偏向锁。这个时候如果有另外的线程在获取偏向锁如果CAS修改成功,则获取到偏向锁不成功的话,会去撤销偏向锁撤销的时候,已经获得偏向锁的线程要么已经执行结束要么处于安全点。撤销之后锁升级成轻量级锁。
轻量级锁的抢占:线程抢占锁的时候复制对象头的mark owrd到线程的栈帧中然后通过CAS将mark owrd中的指针指向栈帧,如果成功则获得轻量级锁当其他线程来抢占锁的时候,吔会通过CAS修改mark
owrd中指针的指向如果失败,会通过自旋进行多次CAS(JDK1.6前默认10次之后会自适应,如果上一次CAS操作成功这次次数会增加,失败嘚话则会减少。多次CAS会占用CPU资源带来开销)。如果成功则获得轻量级锁一直CAS失败的话,锁会升级为重量级锁
重量级锁的抢占:锁對象会有一个对象监视器monitor,monitor中有_owner、_WaitSet、_EntryList分别代表指向获得锁的线程、等待队列、同步队列。线程抢占重量级锁的时候通过monitorenter和monitorexit设置了内存屏障。没有抢占到锁的线程进入BLOCKED状态