ReentrantLock源码

news2024/10/5 14:27:00

介绍

ReentrantLock是Java中的一种可重入锁,也称为重入锁。是一种递归无阻塞的同步机制。它可以等同于 synchronized 的使用,但是 ReentrantLock 提供了比 synchronized 更强大、灵活的锁机制,可以减少死锁发生的概率。

ReentrantLock实现了Lock接口,它提供了以下功能:

1.可重入特性:即同一个线程可以多次获得同一把锁,而不会造成死锁。

2.公平锁和非公平锁:ReentrantLock支持公平锁和非公平锁两种模式,默认情况下是非公平锁。

3.可中断特性:支持可中断的获取锁的方法,即在等待获取锁的过程中,允许被打断等待。

4.多条件变量:ReentrantLock提供了多个条件变量,可以在一个锁上创建多个等待队列。

相对于synchronized关键字,ReentrantLock的主要优点是更加灵活和可扩展。同时,相对于synchronized关键字,ReentrantLock的性能稍微慢一些,因为它需要显式地获取和释放锁。

public class ReentrantLock implements Lock, java.io.Serializable

image-20230627202954077

常量&变量

    //序列化版本号
    private static final long serialVersionUID = 7373984872572414699L;
    /** Synchronizer providing all implementation mechanics */
    //同步器
    private final Sync sync;

构造方法

  1. ReentrantLock() 这是ReentrantLock的无参构造方法,它会创建一个非公平锁(fairness参数默认为false),即当多个线程争抢同一个锁时,先获取锁的线程不一定是先发起请求的线程。
  2. ReentrantLock(boolean fairness) 这是ReentrantLock的带参构造方法,fair参数指定了锁的公平性,如果fair为true,则表示该锁是公平锁,即多个线程争抢同一个锁时,先发起请求的线程会优先获取锁。如果fair为false,则表示该锁是非公平锁,即多个线程争抢同一个锁时,先获取锁的线程不一定是先发起请求的线程。
    /**
     * Creates an instance of {@code ReentrantLock}.
     * This is equivalent to using {@code ReentrantLock(false)}.
     */
    public ReentrantLock() {
        sync = new NonfairSync();
    }

    /**
     * Creates an instance of {@code ReentrantLock} with the
     * given fairness policy.
     *
     * @param fair {@code true} if this lock should use a fair ordering policy
     */
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

内部类

ReentrantLock的内部类Sync是通过继承AQS(AbstractQueuedSynchronizer)实现的可重入锁。它维护了锁的状态和同步队列。

Sync中最重要的是tryAcquire(int acquires)方法和tryRelease(int releases)方法,它们实现了获取锁和释放锁的逻辑。在这两个方法中,会判断当前线程是否已经持有锁,如果已经持有则直接返回true,否则会将当前线程加入同步队列中,阻塞等待获取锁。

此外,Sync还重写了AQS中的其他方法,如tryAcquireShared(int acquires)和tryReleaseShared(int releases),以支持共享锁的获取和释放。

总之,Sync作为ReentrantLock的核心部分,为ReentrantLock提供了可重入锁机制的实现,保证了多线程环境下的线程同步和数据一致性。

Sync

    /**
     * Base of synchronization control for this lock. Subclassed
     * into fair and nonfair versions below. Uses AQS state to
     * represent the number of holds on the lock.
     */
    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;

        /**
         * Performs {@link Lock#lock}. The main reason for subclassing
         * is to allow fast path for nonfair version.
         */
        abstract void lock();

        /**
         * Performs non-fair tryLock.  tryAcquire is implemented in
         * subclasses, but both need nonfair try for trylock method.
         */
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                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;
        }

        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);
            }
            setState(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() {
            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
        }
    }

公平锁FairSync

FairSync是ReentrantLock的内部类,它继承了AQS(AbstractQueuedSynchronizer)类,并重写了tryAcquire方法和tryRelease方法。试图获取锁的线程会按照先进先出的顺序进行排队,并在锁可用时按照队列的顺序获取锁。因此,FairSync实现了公平锁的机制。

需要注意的是,由于FairSync实现了公平锁的机制,因此在高并发环境下性能可能会有所下降。因此,在实际开发中,需要根据具体情况来选择使用公平锁还是非公平锁。

    /**
     * Sync object for fair locks
     */
    static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;

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

        /**
         * Fair version of tryAcquire.  Don't grant access unless
         * recursive call or no waiters or is first.
         */
        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");
                setState(nextc);
                return true;
            }
            return false;
        }
    }

公平锁中,直接调用 acquire 方法。

非公平锁NonfairSync

