zoukankan      html  css  js  c++  java
  • ReentrantLock,公平性锁和非公平性锁

    公平性锁与非公平性锁   

           非公平性: 如果一个线程因为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.

    非公平性锁运行结果:

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

  • 相关阅读:
    非凸优化的方法
    随机梯度下降与批量梯度下降
    python requests用于测试
    Vscode中运行js文件或部分代码 ,在下面cmd输出中显示结果
    ts问题处理(2): 'Promise' only refers to a type, but is being used as a value here.
    typeScript入门基础 (1)
    node启动服务报错Node.js Error: Cannot find module express
    能改变this各种情况下的总结,还有没有总结到的,请留言!!
    flutter安装与配置 v1.2.1版本
    vue项目webpack打包后有的文件big 问题
  • 原文地址:https://www.cnblogs.com/128-cdy/p/12688827.html
Copyright © 2011-2022 走看看