1. 概念介绍
1.1 线程安全锁
Synchronize(同步锁)和ReentrantLock(可重入锁)都是Java中的常用锁,都是用来保证线程安全的。
两者都是同步锁,且都是阻塞同步。
- 阻塞同步:当一个线程获取锁后,其他线程只能等待(进入阻塞态),等待获取锁的线程释放锁后,其他线程才能获取锁。
1.2 公平锁
在多个线程请求资源的时候,如果根据线程请求的顺序来分配资源,那么这个锁就是公平锁,反之就是非公平锁。
1.3 响应中断/等待可中断
在线程阻塞期间,阻塞线程等待资源的使用,如果这种等待状态能够被中断,从而释放线程去做其他的事情,这就称为等待可中断。
2. 区别
2.1 底层实现
Synchronize是Java的关键字,ReentrantLock是Java类。因此,Synchronize是JVM层面语法层面的同步锁,ReentrantLock是API层面的同步锁
2.2 锁的用法
- 设置锁和释放锁:Synchroinze是自动加锁和释放锁的,ReentrantLock设置和释放都需要手动操作;
- 修饰的对象:Synchroinze可以修饰方法和代码块,ReentrantLock只能修饰代码块
如下代码展示了它们的具体用法:
- Synchronize作为关键字修饰方法或者代码块即可;
//synchronized修饰一个方法时,这个方法叫同步方法。
public synchronized void test() {
//方法体``
}
synchronized(Object) {
//括号中表示需要锁的对象.
//线程执行的时候会对Object上锁
}
- ReentrantLock的使用需要先创建锁对象,然后在需要加锁的代码块中调用lock()方法加锁,使用完毕后调用unlock()方法释放锁。
public class LockExample {
// 创建锁对象
private final ReentrantLock lock = new ReentrantLock();
public void method() {
// 加锁操作
lock.lock();
try {
// ...
} finally {
// 释放锁
lock.unlock();
}
}
}
2.3 锁的特点
ReentrantLock相比于Synchronize,有以下特点:
- 响应中断:ReentrantLock可以响应中断,也就是在其他线程阻塞期间,可以在长时间无法获取响应的情况下,自行中断等待状态
- 公平锁:ReentrantLock默认是不公平锁,但是可以设置为公平锁,也就是可以根据线程请求的顺序来分配资源
- 绑定多个条件:一个ReentrantLock可以同时绑定多个条件,而一个Synchronize锁只能绑定一个条件。
这些特点都是Synchronize锁所不具备的。
2.4 性能比较
Sychronize是JVM层面的同步锁,实现简单,性能较好;
ReentrantLock是API层面的同步锁,需要手动创建和释放锁,性能较差,但是增加了很多特点,灵活性较好。
2.5 适用场景
Synchronize适用于:
- 简单的同步场景;
- 对同步性能有较高要求
- 不需要响应中断、公平锁、绑定多个条件;
ReentrantLock适用于: - 需求更复杂的同步场景
- 对性能要求较低
- 需要响应中断、公平锁、绑定多个条件;
3. 总结比较
对上述内容进行总结,如下表所示: