并发编程之Lock---ReentrantLock之1

ReentrantLock

ReentrantLock实现了Lock, Lock下面还有好多实现锁,比如读锁,写锁…
ReentrantLock是重入锁,也是互斥锁,锁实现基于内部类FairSync(公平锁)和NonFairSync(非公平锁)实现,
重入锁: 当前线程获得了执行序列的锁,那么该执行序列中的所有方法都可以获取此锁,简单的说就是该线程获取锁执行某个资源,该资源类部还是可以获取该锁,
互斥锁: 一次最多只能有一个线程获取锁, synchronize关键字和Lock都是互斥锁
公平锁: 基于AQS(AbstractQueuedSynchronizer)同步器队列实现, 该队列中维护的是Node(节点),每一个node中维护的值就是当前请求获取锁的线程(我咋感觉是个双向链表),该队列遵循FIFO(先进先出),公平锁就是每次只从队首取值,新来的线程先入队等待
非公平锁: 非公平锁同样基于AQS实现, 但是在新线程加入的时候回发生锁的争夺, 并不是进行入队操作, 新线程很大程度上都能够获取锁, 而原有队列中的线程则不会被唤醒,继续等待, 当新的线程获取锁失败后,才会加入队列,队列中的线程还是会遵循先进先出,
锁实现机制都是通过node节点, state锁状态,以及cas操作等实现
详细介绍请查看Java中的公平锁和非公平锁实现详解

所有源码我都直接去掉英文注释了,不然那注释太多我,关键是我也看不懂,需要用软件翻译,一行一行的看,我就注释一个大概的意思
首先看看Lock这个类的源码:


package java.util.concurrent.locks;
import java.util.concurrent.TimeUnit;

public interface Lock {

    // 加锁,获取锁,  该方法常用
    void lock();
    
    void lockInterruptibly() throws InterruptedException;
    //尝试获取锁,成不成功看天意
    boolean tryLock();

    //尝试在某个事件段内获取锁,成不成功看天意
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

    //释放锁    该方法常用
    void unlock();

    // 这个condition是个非常好用的工具,后面再讲,他里面的方法类似于object的wait,notify,notifyAll
    Condition newCondition();
}

ReentrantLock实现了lock,看看ReentrantLock的源码:
注释应该比较清楚

package java.util.concurrent.locks;
import java.util.concurrent.TimeUnit;
import java.util.Collection;

public class ReentrantLock implements Lock, java.io.Serializable {
    private static final long serialVersionUID = 7373984872572414699L;
    /** 同步器实例, Sync就下面的一个内部类,实现了aqs */
    private final Sync sync;

    /**
     * aqs是此锁的同步控制基础。 在下面细分为公平和非公平版本。 使用AQS状态表示锁的保留数。
     * sync为ReentrantLock内部类, sync继承AQS AQS中维护了Node节点,state锁持有状态 =0没有线程持有该锁 >0 有线程持有该锁, 对state的操作是cas操作
     * 
     */
    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;

        /**
         * 执行{@link Lock#lock}。 子类化的主要原因是为非公平版本提供快速路径。
         */
        abstract void lock();

        /**
         * 执行不公平的tryLock。 tryAcquire是在子类中实现的,但是都需要对trylock方法进行不公平的尝试。
         * state属性的总结:
	     * 1. 因为存在多线程竞争的情形,使用CAS设置值
	 	 * 2. state初始值为0,线程加一次锁,state加1,获得锁的线程再次加锁,state值再次加1。所以state表示已获得锁线程进行lock操作的次数
	 	 * 3. 是volatile修饰的变量,线程直接从主存中读
         */
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState(); //锁状态标识 aqs中维护 初始值为0 state对所有线程可见的一个状态
            if (c == 0) {  //状态为0
                if (compareAndSetState(0, acquires)) { //cas原子更新操作,该对象在内存中的值和期望值0相等,则将值替换为acquires, 这里不懂的cas等下再讲
                    setExclusiveOwnerThread(current); //将当前线程设置为当前拥有独占访问权的线程
                    return true; //返回true
                }
            }else if (current == getExclusiveOwnerThread()) { //判断当前线程是不是拥有独占访问权的线程 
                
                int nextc = c + acquires; 
                if (nextc < 0) // overflow 状态小于0,溢出
                    throw new Error("Maximum lock count exceeded");//抛出异常"超出最大锁计数"
                setState(nextc);// 如果是取得锁的线程,再次获取锁,直接使用set方法设置
                return true;
            }
            return false;
        }
        
		//释放锁 state-1其实就是
        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())//该操作只针对当前持有锁的线程
                throw new IllegalMonitorStateException();//否则报错
            boolean free = false;
            if (c == 0) { //2.锁状态是不是等于0,true就是没有线程持有锁了,为false的情况就是当前线程获取的资源内部重入该锁了,
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c)//更改状态为c
            return free;
        }

        protected final boolean isHeldExclusively() {
            // While we must in general read state before owner,一般来说我们必须要检查当前线程的状态
            // we don't need to do so to check if current thread is owner,但我们不需要这样做来检查当前线程是否为锁的持有者
            return getExclusiveOwnerThread() == Thread.currentThread(); //判断当前线程是否是持有锁的线程
        }

        final ConditionObject newCondition() {
            return new ConditionObject();
        }

        // Methods relayed from outer class

        final Thread getOwner() {
            return getState() == 0 ? null : getExclusiveOwnerThread();
        }
		//检查线程持有锁的状态
        final int getHoldCount() {
        	//当前线程持有锁,返回state, 否 返回0
            return isHeldExclusively() ? getState() : 0;
        }

        final boolean isLocked() {
            return getState() != 0;
        }

        /**
         * Reconstitutes the instance from a stream (that is, deserializes it).
         */
        private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
            s.defaultReadObject();
            setState(0); // reset to unlocked state
        }
    }

    /**
     * Sync object for non-fair locks
     * ReentrantLockde的非公平锁内部类 为非公平锁同步对象
     */
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

        /**
         * Performs lock.  Try immediate barge, backing up to normal
         * acquire on failure.
         */
        final void lock() {
            if (compareAndSetState(0, 1)) //直接就进行原子操作获取锁
                setExclusiveOwnerThread(Thread.currentThread());//成功就直接设置当前线程为锁的持有者
            else
                acquire(1); //aqs中的方法,意为获取,该方法中调用tryAcquire(int acquires)尝试再次获取锁,成功则返回,不成功则循环尝试加入队列,调用acquireQueued(Node , arg),
        }
		
		//重写aqs的 tryAcquire方法
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires); //直接调用aqs的非公平实现获取锁方法再次尝试获取锁,
        }
    }

    /**
     * ReentrantLockde 公平锁内部类 为公平锁同步对象
     */
    static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;

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

        /**
         * 重写aqs的 公平的tryAcquire方法
         */
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (!hasQueuedPredecessors() && // !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");
                setState(nextc);
                return true;
            }
            return false;
        }
    }

    //创建一个非公平锁
    public ReentrantLock() {
        sync = new NonfairSync();
    }

    //创建一个公平锁还是非公平锁,看你自己的选择,传入true就是公平锁,
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

    //
    public void lock() {
        sync.lock();
    }

    //尝试获取锁,如果获取到锁,返回true
    public boolean tryLock() {
        return sync.nonfairTryAcquire(1);
    }

    //在指定时间类获取锁,如果获取返回true
    public boolean tryLock(long timeout, TimeUnit unit)
            throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }

    //释放锁
    public void unlock() {
        sync.release(1);
    }

    //
    public Condition newCondition() {
        return sync.newCondition();
    }

    //获取当前线程持有锁次数
    public int getHoldCount() {
        return sync.getHoldCount();
    }

    //检查当前线程是否为持有锁的线程
    public boolean isHeldByCurrentThread() {
        return sync.isHeldExclusively();
    }

    //锁是否被线程持有
    public boolean isLocked() {
        return sync.isLocked();
    }

    //
    public final boolean isFair() {
        return sync instanceof FairSync;
    }

    //返回锁的持有者,即当前持有锁的线程
    protected Thread getOwner() {
        return sync.getOwner();
    }

    //查询队列中是否有线程正在等待获取锁
    public final boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }

    //判断某个指定线程是否在队列中等待获取锁
    public final boolean hasQueuedThread(Thread thread) {
        return sync.isQueued(thread);
    }

    //返回队列长度
    public final int getQueueLength() {
        return sync.getQueueLength();
    }

    //返回队列里的所有线程
    protected Collection<Thread> getQueuedThreads() {
        return sync.getQueuedThreads();
    }

    //
    public boolean hasWaiters(Condition condition) {
        if (condition == null)
            throw new NullPointerException();
        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
            throw new IllegalArgumentException("not owner");
        return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
    }

    //
    public int getWaitQueueLength(Condition condition) {
        if (condition == null)
            throw new NullPointerException();
        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
            throw new IllegalArgumentException("not owner");
        return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
    }

    //
    protected Collection<Thread> getWaitingThreads(Condition condition) {
        if (condition == null)
            throw new NullPointerException();
        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
            throw new IllegalArgumentException("not owner");
        return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
    }

    //
    public String toString() {
        Thread o = sync.getOwner();
        return super.toString() + ((o == null) ?
                                   "[Unlocked]" :
                                   "[Locked by thread " + o.getName() + "]");
    }
}

以下都是AQS(AbstractQueuedSynchronized)中的源码
acquire方法 , 以独占模式获取对象,忽略中断。

