参考文献
https://www.cnblogs.com/aishangJava/p/6555291.html
Lock接口
public interface Lock {
//Lock方法用于主动获取锁。但是也必须手动释放锁。直到拿到锁方法才返回。
//在等待获取锁的过程中休眠并禁止一切线程调度
void lock();
//可以响应中断,从而中断等待获取锁的过程。一旦被中断,该方法抛出InterruptedException
void lockInterruptibly() throws InterruptedException;
//方法立即返回,拿到锁返回true,否则返回false
boolean tryLock();
//在指定时间内等待获取锁;过程中可被中断
boolean tryLock(long time, TimeUnit unit) throws InterruptedException; // 可以响应中断
//释放锁
void unlock();
//我们都知道Object类中的wait(), notify(), notifyAll()。但是这三个方法不能精确的控制线程。
//使用Condition代替直接使用Object类
Condition newCondition();
}
ReentrantLock
唯一实现了Lock接口的类。这个类内部可以采用两个Sync,分别是FairSync和NonfairSync。
AQS是JUC的核心,请查看专门的文章。
ReadWriteLock接口
public interface ReadWriteLock {
/**
* Returns the lock used for reading.
*
* @return the lock used for reading.
*/
Lock readLock();
/**
* Returns the lock used for writing.
*
* @return the lock used for writing.
*/
Lock writeLock();
}
ReentrantReadWriteLock类
内部同样是用Sync
读锁的获取条件要满足:
- 其他线程不能拥有写锁。当前申请读操作的线程是占有写锁的线程,可以申请将写锁降级为读锁。
- 读锁的占有数不超过最大上限
写锁的获取条件要满足:
+ 任何线程不能拥有读锁和写锁。
Lock和synchronized的选择
总的来说,Lock和synchronized有以下几点不同:
- Lock是一个接口,是JDK层面的实现;而synchronized是Java中的关键字,是Java的内置特性,是JVM层面的实现;
- synchronized 在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;
- Lock 可以让等待锁的线程响应中断,而使用synchronized时,等待的线程会一直等待下去,不能够响应中断;
- 通过Lock可以知道有没有成功获取锁,而synchronized却无法办到;
- Lock可以提高多个线程进行读操作的效率。
- 在性能上来说,如果竞争资源不激烈,两者的性能是差不多的。而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。