谈谈JVM内部锁升级过程
对象在内存中的内存布局是什么样的?
描述synchronized和ReentrantLock的底层实现和重入的底层原理。
谈谈AQS,为什么AQS底层是CAS+volatile?
描述下锁的四种状态和锁升级过程?
Object o = new Object() 在内存中占用多少字节?
自旋锁是不是一定比重量级锁效率高?
打开偏向锁是否效率一定会提升?
重量级锁到底重在哪里?
重量级锁什么时候比轻量级锁效率高,同样反之呢?
//System.out.println都加了锁
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
markword这部分其实就是加锁的核心,同时还包含的对象的一些生命信息,例如是否GC、经过了几次Young GC还存活。
klass pointer记录了指向对象的class文件指针。
instance data记录了对象里面的变量数据。
padding作为对齐使用,对象在64位服务器版本中,规定对象内存必须要能被8字节整除,如果不能整除,那么就靠对齐来补。举个例子:new出了一个对象,内存只占用18字节,但是规定要能被8整除,所以padding=6。
public class JOLDemo {
private static Object o;
public static void main(String[] args) {
o = new Object();
synchronized (o){
System.out.println(ClassLayout.parseInstance(o).toPrintable());
}
}
}
public class JOLDemo {
private static Object o;
public static void main(String[] args) {
o = new Object();
synchronized (o){
System.out.println(ClassLayout.parseInstance(o).toPrintable());
}
}
}
----------------------------------------------------------------------------------------------
public class JOLDemo {
private static Object o;
public static void main(String[] args) {
try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); }
o = new Object();
synchronized (o){
System.out.println(ClassLayout.parseInstance(o).toPrintable());
}
}
}
为什么要进行锁升级,以前不是默认syn就是重量级锁么?要么不用要么就用别的不行么?
既然4s内如果加了锁就直接到轻量级,那么能不能不要偏向锁,为什么要有偏向锁?
为什么要设置4s之后开始偏向锁?
/***StringBuffer内部同步***/
public synchronized int length() {
return count;
}
//System.out.println 无意识的使用锁
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
public class RnEnterLockDemo {
public void method() {
synchronized (this) {
System.out.println("start");
}
}
}
monitorenter :
Each object is associated with a monitor. A monitor is locked if and only if it has an owner. The thread that executes monitorenter attempts to gain ownership of the monitor associated with objectref, as follows: • If the entry count of the monitor associated with objectref is zero, the thread enters the monitor and sets its entry count to one. The thread is then the owner of the monitor. • If the thread already owns the monitor associated with objectref, it reenters the monitor, incrementing its entry count. • If another thread already owns the monitor associated with objectref, the thread blocks until the monitor's entry count is zero, then tries again to gain ownership
如果monitor的进入数为0,则该线程进入monitor,然后将进入数设置为1,该线程即为monitor的所有者。
如果线程已经占有该monitor,只是重新进入,则进入monitor的进入数加1。
如果其他线程已经占用了monitor,则该线程进入阻塞状态,直到monitor的进入数为0,再重新尝试获取monitor的所有权。
monitorexit:
The thread that executes monitorexit must be the owner of the monitor associated with the instance referenced by objectref. The thread decrements the entry count of the monitor associated with objectref. If as a result the value of the entry count is zero, the thread exits the monitor and is no longer its owner. Other threads that are blocking to enter the monitor are allowed to attempt to do so.
免费下载电子书
《Spring Boot 2.5开发实战》
本书包含了Spring Boot 2.5新特性、自动化配置原理、REST API开发、MySQL、Redis高并发缓存、MongoDB、MQ消息队列、安全机制、 性能监控等核心知识点,带你上手实战!
点击“阅读原文”,立即下载电子书~