公平性锁与非公平性锁   

       非公平性: 如果一个线程因为CPU时间全部被其他的线程抢走而无法获得CPU的执行时间,这种状态称之为饥饿,而该线程被称为“饥饿致死”,非公平锁就存在“饥饿”,因为线程得不到CPU的运行时间机会。

        公平性: 所有的线程均能公平性的获取到执行的机会。

线程饥饿的原因:

高优先级的线程抢夺所有低优先级的线程CPU时间;线程永远阻塞在进入同步块的状态;线程在等待一个本身也处于永久等待的完成的对象(例如该对象调用了wait方法)。

公平性锁:

        Lock类转换成公平锁FairLock,每一个Lock调用的线程都回去进入到队列,当解锁后, 只有队列中的第一个线程被允许获取锁。

ReentrantLock是重入锁的一种实现,一次只能由一个线程持有锁实现了Lock接口。其中包含三个内部类:Sync,NonfairSync,FairSync。

public class ReentrantLock implements Lock, java.io.Serializable
abstract static class Sync extends AbstractQueuedSynchronizer
static final class NonfairSync extends Sync
static final class FairSync extends Sync

ReentrantLock的锁的实现委托于其内部类。

公平性锁和非公平性锁的父类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(); //获取AQS中state属性值,state = 0:锁空闲,大于0: 锁占用 小于0:锁溢出
            if (c == 0) {  //锁空闲
                if (compareAndSetState(0, acquires)) {  //通过CAS来确保多线程的安全性
                    setExclusiveOwnerThread(current);  //设置当前持有锁的线程
                    return true;  //加锁成功
                }
            }
//锁占用(当前线程持有锁或者其他线程持有锁)或者锁溢出
            else if (current == getExclusiveOwnerThread()) {  //判断是否当前线程获取锁(可重入锁的体现,当前线程可以再次获取到锁,并且对state修改)
                int nextc = c + acquires;   //对持有锁的次数进行变更
                if (nextc < 0)   //被锁次数上溢(超过int的最大值),
                    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);  //将持有锁的线程信息置为null
            }
            setState(c);   //变更锁的状态
            return free;  //释放锁操作,当 c==0时,才能真正释放锁,不等于0时,只能变更锁状态,不能真正释放
        }

      //释放当前线程持有的锁
        protected final boolean isHeldExclusively() {
            
            return getExclusiveOwnerThread() == Thread.currentThread();

        }
//获取ConditionObject对象
        final ConditionObject newCondition() {
            return new ConditionObject();
        }

//获取持有锁的线程
        final Thread getOwner() {
            return getState() == 0 ? null : getExclusiveOwnerThread();
        }
//获取加锁次数
        final int getHoldCount() {
            return isHeldExclusively() ? getState() : 0;
        }
//判断是否加锁
        final boolean isLocked() {
            return getState() != 0;
        }

    }

公平性锁的实现(FairSync):

 static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;

        final void lock() {
            acquire(1);
        }

       //公平锁实现的tryAcquire
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {//锁是空闲的
                //当前线程处于等待队列的第一个等待着或者等待队列为空时,当前的线程才能获取锁
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current); //加锁成功
                    return true;
                }
            }
            //当前线程正是锁的持有者
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                //变更state值
                setState(nextc);
                return true;
            }
            return false;
        }
    }
AQS类中方法:
    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            //获取锁失败时,当前线程加入到等待队列
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
    
//当前线程是否处于对队列第一个或者是当前队列为null
 public final boolean hasQueuedPredecessors() {
        Node t = tail; // Read fields in reverse initialization order
        Node h = head;
        Node s;
        return h != t &&
            ((s = h.next) == null || s.thread != Thread.currentThread());
    }

非公平性锁的实现(NonFairSync)

static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;
        //lock加锁操作
        final void lock() {
            if (compareAndSetState(0, 1)) //直接通过CAS抢锁,true:抢锁成功
                setExclusiveOwnerThread(Thread.currentThread());//设置锁的持有者
            else
                acquire(1); //获取锁失败,进入到常规流程,acquire会首先调用tryAcquire
        }

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }

AQS类中的:
 public final void acquire(int arg) {
        if (!tryAcquire(arg) &&            //获取锁失败false(取反也就是true),继续进行后续的判断
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))     //
            selfInterrupt();
 }
private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);    //现在要获取锁的线程
       
        Node pred = tail;
        if (pred != null) {
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        enq(node);
        return node;
    }
 

两个构造函数为:

public ReentrantLock() {
        sync = new NonfairSync();//默认为非公平性锁
    }

public ReentrantLock(boolean fair) {   //fair决定公平性锁和非公平性锁(true -->为公平性锁 false -->非公平性锁  )
       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();
    }

对于公平性锁和非公平性锁实现的加锁操作:

代码试下:

public class Test implements Runnable{
    private ReentrantLock lock;   //锁实例
    private static Integer num = 0;
    public Test(ReentrantLock lock) {
        this.lock = lock;
    }

    @Override
    public void run() {
        while (true){
            lock.lock();
            num++;
            System.out.println(Thread.currentThread().getName()+": "+num);
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        //公平性锁的实现
        ReentrantLock fairLock = new ReentrantLock(true);
        new Thread(new Test(fairLock),"线程A").start();
        new Thread(new Test(fairLock),"线程B").start();

        //非公平性锁的实现
        ReentrantLock NofairLock = new ReentrantLock(false);
        new Thread(new Test(NofairLock),"线程A").start();
        new Thread(new Test(NofairLock),"线程B").start();
        
    }
}

1.

公平性锁运行结果(A,B线程交替执行):

 

 

 

2.

非公平性锁运行结果:

  注意:使用多把锁时,遵循先加锁后释放,后加锁先释放的原则。

posted on 2020-04-26 11:52  CccccDi  阅读(329)  评论(0编辑  收藏  举报