可重入性 Link to heading
可重入锁ReentrantLock,表示一个线程可以反复获得同一把锁。需要注意的是,如果一个线程多次获得锁,那么在释放的时候,也必须释放相同的次数。如果释放的次数少了,相当于当前这个线程还持有锁,其它线程无法获取锁,如果释放的次数多了,会抛出java.lang.IllegalMonitorStateException
异常。
LOCK.lock();
LOCK.lock();
try {
i++;
} finally {
LOCK.unlock();
LOCK.unlock();
}
可中断 Link to heading
通过lock()
方法获取锁的时候,如果锁已被其它线程占用,当前线程会休眠(不能被线程调度器调度),直到获取到锁。
lockInterruptibly
方法允许线程在等待锁的过程中被其它线程中断。
try {
lock.lockInterruptibly();
} catch (InterruptedException exception) {
// log exception
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
限时等待 Link to heading
tryLock()
表示线程尝试获取锁,如果获取成功,则占用,并立即返回true;如果获取失败,也不会等待,而是立即返回false。支持可以带时间参数,表示限时等待,如tryLock(3, TimeUnit.SECONDS)
等待3秒,超时则失败返回false。
try {
if (lock.tryLock(3, TimeUnit.SECONDS)) {
TimeUnit.SECONDS.sleep(5);
System.out.println(Thread.currentThread().getId() + ": my job done.");
} else {
System.out.println(Thread.currentThread().getId() + ": get lock failed.");
}
} catch (InterruptedException exception) {
exception.printStackTrace();
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
注意:
tryLock()
将总是立即获得锁,只要锁是可用的(即锁没有被其它线程占用),即使该重入锁被设置为公平锁。
公平锁 Link to heading
公平锁,根据申请锁的先后顺序,先到先得。非公平锁,则是从所有等待锁的线程中,随机选择。
公平锁最大的特点是:不会导致线程饥饿,即只要排队,线程总是会申请到锁资源的。但是公平锁要求维护一个优先级队列,因此实现成本较高,而且性能较低下。
默认情况下,锁是非公平的,没有特殊需求,不要使用公平锁。使用synchronized
关键字产生的锁就是非公平锁。重入锁允许对公平性进行设置,构造函数的参数如果是true,则表示公平锁。
private ReentrantLock fairLock = new ReentrantLock(true);
Condition Link to heading
Condition
的await()
和signal()/signalAll()
与Object的wait()
和notify()/notifyAll()
的用法和作用非常相似,只不过wait()
和notify()/notifyAll()
是与synchronized
关键字配合使用的,而Condition
的await()
和signal()/signalAll()
则是与ReentrantLock
一起使用的。
当线程使用Condition.await()
时,要求线程必须持有相关的重入锁,在Condition.await()
被调用后,线程会释放锁。同理,在线程调用Condition.signal()
时,也要求线程持有锁,Condition.signal()
被调用后,系统会从当前Condition
对象的等待队列中唤醒一个线程,线程被唤醒后,会尝试重新获取与之绑定的重入锁,一旦获取成功,则继续执行。所以线程在调用Condition.signal()
要释放锁,否则被唤醒的线程无法重新获取锁。