NonfairSync继承自Sync类,Sync类是ReentrantLock的同步基础类。NonfairSync的实现方式是,当一个线程释放锁时,它会检查是否有等待线程,如果有,则唤醒其中的一个线程。如果有多个等待线程,则唤醒其中一个线程的选择是任意的,没有任何保证。这种实现方式被称为“非公平锁”,因为等待时间比较长的线程可能会一直处于等待状态,直到某个线程释放锁时才被唤醒。

总的来说,NonfairSync的实现方式比较简单,而且效率也比较高。如果不需要对线程的执行顺序进行特殊控制,可以使用NonfairSync来实现锁的同步机制。

    /**
     * Sync object for non-fair locks
     */
    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);
        }

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

非公平锁中,首先尝试将 AQS 中的 state 属性从 0 变成 1,如果成功,则代表获取锁资源成功;否则再调用 acquire 方法。

常用方法

ReentrantLock的实现借用了AQS,AQS中包含一个队列,当一个线程调用ReentrantLock的lock方法时,若此锁已经被别的线程获取,那么当前线程就会被封装为AQS中队列的节点,加入等待队列,调用park挂起,直到别的线程调用unlock解锁(内部是unpark),当前线程会被唤醒然后获取锁。

相关AbstractQueuedSynchronizer的方法,请参考AbstractQueuedSynchronizer源码

lock

lock内部调用了内部抽象类Sync(继承了AQS,AbstractQueuedSynchronizer)的实例sync的lock方法,此方法有两个实现:公平锁、非公平锁。对应两个实现了Sync的内部类:FairSync和NonfairSync

在公平锁的实现中,获取锁的lock方法实现为:

        final void lock() {
            //获取锁
            acquire(1); 
        }

非公平锁中,lock的实现为:

        final void lock() {
            // 尝试获取锁,也就是尝试把AQS中的state从0改为1
            if (compareAndSetState(0, 1)) 
                // 来到这里时,说明修改state成功,即获取锁资源成功
                // 将当前线程设置到AOS的exclusiveOwnerThread属性中,代表该线程拿到了锁资源(跟可重入锁有关)
                setExclusiveOwnerThread(Thread.currentThread()); 
            else
                // 再去获取锁
                acquire(1); 
        }

ReentrantLock的lock方法用于获得锁。它具有以下特点:

  1. 如果锁当前没有被其他线程持有,该方法会立即获得锁,并返回。
  2. 如果锁当前被其他线程持有,则当前线程会被阻塞,直到该锁被释放。
  3. 当前线程获得锁后,它可以重复调用lock方法多次,每调用一次就会增加锁的计数器。只有在锁的计数器为0时,锁才会真正被释放。
  4. 当前线程获得锁后,如果没有显式地释放锁,那么锁会一直被当前线程持有,直到当前线程退出或抛出异常,此时锁才会被自动释放。
  5. 如果当前线程在获得锁之前被中断,那么该方法会抛出InterruptedException异常。
  6. lock方法是可重入的,即同一个线程可以重复获得已经持有的锁,不会造成死锁。

acquire

