zoukankan      html  css  js  c++  java
  • Java锁--非公平锁

    转载请注明出处:http://www.cnblogs.com/skywang12345/p/3496651.html

    参考代码

    下面给出Java1.7.0_40版本中,ReentrantLock和AQS的源码,仅供参考!

    ReentranLock.java

     View Code

    AQS(AbstractQueuedSynchronizer.java)

     View Code

    获取非公平锁(基于JDK1.7.0_40)

    非公平锁和公平锁在获取锁的方法上,流程是一样的;它们的区别主要表现在“尝试获取锁的机制不同”。简单点说,“公平锁”在每次尝试获取锁时,都是采用公平策略(根据等待队列依次排序等待);而“非公平锁”在每次尝试获取锁时,都是采用的非公平策略(无视等待队列,直接尝试获取锁,如果锁是空闲的,即可获取状态,则获取锁)。
    在前面的“Java多线程系列--“JUC锁”03之 公平锁(一)”中,已经详细介绍了获取公平锁的流程和机制;下面,通过代码分析以下获取非公平锁的流程。

    1. lock()

    lock()在ReentrantLock.java的NonfairSync类中实现,它的源码如下:

    final void lock() {
        if (compareAndSetState(0, 1))
            setExclusiveOwnerThread(Thread.currentThread());
        else
            acquire(1);
    }

    说明
    lock()会先通过compareAndSet(0, 1)来判断“锁”是不是空闲状态。是的话,“当前线程”直接获取“锁”;否则的话,调用acquire(1)获取锁。
    (01) compareAndSetState()是CAS函数,它的作用是比较并设置当前锁的状态。若锁的状态值为0,则设置锁的状态值为1。
    (02) setExclusiveOwnerThread(Thread.currentThread())的作用是,设置“当前线程”为“锁”的持有者。

    “公平锁”和“非公平锁”关于lock()的对比

    公平锁   -- 公平锁的lock()函数,会直接调用acquire(1)。
    非公平锁 -- 非公平锁会先判断当前锁的状态是不是空闲,是的话,就不排队,而是直接获取锁。

    2. acquire()

    acquire()在AQS中实现的,它的源码如下:

    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

    (01) “当前线程”首先通过tryAcquire()尝试获取锁。获取成功的话,直接返回;尝试失败的话,进入到等待队列依次排序,然后获取锁。
    (02) “当前线程”尝试失败的情况下,会先通过addWaiter(Node.EXCLUSIVE)来将“当前线程”加入到"CLH队列(非阻塞的FIFO队列)"末尾。
    (03) 然后,调用acquireQueued()获取锁。在acquireQueued()中,当前线程会等待它在“CLH队列”中前面的所有线程执行并释放锁之后,才能获取锁并返回。如果“当前线程”在休眠等待过程中被中断过,则调用selfInterrupt()来自己产生一个中断。

    “公平锁”和“非公平锁”关于acquire()的对比

    公平锁和非公平锁,只有tryAcquire()函数的实现不同;即它们尝试获取锁的机制不同。这就是我们所说的“它们获取锁策略的不同所在之处”!
    在“Java多线程系列--“JUC锁”03之 公平锁(一)”中,已经详细介绍了acquire()涉及到的各个函数。这里仅对它们有差异的函数tryAcquire()进行说明。

    非公平锁的tryAcquire()在ReentrantLock.java的NonfairSync类中实现,源码如下:

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

    nonfairTryAcquire()在ReentrantLock.java的Sync类中实现,源码如下:

    复制代码
    final boolean nonfairTryAcquire(int acquires) {
        // 获取“当前线程”
        final Thread current = Thread.currentThread();
        // 获取“锁”的状态
        int c = getState();
        // c=0意味着“锁没有被任何线程锁拥有”
        if (c == 0) {
            // 若“锁没有被任何线程锁拥有”,则通过CAS函数设置“锁”的状态为acquires。
            // 同时,设置“当前线程”为锁的持有者。
            if (compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(current);
                return true;
            }
        }
        else if (current == getExclusiveOwnerThread()) {
            // 如果“锁”的持有者已经是“当前线程”,
            // 则将更新锁的状态。
            int nextc = c + acquires;
            if (nextc < 0) // overflow
                throw new Error("Maximum lock count exceeded");
            setState(nextc);
            return true;
        }
        return false;
    }
    复制代码

    说明
    根据代码,我们可以分析出,tryAcquire()的作用就是尝试去获取锁。
    (01) 如果“锁”没有被任何线程拥有,则通过CAS函数设置“锁”的状态为acquires,同时,设置“当前线程”为锁的持有者,然后返回true。
    (02) 如果“锁”的持有者已经是当前线程,则将更新锁的状态即可。
    (03) 如果不术语上面的两种情况,则认为尝试失败。

    “公平锁”和“非公平锁”关于tryAcquire()的对比

    公平锁和非公平锁,它们尝试获取锁的方式不同。
    公平锁在尝试获取锁时,即使“锁”没有被任何线程锁持有,它也会判断自己是不是CLH等待队列的表头;是的话,才获取锁。
    而非公平锁在尝试获取锁时,如果“锁”没有被任何线程持有,则不管它在CLH队列的何处,它都直接获取锁。

    释放非公平锁(基于JDK1.7.0_40)

    非公平锁和公平锁在释放锁的方法和策略上是一样的。
    而在前面的“Java多线程系列--“JUC锁”04之 公平锁(二) ”中,已经对“释放公平锁”进行了介绍;这里就不再重复的进行说明。

    总结
    公平锁和非公平锁的区别,是在获取锁的机制上的区别。表现在,在尝试获取锁时 —— 公平锁,只有在当前线程是CLH等待队列的表头时,才获取锁;而非公平锁,只要当前锁处于空闲状态,则直接获取锁,而不管CLH等待队列中的顺序。
    只有当非公平锁尝试获取锁失败的时候,它才会像公平锁一样,进入CLH等待队列排序等待。

  • 相关阅读:
    Android 主题theme说明 摘记
    Android开发 去掉标题栏方法 摘记
    安卓项目五子棋代码详解(二)
    关于 ake sure class name exists, is public, and has an empty constructor that is public
    百度地图3.0实现图文并茂的覆盖物
    android onSaveInstanceState()及其配对方法。
    关于集成科大讯飞语音识别的 一个问题总结
    android 关于 webview 控制其它view的显示 以及更改view数据失败的问题总结
    C# 解析 json Newtonsoft果然强大,代码写的真好
    c#数据类型 与sql的对应关系 以及 取值范围
  • 原文地址:https://www.cnblogs.com/kexianting/p/8550997.html
Copyright © 2011-2022 走看看