1.synchronized
synchronized关键字是JVM提供的内置锁,是通过Monitor两种来实现的,分别是当其作用在类上和方法上时。
类上:
- 测试代码
public class Test {
public void test() {
synchronized (this) {
System.out.println(1);
}
}
}
- 测试类的反编译结果,执行
javap -v Test.class
.....
public void test();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=1
0: aload_0
1: dup
2: astore_1
3: monitorenter
4: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
7: iconst_1
8: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
11: aload_1
12: monitorexit
13: goto 21
16: astore_2
17: aload_1
line 10: 4
line 11: 11
line 12: 21
LocalVariableTable:
Start Length Slot Name Signature
0 22 0 this
- 分析
从上面的反编译class文件可以看出,synchronized关键字作用在类上时,其是通过monitor锁来实现的,通过monitorenter指令来表示资源已被锁定,monitorexit指令来表示资源已被释放。
另外,资源在被锁定的时候mointor会将monitor的计数设置为1,由于synchronized是可重入锁,所以如果是同一个线程再次持有该锁时,则会将monitor的计数加1。如果是不同的线程则会阻塞。而资源在被释放的时候则会将计数进行减1,当计数为0时,则证明该资源已被释放,可以被其他线程获取。
方法上:
- 测试代码
public class Test {
public synchronized void test() {
System.out.println(1);
}
}
- 测试类的反编译结果,执行
javap -v Test.class
......
public synchronized void test();
descriptor: ()V
flags: ACC_PUBLIC, ACC_SYNCHRONIZED
Code:
stack=2, locals=1, args_size=1
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: iconst_1
4: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
7: return
LineNumberTable:
line 9: 0
line 10: 7
LocalVariableTable:
Start Length Slot Name Signature
0 8 0 this
- 分析
通过上面的反编译结果可以看出当synchronized关键字作用在方法上时其是通过标志ACC_SYNCHRONIZED
来进行表示的,当方法上有该标志时,则说明当前方法是由synchronized关键字进行修饰的,需要进行相应的加锁操作,是隐式的。
2.Lock
lock是java中的一个类。其主要实现是通过五个方法lock()
,lockInterruptibly()
,trylock()
,
trylock(time:long, unit:TimeUnit)
,unlock()
- lock()
阻塞模式抢占锁,如果当前线程抢占锁成功,那么其继续向下执行程序的业务逻辑,否则,当前线程会阻塞,直到持有锁的线程释放锁后再继续抢占锁。 - lockInterruptibly()
可中断模式抢占锁的方法。当前线程在抢占锁的过程中,能够响应中断信号,从而能够中断当前线程。 - trylock()
非阻塞模式下抢占锁的方法。抢占锁时,线程不会阻塞,而会立即返回抢占锁的结果。 - trylock(time:long, unit:TimeUnit)
在trylock()的基础上,加了抢占锁的时间限制 - unlock()
释放锁
关于lock的源码解析,可以看AQS与CAS分析这篇博客。
3.总结
类别 | synchronized | lock |
---|---|---|
存在层次 | Java的关键字,属于jvm层面 | java中的一个类 |
是否需要手动释放 | 不需要手动释放,jvm会自动帮忙释放 | 需要在final块中手动进行释放 |
锁的获取 | 只有阻塞模式抢占锁一种,一个线程获取之后,另一个线程需要阻塞 | 有多种模式,可阻塞,可非阻塞 |
锁状态 | 无法判断 | 可以判断 |
锁类型 | 可重入,不可中断,非公平 | 可重入,可中断,可公平也可非公平 |
性能 | 少量同步 | 大量同步 |