java中的并发中的AQS引用之Lock关键字-上(四)

并发必须详解的AQS

以java为例子,谈到并发问题,最关键的两个synchronized(下篇文章会谈谈的)和ReentrantLock,而谈到ReentrantLock,不得不谈的AbstractQueuedSynchronizer(AQS)!
首先将AQS应用于Lock中人叫Doug Lea,被称为并发之父,网传:生平不识Doug Lea,学懂并发也枉然。
java并发编程核心包在于java.concurrent.util包而JUC当中的大多数同步器实现都是围绕着共同的基础行为,比如等待队列,条件队列,独占获取,共享获取等,concurrentHashMap,ConcurrentLinkedQueue等等都在这个下面。它们这些行为的抽象就是基于AQS的,
ReentrantLock
ReentrantLock是一种具有AQS框架的应用实现,是jdk中一种线程并发访问的同步手段,它的功能类似于synchronized是一种互斥锁,可以保证线程安全。而且它具有比synchronized更多的特性,如:手动加锁与解锁,处理公平和非公平性问题。(与synchronized区别会在下篇synchronized中谈到)
三大核心原理
自旋锁,LocksSuport,CAS,queue队(双向循环链表)
自旋锁
轻量级锁失败后,虚拟机为了避免线程真实地在操作系统层面挂起,还会进行一项称为自旋锁地优化手段。在大多数情况下,线程持有锁地时间都不会太长,如果直接挂起os层面地线程可能会得不偿失,因为挂起动作,在os层面会做用户态转换到内核态,这种切换时间长,成本高,因此自旋锁,会假设在不久将来,当前地线程可以获得锁,因此虚拟机会让当前想要获取锁地线程做几个空循环,一般不会太久(50-100次),在经过若干循环后,得不到锁,才会进行os层面地挂起,将其升级为重量级锁。
LocksSuport
juc下面地提供了类,包含park()加锁,unpark()解锁,其实往底层看看它最终实现是非java语言实现地代码。
CAS
Compare And Swap --乐观锁策略
顾名思义:比较交换来判断是否出现冲突,出现冲突就重试直到不冲突为止。
假设所有线程访问共享资源时不会出现冲突,既然不会出现冲突自然就不会阻塞其他线程。线程不会出现阻塞状态。
反之还有个叫悲观锁(JDK1.6之前的内建锁):假设每一次执行同步代码块均会产生冲突,所以当线程获取锁成功,会阻塞其他尝试获取该锁的线程。
其实很简单,如图:请添加图片描述
queue队(双向循环链表)
请添加图片描述

这就是一个双向循环链表 ,这个链表中会有n个节点,每个节点是由主要的三部分组成pre,next,data。其实data会因系统而异,也会由多部分组成。pre指向前驱节点,next指向后继节点。
如:我们接下来要讲的ReentrantLock中就用到过
java.util.concurrent.locks.Node类中
请添加图片描述
上面是链表中一个节点,组成后形成全的链表。请添加图片描述
接下通过java代码实现双向循环链表的增、删、查操作。
下面展示一些 内联代码片

public class DoubleLink<Data> {
    Node<Data> head;//头节点
    Node<Data> end; //尾节点
    int size;//链表长度

    //初始化链表
    public void initList() {
        end = new Node<>(null,null,null);
        head = new Node<>(null,null, end);
        end.prev = head;
        end.next = head;
        size =0;
    }
    //获取长度
    public int length() {
        return size;
    }
    //获取节点
    //在查找时为了优化查找速度,借用了折半查找的思想进行查找
    public Node<Data> getNode (int index) {
        Node<Data> n;
        if(index>size/2){
            n = end;
            for (int i = length(); i > index; i--) {
                n = n.prev;
            }
            return n;
        } else {
            n=head;
            for (int i =0 ;i < index; i++) {
                n = n.next;
            }
            return  n;
        }
    }

    //添加节点(尾插)
    public void addNode (Data data) {
        Node<Data> renode = new Node<>(data,getNode(size-1), end);
        renode.prev.next=renode;
        renode.next.prev=renode;
        size++;
    }
    //指定位置插入节点
    public void addNodeByIndex (int i, Data data) {
        Node<Data> n=getNode(i);
        Node<Data> renode=new Node<>(data,n.prev,n);
        n.prev.next=renode;
        n.prev=renode;
        size++;
    }
    //删除元素
    public Data remove(int i){
        Node<Data> n=getNode(i);
        Data data=n.data;
        n.prev.next=n.next;
        n.next.prev=n.prev;
        size--;
        return data;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值