<!-- index-menu -->
ReentrantLock的使用
public class LockTest {
private static final Lock lock = new ReentrantLock();
public static void main(String[] args) throws Exception {
Thread thread = new Thread() {
@Override
public void run() {
lock.lock();
System.out.println(Thread.currentThread().getName() + " AAAAAAAAAA: " + lock.toString());
method("a");
lock.unlock();
}
};
Thread thread2 = new Thread() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " BBBBBBBBBB: " + lock.toString());
method("b");
}
};
thread.start();
thread2.start();
}
public static void method(String a) {
lock.lock();
System.out.println(a);
System.out.println(Thread.currentThread().getName() + " : " + lock.toString());
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + " : " + i);
}
lock.unlock();
}
}
ReentrantLock是可重入锁,上面的代码是使用的示例,在看源码之前需要先了解下ReentrantLock。
ReentrantLock和Synchronized都是可重入锁,可重入是指某线程已经获得某个锁,可以再次获取锁而不会出现死锁,不会因为之前已经获取过还没释放而阻塞。
ReentrantLock 与 synchronized 的区别
前面提到 ReentrantLock 提供了比 synchronized
更加灵活和强大的锁机制,那么它的灵活和强大之处在哪里呢?他们之间又有什么相异之处呢?
首先他们肯定具有相同的功能和内存语义。
- 与
synchronized
相比,ReentrantLock提供了更多,更加全面的功能,具备更强的扩展性。例如:时间锁等候,可中断锁等候,锁投票。 - ReentrantLock 还提供了条件 Condition ,对线程的等待、唤醒操作更加详细和灵活,所以在多个条件变量和高度竞争锁的地方,ReentrantLock 更加适合(以后会阐述Condition)。
- ReentrantLock 提供了可轮询的锁请求。它会尝试着去获取锁,如果成功则继续,否则可以等到下次运行时处理,而
synchronized
则一旦进入锁请求要么成功要么阻塞,所以相比synchronized
而言,ReentrantLock会不容易产生死锁些。 - ReentrantLock 支持更加灵活的同步代码块,但是使用
synchronized
时,只能在同一个synchronized
块结构中获取和释放。注意,ReentrantLock 的锁释放一定要在finally
中处理,否则可能会产生严重的后果。 - ReentrantLock 支持中断处理,且性能较
synchronized
会好些。
ReentrantLock的方法
• void lock() 获取锁,调用该方法当前线程将会获取锁,当锁获取后,该方法将返回。
• void lockInterruptibly() throws InterruptedException 可中断获取锁,与 lock()方法不同之处在于该方
法会响应中断,即在锁的获取过程中可以中断当前线程
• boolean tryLock() 尝试非阻塞的获取锁,调用该方法立即返回,true 表示获取到锁
• boolean tryLock(long time,TimeUnit unit) throws InterruptedException 超时获取锁,以下情况会返回:
时间内获取到了锁,时间内被中断,时间到了没有获取到锁。
• void unlock() 释放锁
ReentrantLock()底层是公平锁(FairSync)和非公平锁(NonfairSync)实现的,默认是非公平锁
new ReentrantLock(); // 默认非公平锁。也可以填入true指定为公平锁
-------->
public ReentrantLock() {
sync = new NonfairSync();
}
公平锁与非公平锁的区别在于,公平锁的锁获取是有顺序的。但是公平锁的效率往往没有非公平锁的效率高,在许多线程访问的情况下,公平锁表现出较低的吞吐量。
NonfairSync分析
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
// 获得锁
final void lock() {
if (compareAndSetState(0, 1)) // 比较并设置状态成功,状态0表示锁没有被占用
// 把当前线程设置独占了锁
setExclusiveOwnerThread(Thread.currentThread());
else // 锁已经被占用,或者set失败
// 以独占模式获取对象,忽略中断
acquire(1);
}
// 非公平的方式,获得同步状态。
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
NonfairSync继承Sync,Sync又继承了AbstractQueuedSynchronizer(AQS),所以实际上Lock锁底层是借助AQS同步队列实现的!
FairSync 是 ReentrantLock 的内部静态类,实现 Sync 抽象类,公平锁实现类。
FairSync
FairSync 是 ReentrantLock 的内部静态类,实现 Sync 抽象类,公平锁实现类。
#lock()
实现方法,代码如下:
final void lock() {
acquire(1);
}
Sync分析
既然NonfairSync继承Sync,那就分析下Sync吧
abstract static class Sync extends AbstractQueuedSynchronizer {
// 序列号
private static final long serialVersionUID = -5179523762034025860L;
// 获取锁
abstract void lock();
// 非公平方式获取
final boolean nonfairTryAcquire(int acquires) {
// 当前线程
final Thread current = Thread.currentThread();
// 获取状态
int c = getState();
if (c == 0) { // 表示没有线程正在竞争该锁
if (compareAndSetState(0, acquires)) { // 比较并设置状态成功,状态0表示锁没有被占用
// 设置当前线程独占
setExclusiveOwnerThread(current);
return true; // 成功
}
}
else if (current == getExclusiveOwnerThread()) { // 当前线程拥有该锁
int nextc = c + acquires; // 增加重入次数
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
// 设置状态
setState(nextc);
// 成功
return true;
}
// 失败
return false;
}
// 试图在共享模式下获取对象状态,此方法应该查询是否允许它在共享模式下获取对象状态,如果允许,则获取它
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread()) // 当前线程不为独占线程
throw new IllegalMonitorStateException(); // 抛出异常
// 释放标识
boolean free = false;
if (c == 0) {
free = true;
// 已经释放,清空独占
setExclusiveOwnerThread(null);
}
// 设置标识
setState(c);
return free;
}
// 判断资源是否被当前线程占有
protected final boolean isHeldExclusively() {
// While we must in general read state before owner,
// we don't need to do so to check if current thread is owner
return getExclusiveOwnerThread() == Thread.currentThread();
}
// 新生一个条件
final ConditionObject newCondition() {
return new ConditionObject();
}
// Methods relayed from outer class
// 返回资源的占用线程
final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
}
// 返回状态
final int getHoldCount() {
return isHeldExclusively() ? getState() : 0;
}
// 资源是否被占用
final boolean isLocked() {
return getState() != 0;
}
/**
* Reconstitutes the instance from a stream (that is, deserializes it).
*/
// 自定义反序列化逻辑
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}