章
目
录
前文我们主要讲解了《Java多线程:Lock显示锁详解》,其中重点讲解了ReentrantLock的相关API实现锁机制,本文重点讲解ReentrantLock如何实现公平锁以及它的其他几个常用方法。
公平锁与非公平锁
大多数情况下,锁是非公平的,也就是说,当好几个线程在申请锁A时,可能某几个线程申请成功的概率大于其他线程。
公平锁:会按照时间先后顺序分配锁,保证先到先得,不会让线程饥饿。
ReentrantLock实现公平锁
synchronized这个内部锁是非公平的,ReentrantLock默认实现也是非公平锁,但是ReentrantLock在定义时可以通过其构造方法让其变成公平锁,即:ReentrantLock(boolean fair)。
//公平锁
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
可传入一个boolean值,true时为公平锁,false时为非公平锁
如果是非公平锁,系统会倾向于让一个已经获得了锁的线程继续获得锁,因为这样比较高效;如果是公平锁,系统会选择等待时间最长的那个线程获得锁。公平锁需要维护一个有序队列,所以性能不高。如果不是特别的需求,一般不使用公平锁。
/**
* 公平锁和非公平锁
*/
public class Test01 {
// private static ReentrantLock lock = new ReentrantLock(); //默认是非公平锁
private static ReentrantLock lock = new ReentrantLock(true); //定义成公平锁
public static void main(String[] args) {
for(int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
while(true) {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + "获得了锁");
} finally {
lock.unlock();
}
}
}
}, "Thread" + i).start();
}
}
}
ReentrantLock的几个常用的方法
1、 getHoldCount():返回当前线程调用lock()方法的次数;
public class Test02 {
private static ReentrantLock lock = new ReentrantLock();
public static void m1() {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + "持有了:" + lock.getHoldCount());
//引文ReentrantLock是可重入锁,所以可以继续在m2()方法中继续获得锁
m2();
} finally {
lock.unlock();
}
}
public static void m2() {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + "持有了:" + lock.getHoldCount());
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
m1();
}
}
2、 getQueueLength():返回正等待获得此锁的线程预估数;
/**
* getQueueLength() 返回获得锁的线程预估数
*/
public class Test03 {
private static ReentrantLock lock = new ReentrantLock();
private static class SubThread extends Thread {
@Override
public void run() {
try {
lock.lock();
TimeUnit.SECONDS.sleep(1);
System.out.println(Thread.currentThread().getName() + ":" + lock.getQueueLength());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) {
for(int i = 0; i < 10; i++) {
new SubThread().start();
}
}
}
3、 getWaitQueueLength(Conditioncondition):返回在condition队列上等待的线程预估数;
4、 hasQueuedThread(Threadthread):查询某线程是否在等待获得该锁;
5、 hasQueuedThreads():查询是否有其他线程在等待获得该锁;
6、 hasWaiters(Conditioncondition):查询在该condition队列上是否有线程在等待;
7、 isHeldByCurrentThread():判断锁是否被当前线程锁持有;
8、 isLocked():判断锁是否被任何一个线程锁持有;
这里就不再使用代码演示了,有兴趣的可以自己去尝试下。
总结
以上就是ReentrantLock实现公平锁和几个常用方法的全部内容。