在执行一个方法之前,首先会识别ACC_SYNCONSIZED位,如果有,表明是一个同步方法,执行方法之前必须获取对象的Monitor,才会进去执行方法一当中内容,并且执行结束之前,其他线程无法获取当前Monitor,直到方法结束或者抛出异常。
public class Tues {
public static int i ;
public synchronized static void syncTask(){
i++;
}
}
public class Test {
public static int i ;
public static void syncTask(){
synchronized (Test.class){
i++;
}
}
}
字节码: 注意其中的两个指令 MONITORENTER 和 MONITOREXIT 指令
public static syncTask()V
TRYCATCHBLOCK L0 L1 L2 null
TRYCATCHBLOCK L2 L3 L2 null
L4
LINENUMBER 12 L4
LDC Lcom/ll/payconter/intf/entity/Test;.class
DUP
ASTORE 0
MONITORENTER
L0
LINENUMBER 13 L0
GETSTATIC com/ll/payconter/intf/entity/Test.i : I
ICONST_1
IADD
PUTSTATIC com/ll/payconter/intf/entity/Test.i : I
L5
LINENUMBER 14 L5
ALOAD 0
MONITOREXIT
L1
GOTO L6
L2
FRAME FULL [java/lang/Object] [java/lang/Throwable]
ASTORE 1
ALOAD 0
MONITOREXIT
L3
ALOAD 1
ATHROW
L6
LINENUMBER 15 L6
FRAME CHOP 1
RETURN
MAXSTACK = 2
MAXLOCALS = 2
}
Lock 完全用 Java 写成,在java这个层面是无关JVM实现的。虽然 Lock 缺少了 (通过 synchronized 块或者方法所提供的) 隐式获取释放锁的便捷性,但是却拥有了锁获取与释放的可操作性、可中断的获取锁以及超时获取锁等多种 synchronized 关键字所不具备的同步特性。
锁的原理,主要是依靠聚合了一个同步器(AbstractQueuedSynchronizer 缩写为 AQS)的子类来完成线程访问控制的。
比如常见的ReentrantLock,其中内聚了Sync ,实现了AbstractQueuedSynchronizer进行线程的同步管理
abstract static class Sync extends AbstractQueuedSynchronizer
AQS原理是:如果一个共享资源是处于空闲状态,就标记当前线程为访问线程,如果当前资源处于非空闲状态,就需要一个一个线程阻塞等待以及唤醒资源分配机制,AQS通过int类型变量表示状态,使用一个FIFO的队列进行线程管理,使用CAS进行状态改变。
什么事CAS
什么是 CAS? CAS 即比较并替换(Compare And Swap)。CAS 操作包含三个操作数——内存位置、预期原值及新值。执行 CAS 操作的时候,将内存位置的值与预期原值比较,如果相匹配,那么处理器会自动将该位置值更新为新值,否则,处理器不做任何操作。
Lock锁就是需要AbstractQueuedSynchronizer子类进行实现
/** Synchronizer providing all implementation mechanics */
private final Sync sync; 手动设置公平锁或者非公平锁
/**
* Creates an instance of {@code ReentrantLock}.
* This is equivalent to using {@code ReentrantLock(false)}.
*/
public ReentrantLock() {
sync = new NonfairSync(); 默认是非公平锁
}
参考链接