重入锁
- 重入锁指的是当前线成功获取锁后,如果再次访问该临界区,则不会对自己产生互斥行为。
- Java中对ReentrantLock和synchronized都是可重入锁,synchronized由jvm实现可重入即使,ReentrantLock都可重入性基于AQS实现。
- ReentrantLock还提供公平锁和非公平锁两种模式。
- 重入锁的基本原理是判断上次获取锁的线程是否为当前线程,如果是则可再次进入临界区,如果不是,则阻塞。
ReentrantLock
- 在JDK5.0版本之前,重入锁的性能远远好于synchronized关键字,JDK6.0版本之后synchronized 得到了大量的优化,二者性能也不分伯仲,但是重入锁是可以完全替代synchronized关键字的。除此之外,重入锁又自带一系列高逼格UBFF:可中断响应、锁申请等待限时、公平锁。另外可以结合Condition来使用,使其更是逼格满满。
package cas;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
public class MyThread extends Thread {
public static ReentrantLock lock = new ReentrantLock();
public static int i = 0;
public MyThread(String name) {
super.setName(name);
}
@Override
public void run() {
for (int j = 0; j < 100; j++) {
lock.lock();
try {
System.out.println(this.getName() + " " + i);
i++;
} finally {
lock.unlock();
}
}
}
/**
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
MyThread test1 = new MyThread("thread1");
MyThread test2 = new MyThread("thread2");
test1.start();
test2.start();
test1.join();
test2.join();
System.out.println(i);
}
}
- 用法上可以看出,与synchronized相比, ReentrantLock就稍微复杂一点。因为必须在finally中进行解锁操作,如果不在 finally解锁,有可能代码出现异常锁没被释放,
- ReentrantLock并不是一种替代内置加锁的方法,而是作为一种可选择的高级功能。ReentrantLock在功能上更加丰富,它具有可重入、可中断、可限时、公平锁等特点。
- ReentrantLock 实现了 Lock interface
- 特点
- 可重入:可以反复得到相同的一把锁,它有一个与锁相关的获取计数器,如果拥有锁的某个线程再次得到锁,那么获取计数器就加1,然后锁需要被释放两次才能获得真正释放(重入锁)。
- 与synchronized不同的是,ReentrantLock对中断是有响应的.synchronized一旦尝试获取锁就会一直等待直到获取到锁。
- 可限时
- 超时不能获得锁,就返回false,不会永久等待构成死锁
- 使用lock.tryLock(long timeout, TimeUnit unit)来实现可限时锁,参数为时间和单位。
public class TryLockTest extends Thread {
public static ReentrantLock lock = new ReentrantLock();
public TryLockTest(String name){
super(name);
}
@Override
public void run() {
try {
if (lock.tryLock(5, TimeUnit.SECONDS)) {
Thread.sleep(6000);
} else {
System.out.println(this.getName() + " get lock failed");
}
} catch (Exception e) {
} finally {
if (lock.isHeldByCurrentThread()) {
System.out.println("lock.isHeldByCurrentThread: " + this.getName());
lock.unlock();
}
}
}
public static void main(String[] args) {
TryLockTest t1 = new TryLockTest("TryLockTest1");
TryLockTest t2 = new TryLockTest("TryLockTest2");
t1.start();
t2.start();
}
}
实现ReentrantLock公平锁
- 一般意义上的锁是不公平的,不一定先来的线程能先得到锁,后来的线程就后得到锁。不公平的锁可能会产生饥饿现象。
- 公平锁的意思就是,这个锁能保证线程是先来的先得到锁。虽然公平锁不会产生饥饿现象,但是公平锁的性能会比非公平锁差很多。
- synchronized是作为Java关键字是依赖于JVM实现,Java团队应该是优先考虑性能问题,因此synchronized是非公平锁。
- 使用方法:
public ReentrantLock(boolean fair)
public static ReentrantLock fairLock = new ReentrantLock(true);
隐式锁和显式锁
- 隐式锁:隐式获取锁,synchronized是它的代表,使用者不需要关心其内部锁的获取和释放,所有的锁的相关操作都由具体的关键字完成;
- 显式锁:显示地获取锁,Lock是它的代表,需要使用者在使用的时候显示地获取和释放锁。
参考