前言
软件并发已经成为现代软件开发的基础能力,而 Java 精心设计的高效并发机制,正是构建大规模应用的基础之一,掌握java并发编程已经成为日常开发中不可或缺的一部分。因此我会尝试谈一谈并发中的锁。关键字
再入锁(重入锁),锁膨胀、降级;理解偏斜锁、自旋锁、轻量级锁、重量级锁,原子性,可见性,有序性
一、定义
ReentrantLock(再入锁,重入锁)
一个可重入互斥Lock具有与使用synchronized方法和语句访问的隐式监视锁相同的基本行为和语义,但具有扩展功能。再入锁通过代码直接调用 lock() 方法获取,代码书写也更加灵活。
synchronized(同步)
ynchronized 是 Java 内建的同步机制,所以也有人称其为 Intrinsic Locking,它提供了互斥的语义和可见性,当一个线程已经获取当前锁时,其他试图获取的线程只能等待或者阻塞在那里。
在 Java 5 以前,synchronized 是仅有的同步手段,在代码中, synchronized 可以用来修饰方法,也可以使用在特定的代码块儿上,本质上 synchronized 方法等同于把方法全部语句用 synchronized 块包起来。
二、对比
序号\机制 | 同步 (synchronized) | 重入锁(ReentrantLock) |
---|---|---|
1 | 不支持公平性的控制 | 支持对锁的公平性(fairness)控制 |
2 | 可以被长期或一直阻塞 | 锁定期间, 是可以被其他线程打断的 (interrupt) |
3 | 无 | Condition 的构造方法newCondition |
4 | 无 | 获取所有等待锁线程的List 的方法 |
5 | 无 | lock();unlock(); |
三、使用及场景
1
当您使用同步块或方法时,您只需要编写 synchronized 关键字(并提供关联的对象),即可隐式地完成获取和释放锁的操作。
使用ReentrantLock,用户可以使用lock()和unlock()方法来获取和释放锁。
在Java中使用RentrantLock的规定方法是使用try-finally块。 调用锁后应立即使用try块,并应在finally块中释放锁。 这样,即使关键部分代码中抛出异常,也将释放锁定。
lock.lock();
try {
//…method body
}finally {
lock.unlock();
}
然而Synchronized,就没有强制性,因为隐式完成了获取和释放。
Synchronized(myObj){
…
…
}
因此,使用Synchronized编写的代码更加清晰易读。
2
Synchronized关键字强制所有锁的获取和释放以块结构的方式发生,这意味着当获取多个锁时,它们必须以相反的顺序释放,并且所有锁必须在与获取它们相同的词法范围内释放。
ReentrantLock提供了更大的灵活性,它允许在不同的作用域中获取和释放锁,并允许以任意顺序获取和释放多个锁。
使用ReentrantLock,可以使用以下代码,但不能同步。
private ReentrantLock lock;
public void methodA() {
lock.lock();
}
public void methodB() {
lock.unlock();
}
总结
1 分析好业务场景高竞争就用ReentrantLock,低竞争就用synchronized;