公平锁:
优势:各线程平等,每个线程在等待一段时间后,总有执行的机会
劣势:更慢,吞吐量更小
非公平锁:
优势:更快,吞吐量更大
劣势:有可能产生线程饥饿,也就是某些线程长时间内,始终得不到执行(线程饥饿)
读锁插队策略:::
非公平:假设线程2和线程4正在同时读取,线程3想要写入,拿不到锁,于是进入等待队列,线程5不在队列里,现在过来想要读取。
这种有2种策略: 策略1:读可以插队,效率高 ,但是容易造成饥饿,容易让写操作的线程陷入饥饿
策略2:避免饥饿,排在头节点的写锁后面
策略选择演示::
策略的选择取决于具体锁的实现,ReentrantReadWriteLock的实现是选择了策略2,是很明智的。
公平锁::不允许插队,排队,其他的只能尝试,但是不能获取锁成功
非公平锁:写锁可以随时插队
读锁仅在等待队列头节点不是想获取写锁的线程的时候可以插队,就是如果等待队列是写操作时不能插队的。这样说,好像读也不能插队,但是当等待队列头节点不是写操作就能插队;
public class NofairReadWriteLock {
private static ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock(false);
private static ReentrantReadWriteLock.ReadLock readLock = reentrantReadWriteLock.readLock();
private static ReentrantReadWriteLock.WriteLock writeLock = reentrantReadWriteLock.writeLock();
public static void main(String[] args) {
new Thread(()->{ write(); },"Thread-1").start();
new Thread(()->{ read(); },"Thread-2").start();
new Thread(()->{ read(); },"Thread-3").start();
// 写需要排队,写后面5,6线程读,但是当4作为等待队列头节点时,5,6需要在4后面排队,即使是非公平锁
new Thread(()->{ write(); },"Thread-4").start();
new Thread(()->{ read(); },"Thread-5").start();
new Thread(()->{ read(); },"Thread-6").start();
/**
* Thread-1得到了写锁,正在写入
* Thread-1释放写锁
* Thread-2得到了读锁,正在读取
* Thread-3得到了读锁,正在读取
* Thread-3释放读锁
* Thread-2释放读锁
* Thread-4得到了写锁,正在写入
* Thread-4释放写锁
* Thread-5得到了读锁,正在读取
* Thread-6得到了读锁,正在读取
* Thread-6释放读锁
* Thread-5释放读锁
*/
}
private static void read(){
readLock.lock();
try {
System.out.println(Thread.currentThread().getName()+"得到了读锁,正在读取");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println(Thread.currentThread().getName()+"释放读锁");
readLock.unlock();
}
}
private static void write(){
writeLock.lock();
try {
System.out.println(Thread.currentThread().getName()+"得到了写锁,正在写入");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println(Thread.currentThread().getName()+"释放写锁");
writeLock.unlock();
}
}
}