AbstractQueuedSynchronizer.java

    /**
     * Acquires in exclusive mode, ignoring interrupts.  Implemented
     * by invoking at least once {@link #tryAcquire},
     * returning on success.  Otherwise the thread is queued, possibly
     * repeatedly blocking and unblocking, invoking {@link
     * #tryAcquire} until success.  This method can be used
     * to implement method {@link Lock#lock}.
     *
     * @param arg the acquire argument.  This value is conveyed to
     *        {@link #tryAcquire} but is otherwise uninterpreted and
     *        can represent anything you like.
     */
    public final void acquire(int arg) {
        //尝试获取锁
        if (!tryAcquire(arg) &&
            //addWaiter:将线程封装到 Node 节点并添加到队列尾部
            //acquireQueued查看当前排队的 Node 是否在队列的前面,如果在前面,尝试获取锁资源。如果没在前面,线程进入到阻塞状态。
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

在公平锁中,tryAcquire方法会先查看state是否为0,再看是否有线程排队,若有就直接去排队。非公平锁的tryAcquire会先查看state是否为0,若为0就尝试修改state来获取锁。如果state为1,还会额外检查一下此次获取锁是否为可重入操作,若是,就直接获取锁。

addWaiter会在线程没有拿到锁资源时(tryAcquire返回true时),将当前线程封装为Node对象,把这个Node对象加入AQS的等待队列中去。

acquireQueued会检查当前线程是否排在队伍前面,若是就尝试获取锁,若长期未获得锁,就挂起当前线程。

tryAcquire

tryAcquire() 方法分公平锁和非公平锁两套实现,主要做了两件事:

如果 AQS 当前 state 为 0,尝试获取锁资源。

如果 AQS 当前 state 不为 0,查看是否是可重入操作。

公平锁

        /**
         * Fair version of tryAcquire.  Don't grant access unless
         * recursive call or no waiters or is first.
         */
        protected final boolean tryAcquire(int acquires) {
            //获取当前线程
            final Thread current = Thread.currentThread();
            //获取AQS当前state值
            int c = getState();
            // 判断state是否为0,为0则代表当前没有线程持有锁
            if (c == 0) {
                // 首先判断是否有线程在排队,如果有,tryAcquie()方法直接返回false
                // 如果没有,则尝试获取锁资源
                if (!hasQueuedPredecessors() &&
                    //将state设置为acquires
                    compareAndSetState(0, acquires)) {
                    //将当前线程设置为锁持有者线程
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            // 如果state != 0,则代表有线程持有锁资源
            // 判断占有锁的线程是不是当前线程,如果是,则进行可重入操作
            else if (current == getExclusiveOwnerThread()) {
                // 可重入state的预期值
                int nextc = c + acquires;
                // 检查锁重入是否超过最大值,二进制第一位表示符号
                //01111111 11111111 11111111 11111111  超过最大值为负值
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
    }

非公平锁

        /**
         * Performs non-fair tryLock.  tryAcquire is implemented in
         * subclasses, but both need nonfair try for trylock method.
         */
        final boolean nonfairTryAcquire(int acquires) {
      非公平锁      //获取当前线程
            final Thread current = Thread.currentThread();
            //aqs的state状态值
            int c = getState();
            //如果state == 0,说明没有线程占用着当前的锁资源
            if (c == 0) {
                // CAS直接尝试获取锁资源,直接抢锁,不管有没有线程在队列中
                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;
        }

公平锁比非公平锁多了一步操作,就是当锁空闲时,查看一下是否有线程在排队,再决定是否尝试获取锁;非公平锁则不管是否有线程在排队,直接去抢锁。

addWaiter

AbstractQueuedSynchronizer.java

没有拿到锁资源时,当前线程就要被封装为Node对象并排队,会调用addWaiter方法。此方法在AQS中实现,因为要对AQS中的队列(双向链表)进行操作。

unlock

释放锁,将state从正整数更改为0,并且会将AQS中队列中挂起的线程唤醒(会有unpark方法)允许其他线程获得这个锁。

    /**
     * Attempts to release this lock.
     *
     * <p>If the current thread is the holder of this lock then the hold
     * count is decremented.  If the hold count is now zero then the lock
     * is released.  If the current thread is not the holder of this
     * lock then {@link IllegalMonitorStateException} is thrown.
     *
     * @throws IllegalMonitorStateException if the current thread does not
     *         hold this lock
     */
    public void unlock() {
        sync.release(1);
    }

在内部,它调用了同步对象sync的release方法,该方法会释放一个锁定计数器,允许其他线程获得锁。

注意:调用unlock方法的线程必须持有锁,否则会抛出IllegalMonitorStateException异常。

release

AbstractQueuedSynchronizer.java

释放锁 release方法(位于AQS)

    /**
     * Releases in exclusive mode.  Implemented by unblocking one or
     * more threads if {@link #tryRelease} returns true.
     * This method can be used to implement method {@link Lock#unlock}.
     *
     * @param arg the release argument.  This value is conveyed to
     *        {@link #tryRelease} but is otherwise uninterpreted and
     *        can represent anything you like.
     * @return the value returned from {@link #tryRelease}
     * release利用tryRelease先进行释放锁,tryRealse是由子类实现的方法,可以确保线程是获取到锁的,并进行释放锁,
     * unparkSuccessor主要是利用LockSupport.unpark唤醒线程;
     */
    public final boolean release(int arg) {
        //尝试释放锁,这个方法是由子类实现的方法
        if (tryRelease(arg)) {
            Node h = head;
            //头节点不为如果节点状态不是CANCELLED,也就是线程没有被取消,也就是不为0的,就进行唤醒
            if (h != null && h.waitStatus != 0)
                //唤醒线程
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

tryRelease

tryRelease在AQS中只抛出了一个异常,Sync对此方法进行了重写

该方法的作用是将锁的状态值减去传入的参数releases,并检查当前线程是否持有锁。如果当前线程不是持有锁的线程,则抛出IllegalMonitorStateException异常。如果锁的状态值为0,则表示该锁已经被完全释放,此时将锁的拥有者设置为null,并将锁的状态值设置为c,即0。如果锁的状态值不为0,则将锁的状态值设置为c。最后,如果锁已经完全释放,则返回true,否则返回false。

需要注意的是,在使用ReentrantLock时,应该使用try-finally块来确保锁的释放,避免出现死锁等问题。

        //这个方法主要是确保了当前线程持有的锁,不是抛出异常,确保线程一定获取到锁的线程,并进行响应的释放锁:
        protected final boolean tryRelease(int releases) {
            //将线程的state计时器减-1,state为0代表没有线程持有锁,大于0则代表有线程持有锁了
            int c = getState() - releases;
            // 如果释放锁的线程不是占用锁的线程,抛异常
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            // 是否成功的将锁资源释放
            boolean free = false;
            //没有线程持有锁
            if (c == 0) {
                // 如果state = 0,代表成功释放锁资源
                free = true;
                //将记录持有线程的变量置为空
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/699193.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring学习笔记---下篇

文章目录 Spring下篇1、代理模式1.1、静态代理1.2、加深理解1.3、动态代理 2、AOP2.1、什么是AOP2.2 、Aop在Spring中的作用2.3、在Spring中使用Aop 3、整合MyBatis3.1、[mybatis-spring介绍](https://mybatis.org/spring/zh/getting-started.html)3.2、整合步骤 4、事务4.1、事…

Linux基础工具|文本编辑器Vim的使用

0.前言 您好这里是limou3434的个人博客&#xff0c;感兴趣可以看看我的其他内容。 本次我给您带来的是Linux下Vim文本编辑器的使用&#xff0c;关于vim&#xff0c;您只需要知道一些常用的指令和操作即可&#xff0c;快速上手的秘诀是实践&#xff0c;并且是多次实践。 1.Vi…

12 MFC常用控件(一)

文章目录 button 按钮设置默认按钮按下回车后会响应禁用开启禁用设置隐藏设置显示设置图片设置Icon设置光标 Cbutton 类创建按钮创建消息单选按钮多选按钮 编辑框组合框下拉框操作 CListBox插入数据获取当前选中 CListCtrl插入数据设置表头修改删除 button 按钮 设置默认按钮按…

将 YAPF 设置为默认的 Python 代码格式化工具 (VS Code, PyCharm)

yapf 是一个 python 代码格式化工具, 和 black, autopep8, pycharm 自带的格式化功能相同用途. 使用 yapf 作为我的默认格式化工具, 出于以下考虑: 我和团队使用多种 ide, 而 pycharm 自带的格式化功能在其他 ide 上没法用. 所以我需要一个通用的格式化方案来保持代码风格的一…

Unity | HDRP高清渲染管线学习笔记:Rendering Debugger窗口

HDRP给我们提供了一套完整的可视化Debug工具&#xff0c;集成在Rendering Debugger窗口。通过顶部菜单Window→Analysis→Rendering Debugger可以打开窗口。Rendering Debugger窗口不仅仅可以在编辑模式下使用&#xff0c;也可以在真机上运行时使用。&#xff08;要在真机上运行…

数据结构--栈(Stack)的基本概念

数据结构–栈(Stack)的基本概念 线性表是具有相同数据类型的n ( n ≥ 0 n\ge0 n≥0&#xff09;个数据元素的有限序列&#xff0c;其中n为表长&#xff0c;当n 0时线性表是一个空表。若用L命名线性表&#xff0c;则其一般表示为: L ( a 1 , a 2 . . . , a i , a i 1 , . . …

JavaScript 手写代码 第七期(重写数组方法三) 用于遍历的方法

文章目录 1. 为什么要手写代码&#xff1f;2. 手写代码2.1 forEach2.1.1 基本使用2.1.2 手写实现 2.2 map2.2.1 基本使用2.2.2 手写实现 2.3 filter2.3.1 基本使用2.3.2 手写实现 2.4 every2.4.1 基本使用2.4.2 手写实现 2.5 some2.5.1 基本使用2.5.2 手写实现 2.6 reduce2.6.1…

大学实训报告范文6篇

大学实训报告范文篇一&#xff1a;js实训报告 一、简介&#xff1a; Web标准并不是一个单一的标准&#xff0c;而是一个系列的标准的集合。Web标准中具有代表性的几种语言有&#xff1a;_ML可扩展标记语言、_HTML可扩展超文本标记语言、CSS层叠样式表、DOM文档对象模型、Java…

助你丝滑过度到 Vue3 常用的组合式API ②④

作者 : SYFStrive 博客首页 : HomePage &#x1f4dc;&#xff1a; VUE3~TS &#x1f4cc;&#xff1a;个人社区&#xff08;欢迎大佬们加入&#xff09; &#x1f449;&#xff1a;社区链接&#x1f517; &#x1f4cc;&#xff1a;觉得文章不错可以点点关注 &#x1f449;…

HOT25-环形链表

leetcode原题链接&#xff1a;环形链表 题目描述 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数…

数据库分库分表(上)

数据库分库分表 1&#xff0c;概念 分库分表是一种数据库架构设计的方法&#xff0c;用于解决大规模数据存储和查询的性能问题。它将一个大型数据库拆分成多个小型数据库&#xff0c;每个数据库负责存储一部分数据&#xff0c;从而提高数据的读写效率和并发处理能力。 分库分…

MySQL数据库基础 17

第十七章 触发器 1. 触发器概述2. 触发器的创建2.1 创建触发器语法2.2 代码举例 3. 查看、删除触发器3.1 查看触发器3.2 删除触发器 4. 触发器的优缺点4.1 优点4.2 缺点4.3 注意点 在实际开发中&#xff0c;我们经常会遇到这样的情况&#xff1a;有 2 个或者多个相互关联的表&a…

虚幻引擎(UE5)-大世界分区WorldPartition教程(三)

文章目录 前言LevelInstance的使用1.ALevelInstance2.选择Actor创建关卡3.运行时加载LevelInstance 总结 上一篇&#xff1a;虚幻引擎(UE5)-大世界分区WorldPartition教程(二) 前言 在制作大关卡时&#xff0c;可能会遇到这样一种情况&#xff0c;就是关卡中的某些Actor会重复…

【每日一题】——Majority

&#x1f30f;博客主页&#xff1a;PH_modest的博客主页 &#x1f6a9;当前专栏&#xff1a;每日一题 &#x1f48c;其他专栏&#xff1a; &#x1f534; 每日反刍 &#x1f7e1; C跬步积累 &#x1f7e2; C语言跬步积累 &#x1f308;座右铭&#xff1a;广积粮&#xff0c;缓称…

A*算法学习笔记

1 算法思路 1、Dijkstra算法与A*算法 &#xff08;1&#xff09;Dijkstra算法&#xff08;贪心策略 优先队列&#xff09;&#xff1a; 集合S&#xff1a;已确定的顶点集合&#xff0c;初始只含源点s。 集合T&#xff1a;尚未确定的顶点集合。 算法反复从集合T中选择当前到…

开闭架构

在《不过时的经典层架构》里&#xff0c;有朋友留言关于Manager和Engine的概念&#xff0c;虽然朋友留言把概念解释清楚了。为了避免其他人有同样的疑问&#xff0c;这里我还是再解释一下。 以上是经典的四层架构&#xff0c;在这个架构中&#xff0c;Manager和Engine(引擎)都是…

【liunx配置服务自启动】liunx系统设置net Core程序开机自启动服务 centos系统

liunx系统设置net Core程序开机自启动服务 系统版本&#xff1a;Centos7.9 我的程序部署到/www/wwwroot/AcmeBookStoreHttpApiHost.com/目录下&#xff0c; 程序名是Meowv.Blog.HttpApi.Hosting.dll 1.新建自启动配置文件 首先跳转到system目录下 cd /usr/lib/systemd/syste…

【.net core】yisha框架,实体不在同一项目下设置swagger接口及实体模型注释,授权鉴权

1.Startup.cs中ConfigureServices方法中添加&#xff1a; 授权鉴权内容 #region 授权鉴权//Bearer 的scheme定义var securityScheme new OpenApiSecurityScheme(){Description "使用JWT方案授权&#xff0c;请求时&#xff0c;在请求头部信息中加入: \"Authoriza…

分布式计算模型详解:MapReduce、数据流、P2P、RPC、Agent

前言 本文隶属于专栏《大数据理论体系》&#xff0c;该专栏为笔者原创&#xff0c;引用请注明来源&#xff0c;不足和错误之处请在评论区帮忙指出&#xff0c;谢谢&#xff01; 本专栏目录结构和参考文献请见大数据理论体系 思维导图 MapReduce MapReduce 是一种分布式计算模…

Tomcat与Undertow容器性能对比分析

&#x1f468;‍&#x1f393;作者&#xff1a;bug菌 ✏️博客&#xff1a; CSDN、 掘金、 infoQ、 51CTO等 &#x1f389;简介&#xff1a;CSDN博客专家&#xff0c;C站历届博客之星Top50&#xff0c;掘金/InfoQ/51CTO等社区优质创作者&#xff0c;全网合计8w粉&#xff0c;对…