synchronized是Java提供的一种内置锁,它修饰的对象,同一时刻只能被唯一一个锁持有,它可修饰的对象有:
- 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
- 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
- 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
- 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。
从互斥锁的设计原则上来说,当B线程试图操作由A线程
持有的对象锁的临界资源时,B线程将会处于阻塞状态。
但当一个线程再次请求自己持有对象锁的临界资源时,这种情况属于重入。
如下示例, 子类重写父类中的方法doSomeThing(),sayBy(),如果是不可重入的,则会导致死锁。
package com.myConcurrent.demo.mysynchronized;
public class MySynchronizedChild extends MySynchronizedParent {
@Override
public synchronized void doSomething() {
System.out.println("Child say hello");
super.doSomething();
}
public void sayBy() {
synchronized (this){
System.out.println("Child say by 01");
synchronized (this){
System.out.println("Child say by 02");
}
}
}
public static void main(String[] args) {
MySynchronizedChild child = new MySynchronizedChild();
child.doSomething(); // 01
child.sayBy(); // 02
}
}
public abstract class MySynchronizedParent {
public synchronized void doSomething() {
System.out.println("Parent say hello");
}
}
我们通过 javap -verbose 查看 反编译的字节码,关注main 方法的2个地方:
关于01,synchronized对于方法的修饰,采用隐式标记,对方法标记为ACC_SYNCHRONIZED,表示该方法是个内置锁:
关于02,synchronized对于代码块的修饰,采用显示入锁,出锁标志,图中,出现2次 monitorenter 与 monitorexit,均是在同一线程中,重复获取对象锁,再退出对象锁。:
如上,均证明了synchronized是可重入锁。