synchronized
synchronized中文意思是'同步',在java代码中也被称为同步锁。它的作用是保证同一时刻只有一个线程执行被synchronized修饰的代码块或方法,从而实现我们常说的'线程安全'。
synchronizd使用方法主要分为3种:
- 修饰实例方法
- 修饰静态方法
- 修饰代码块
具体使用规则大家可以百度,这里就不在赘述了。
那么synchronized底层原理是什么呢?
其实synchronized是通过monitor对象监视器来实现的,对于monitor对象监视器,大家可以把它理解为对与一个对象当前锁状态的监控,多个线程执行同一个同步代码块时,其实就是在争夺这个对象的monitor,如果大家尝试反编译我们synchronized的代码就会发现,在同步代码块开始时有monitorenter,结束时有monitorexit 的代码执行,这两个执行就是为了获取monitor和释放monitor。
public class com.test.testSyn.Main {
public static final java.lang.Object object;
public com.yang.testSyn.Main();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public void print();
Code:
0: getstatic #2 // Field object:Ljava/lang/Object;
3: dup
4: astore_1
5: monitorenter
6: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
9: ldc #4 // String 123
11: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
14: aload_1
15: monitorexit
16: goto 24
19: astore_2
20: aload_1
21: monitorexit
22: aload_2
23: athrow
24: return
Exception table:
from to target type
6 16 19 any
19 22 19 any
static {};
Code:
0: new #6 // class java/lang/Object
3: dup
4: invokespecial #1 // Method java/lang/Object."<init>":()V
7: putstatic #2 // Field object:Ljava/lang/Object;
10: return
}
偏向锁:后来java开发人员发现对于同步代码其实大部分情况下不存在多个线程争夺锁的情况,一般都是同一个线程执行这段同步代码块,此时每次还要在获取锁、释放锁,对于性能的消耗是很大的,所以对于只有一个线程获取锁时,只有该线程第一次获取锁会加锁(cas操作),后续就不需要加锁可以直接执行,这种就叫偏向锁。
轻量级锁:如果偏向锁在线程1执行完后,又有线程2来执行这段代码,线程2此时只需要执行加锁操作,如果线程1还没有执行完,线程2会通过自旋等待其实现完再加锁,这就是轻量级锁
重量级锁:在轻量级的基础上,此时如果又有1个或多个线程来竞争该锁,那么所有试图获取该锁的线程都会被阻塞,直到锁释放 唤醒这些线程。这就是重量级锁。
AQS
AQS:全称是 AbstractQueuedSynchronizer,中文译为抽象队列式同步器。
AQS的实现原理:AQS内部保存有state的变量,每个线程在抢锁的时其实就是取修改state的值,如果修改成功了,那么该线程就获取到锁,反之就没有获取到锁,进入阻塞队列等待。
AQS修改state是通过java中Unsafe类中的compareAndSwap方法实现的,该方法的作用就是保证操作的原子性,其参数一共有4个:操作对象、原始值、偏移量、变更后的值。