public final void acquire(int arg) {
        if (!tryAcquire(arg) && //当尝试获取锁失败
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

tryAcquire(arg): 尝试获取锁,获取成功直接返回,
addWaiter:将当前线程加入到CLH队列队尾。
acquireQueued:当前线程会根据公平性原则来进行阻塞等待,直到获取锁为止;并且返回当前线程在等待过程中有没有中断过。
selfInterrupt:产生一个中断。

acquireQueued方法

final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();//当前节点的前一个节点
                if (p == head && tryAcquire(arg)) {//如果p是标杆节点,再次尝试获取锁,
                    setHead(node);//当前线程获取锁,将node标杆节点,p节点则出队
                    p.next = null; // help GC  将p的尾节点置位空,等待gc
                    failed = false;
                    return interrupted;//返回没有中断过
                }
                //p节点不是第一个节点,或者再次获取锁失败 则执行shouldParkAfterFailedAcquire和parkAndCheckInterrupt来达到阻塞的效果
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true; //返回线程中断
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

图片取至https://blog.csdn.net/ssuperlg/article/details/79542473
标杆节点: 我理解为原来在队列中但是现在获取锁的线程的节点通过setHead(node)设置的节点, 随时准备出队列的节点
而从第二个节点开始才是真正有线程在等待的节点,当正在执行的线程释放锁,将唤醒线程1,同时原标杆节点出队列,线程1这个节点设置为标杆节点,
在这里插入图片描述

addWaiter方法, 添加节点值CLH队列中

private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode); //创建一个新节点,并将当前线程放入节点中
        // Try the fast path of enq; backup to full enq on failure
        //尝试快速插入,
        //获取同步器中的tail指向的节点,即:未插入新节点时的尾节点(暂且称之为原队列中的尾节点)
        Node pred = tail;
        if (pred != null) {//如果tail为空,即原有队列没有节点,则直接用enq插入
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {//原子操作插入节点
                pred.next = node;
                return node;
            }
        }
        enq(node);//如果快速插入失败,则使用enq插入,enq内部死循环直到插入成功
        return node;
    }

enq(node)方法;将节点插入队列
这里进行了循环,如果此时存在了tail就执行同上一步骤的添加队尾操作,如果依然不存在,就把当前线程作为head结点。
插入节点后,调用acquireQueued()进行阻塞

private Node enq(final Node node) {
        for (;;) {
            Node t = tail; //队列的尾节点
            if (t == null) { // Must initialize 空队列,必须初始化一个标杆节点
                if (compareAndSetHead(new Node()))//原子操作,创建一个空值的节点
                    tail = head; //
            } else {
            	//如果不是空队列
                node.prev = t; //将队列尾节点赋值给要插入的node的前节点
                if (compareAndSetTail(t, node)) {//再将node节点插入队列
                    t.next = node;  
                    return t;
                }
            }
        }
    }

详细分析参考:
https://blog.csdn.net/qyp199312/article/details/70598480

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
# 智慧旅游解决方案摘要 智慧旅游解决方案旨在通过新一代信息网络技术和装备,实现旅游服务、管理、营销和体验的智能化。该方案响应国家政策背景,如国家旅游局和工业信息化部的指导意见,以及国家发改委的发展规划,强调数字化、网络化、智能化在旅游业的应用,推动5G和移动互联网技术在旅游领域的创新应用。 方案的建设目标围绕“一个中心、四个方面、五大平台”展开,即以智慧旅游数据中心为核心,面向服务、管理、商务和营销构建智慧景区管理平台、智慧旅游服务平台、智慧旅游商务平台和智慧旅游营销平台。这五大平台将整合全域旅游资源,提升旅游设施,拓展旅游空间,融合旅游产业链,提升旅游服务,定制旅游产品,推进旅游改革。 建设内容涵盖了整体架构的构建,包括智慧服务、智慧管理、电子商务和智慧营销等方面。通过云计算、人工智能、大数据、物联网、5G等技术,实现“云-管-端”服务能力,打造集时间、空间、层次为一体的体验平台。此外,还包括智慧景区管理平台的多个子系统,如视频监控、应急指挥调度、流量监测、舆情监督、线路SOS一键呼救、GIS人车调度、停车场管理、语音广播、环境监测管理、多媒体发布、电子巡更以及指挥调度大屏建设等。 智慧旅游服务平台则包括自助票务系统、人脸识别、扫码购票、景区门户网站、机游、WIFI覆盖系统、数字全景VR、AI机器人、智慧座椅、智慧厕所等,旨在提升游客体验,实现景区的智能化管理和服务。通过这些服务,游客可以享受到便捷的购票、入园、导览和信息服务,同时景区管理者能够更有效地监控和管理景区运营。 智慧旅游商务平台则侧重于旅行社团队申报、电子商城、综合票务系统、分销管理系统、大会员系统和景区聚合支付系统,为旅游企业提供全面的商务服务和营销支持。这些平台和系统帮助旅游企业拓宽分销渠道,实现财务管理和订单管理,同时为游客提供便捷的支付和会员服务。 最后,智慧营销平台通过综合票务系统、分销管理系统、大会员系统和景区聚合支付系统,为旅游行业提供精准的营销工具和策略。这些工具和策略有助于整合旅游资源,拓宽销售渠道,提升游客体验,实现旅游业务的数字化和智能化。 智慧旅游解决方案通过这些综合性的技术和平台,不仅提升了游客的旅游体验,还为旅游行业的可持续发展提供了强有力的技术支持和数据驱动的决策依据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值