1.synchronized的功能扩展:重入锁
重入锁可以完全替代synchronized关键字。在JDK5.0的早期版本中,重入锁的性能远远的好于synchronized,但是从JDL6.0开始,JDK在synchronized上做了大量的优化,使两者的性能差距并不大。
重入锁使用java.util.concurrent.locks.ReentrantLock类来实现,我们先看一段简单的重入锁的使用案例:
/**
* @ClassName ReenterLock
* @Description 重入锁简单实现方式
* @Author JinDuoWang
* @Email wangjinduoliuxi@163.com
* @Date 9:30 2019/1/18
* @Version 1.0
**/
public class ReenterLock implements Runnable {
public static ReentrantLock lock = new ReentrantLock();
public static int i = 0;
@Override
public void run() {
for (int j = 0; j < 10000000; j++) {
lock.lock();
try {
i++;
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) throws InterruptedException {
ReenterLock reenterLock = new ReenterLock();
Thread t1 = new Thread(reenterLock);
Thread t2 = new Thread(reenterLock);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
这就是一种简单的重入锁实现,重入锁对逻辑控制的灵活性要远远好于synchronized。
在这里肯定有个疑问,为什么叫重入锁呢,这不就是个锁吗?之所以这样叫是因为这种锁是可以反复进入的。当然,这里的反复仅仅局限于一个线程,看个示例:
// 在这种情况下,一个线程同时获得同一把锁,这是允许的,如果不允许的话同一个线程在第二次获得锁的时候,将会和自己产生死锁。
// 但是需要注意的是,如果一次线程获得多个锁,那么你在释放的时候也必须释放相同的次数,如果释放的次数多,会抛出一个java.lang.IllegalMonitorStateException异常,
// 反之,如果你加锁两次,但是你只释放了一次,那么后面的线程就永远无法进入临界区。
lock.lock();
lock.lock();
try {
i++;
} finally {
lock.unlock();
lock.unlock();
}
2.中断响应
对于synchronized来说,如果一个线程在等待锁,那么结果只有两种情况,要么它获得了这个锁,要么就保持等待。而是用重入锁的话还