1、公平性锁和非公平性锁
非公平性:如果一个线程因为CPU时间全部被其他的线程抢走而无法获得CPU的执行时间,这种状态称之为饥饿,而该线程被称为“饥饿致死”,非公平锁就存在“饥饿”,因为线程得不到CPU的运行时间机会。
公平性:所有的线程均能公平性的获取到执行的机会
2、Java的线程饥饿原因:
1、高优先级的线程抢夺所有的低优先级的线程CPU时间
2、线程被永久阻塞在一个等待进入同步块的状态
3、线程在等待一个本身也处于永久等待完成的对象(比如调用这个对象的wait方法)
3、公平性锁的实现:
Lock类转换为公平锁FairLock,原理是:每一个Lock调用的线程都回去进入到队列,当解锁后,只有队列中的第一个线程被允许获取锁
4、ReentrantLock实现
ReentrantLock是Java中的课重入锁的一种实现,一次只能有一个线程持有锁,也就是独占锁的概念
包含三个内内部类:Sync、NonFairSync、FairSync,公平性锁和非公平性锁通过构造函数来指定
public class ReentrantLock implements Lock, java.io.Serializable {
//默认的非公平锁
public ReentrantLock() {
sync = new NonfairSync();
}
//fair决定是公平性锁和非公平性锁 true:公平锁 false:非公平锁
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
//加锁
public void lock() {
sync.lock();
}
//非公平性锁实现
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
//释放锁
public void unlock() {
sync.release(1);
}
public Condition newCondition() {
return sync.newCondition();
}
//判断有线程在等待锁
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
}
使用示例
公平锁和非公平锁的不同
A、B两个线程不断的获取共享的变量,为了保证变量的并发安全,分别使用公平锁和非公平锁实现加锁操作
实现类:
public class NonFairAndFairDemo implements Runnable {
private static Integer num = 0;
private ReentrantLock rtl;
public NonFairAndFairDemo(ReentrantLock rtl) {
this.rtl = rtl;
}
@Override
public void run() {
while (true) {
//显性加锁
rtl.lock();
num++;
System.out.println(Thread.currentThread().getName()+":"+num);
//显性释放锁
rtl.unlock();
}
}
}
注意:Lock锁的使用:
加锁和释放锁是显性调用
加锁和释放锁必须成对出现
多把锁的使用遵循先加锁后释放,后加锁先释放的原则
ReentrantLock源码分析
未完待续…