Java中对对象加锁的方法和对类加锁的方法会不会互相阻塞?
今天面试遇到这么一个问题:对对象加锁的方法和对类加锁的方法会不会互相阻塞?
然后我参照了网上的一些博客内容,写了以下程序验证:
他们的结果是交错输出的,也就是说他们是不阻塞的。
那么为什么会成为这样子呢?
先说一个Synchronized的原理
Synchronized关键字在编译的时候,会在同步块前后形成一个monitorenter和monitorexit的字节码指令,这两个字节码都需要一个reference类型的参数来指明要加锁和解锁的对象,在执行moniterenter指令的时候,首先要先获取加锁的对象,如果这个对象没有被锁定,就会把对象头里边锁的计数器加1,执行monitroexit的时候就会把锁的对象减一。
在执行synchronized (Solution.class)进入代码块的时候,他是对Solution的Class对象加锁,Class对象是每次加载Class文件在JVM中生成的对象,每个类对应着一个Class对象,这个Class对象是实际存在的,因此在进入synchronized (Solution.class)同步代码块的时候,会将对象头中锁的计数器加一。对实例对象synchronized (this)进行加锁的时候,则会在实例对象的对象头的计数器里边加一。因此他们是不通的加锁对象,因此不会阻塞。
那么对使用不同加载器加载的类加锁会不会阻塞呢?
我正在验证,之后补上。
结果和程序如下
public class Solution3 {
static void run1() throws InterruptedException {
synchronized (Solution.class) {
for(int i=0;i<10;i++) {
Thread.sleep(10);
System.out.println(Thread.currentThread().getName());
}
}
}
void run2() throws InterruptedException {
synchronized (this) {
for(int i=0;i<10;i++) {
Thread.sleep(10);
System.out.println(Thread.currentThread().getName());
}
}
}
public static void main(String[] args) throws InterruptedException {
Solution3 solution=new Solution3();
new Thread(()->{
try {
Solution3.run1();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}).start();
new Thread(()->{
try {
solution.run2();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}).start();
Thread.sleep(2000);
}
}