阐述网站建设的步骤过程/成都高端网站建设哪家好
Java并发包(JUC)中提供了很多并发工具,比如前面介绍过的ReentrantLock、ReentrantReadWriteLock、CountDownLatch、Semaphore、FutureTask等锁或者同步部件,它们的实现都用到了一个共同的基类——AbstractQueuedSynchronizer,简称AQS。本篇文章将深入剖析AQS的工作原理和核心概念,以理解多线程同步的关键技术。
一、什么是AQS
AQS全称AbstractQueuedSynchronizer。JDK 1.5之前只有synchronized同步锁,并且效率并不高,因此并发大神Doug Lea在JDK 1.5的时候自己写了一套框架,希望能够成为高效率地实现大部分同步需求的基础,也就是我们现在熟知的AQS(队列同步器)。
AQS提供了一个同步器的框架,JUC包下大多数同步器都是围绕着AQS 使用的一组共同的基础行为(如等待队列、条件队列、独占或共享获取等)实现的,比如前边提到的ReentrantLock、CountDownLatch、Semaphore、FutureTask等,当然,我们也可以用AQS来构造出一个符合我们自己需求的同步器。
AQS支持两种同步方式:
- 独占式(Exclusive):同一时刻只能有一个线程持有同步资源或锁。当一个线程成功获取到锁时,其它线程就必须等待,直到持有锁的线程释放资源才能继续执行,比如ReentrantLock。
- 共享式(Shared):多个线程可以同时获取同一个同步资源或锁,从而实现并发方法。当一个线程获取到共享资源或锁后,其它线程仍然有机会获取资源,而不是被阻塞。比如CountDownLatch、Semaphore和CyclicBarrier就是一种共享锁。
二、AQS的常用方法与示例
AQS的设计是基于模板设计模式的,也就是说,使用者(子类)需要继承AQS并重写指定的方法,随后将同步器组合在自定义同步组件的实现中,并调用AQS提供的模板方法,而这些模板方法将会调用子类重写的方法。
2.1 可重写的方法
使用AQS的一般方式:
- 继承AQS并重写指定的方法。(无非是对于共享资源state的获取和释放)
- 将AQS组合在自定义同步组件中,并调用其模板方法,这些模板方法就会调用子类重写的方法,这是模板方法设计模式一个典型的应用。
需要注意的是,重写AQS指定方法的同时,需要使用同步器提供的下面三个方法来访问和修改同步状态:
- getState():获取当前同步状态。
- setState():设置当前同步状态。
- compareAndSetState(int expect,int update):使用CAS设置当前状态。
下面我们看看AQS定义的可重写的5个方法:
- protected boolean tryAcquire(int arg):独占式获取同步状态,试着获取,成功返回true,失败返回false。
- protected boolean tryRelease(int arg):独占式释放同步状态,等待获取同步状态的线程将有机会获取同步状态。
- protected int tryAcquireShared(int arg):共享式获取同步状态,返回小于0的值表示获取失败,反之成功。
- protected boolean tryReleaseShared(int arg):共享式释放同步状态,成功true,失败false。
- protected boolean isHeldExclusively():是否在独占模式下被线程占用。
看过我之前文章的同学,除了最后一个方法,其它的是不是都很熟悉但又有点“模糊”,那么今天我们就一探究竟😊,看看到底是怎么个事。
2.2 常用方法
实现自定义同步组件时,将会调用同步器提供的模板方法,如下(部分):
- void acquire(int arg):独占式获取同步状态,如果当前线程获取同步状态成功,则返回,否则将会进入同步队列等待,该方法会调用重写的tryAcquire(int arg)方法。
- void acquireInterruptibly(int arg):与acquire方法相同,但是该方法响应中断,若线程未获取同步状态进入到同步队列,如果当前线程中断,则会抛出InterruptedException。
- boolean tryAcquireNanos(int arg,long nanos):在acquireInterruptibly方法基础上增加了超时限制,如果超时,返回false,获取成功返回true。
- void acquireShared(int arg):共享式获取同步状态,如果为获取,将进入同步列等待,与独占式获取的主要区别在于同一时刻可以又多个线程获取到同步状态。
- boolean tryAcquireSharedInterruptibly(int arg):与acquireShared方法相同,可响应中断。
- boolean tryAcquireSharedNanos(int arg,long nanos):共享模式获取,可中断,并且有超时时间。
- boolean release(int arg):独占式释放同步状态,该方法会在释放同步状态之后,将同步队列中第一个节点包含的线程唤醒。
- boolean releaseShare(int arg):共享式获取同步状态。
- Collection<Thread> getQueuedThreads():获取等待在同步队列上的线程集合。
2.3 基于AQS实现Mutex锁(示例)
上面大概讲了一下AQS的使用方式和常用的一些方法,接下来就借用JDK 1.8官方文档 在介绍AQS类时,举的一个例子来进一步理解AQS。
public class Mutex implements Serializable {// 静态内部类,自定义同步器private static class Sync extends AbstractQueuedSynchronizer {// 是否处于占用状态protected boolean isHeldExclusively() {return getState() == 1;}// 当前状态为0的时候获取锁,CAS成功则将state修改为1public boolean tryAcquire(int acquires) {assert acquires == 1; // Otherwise unusedif (compareAndSetState(0, 1)) {setExclusiveOwnerThread(Thread.currentThread());return true;}return false;}// 释放锁,将同步状态设置为0protected boolean tryRelease(int releases) {assert releases == 1; // Otherwise unusedif (getState() == 0) {throw new IllegalMonitorStateException();}setExclusiveOwnerThread(null);setState(0);return true;}}//同步对象完成一系列复杂的操作,我们仅需指向它即可private final Sync sync = new Sync();//加锁,代理到acquire(模板方法)上,acquire会调用我们重现的tryAcquire方法public void lock() {sync.acquire(1);}public boolean tryLock() {return sync.tryAcquire(1);}//释放锁,代理到release(模板方法上),release会调用我们重写的tryRealease方法public void unlock() {sync.release(1);}public boolean isLocked() {return sync.isHeldExclusively();}
}
上述示例中,独占锁Mutex是一个自定义的同步器,它在同一时刻只允许一个线程占有锁。接下来我们就是用常见的i++例子来检验一下Mutex:
public class TestMutex {private static int i = 0;private static Mutex mutex = new Mutex();//使用自定义的Mutex进行同步处理的a++public static void increase() {mutex.lock();i++;mutex.unlock();}public static void main(String[] args) throws Exception {//启动十个线程,每个线程累加10000次for (int j = 0; j < 10; j++) {new Thread(() -> {for (int k = 0; k < 10000; k++) {increase();}}).start();}while (Thread.activeCount()>2){Thread.yield();}System.out.println(i);//100000}
}
每次测试i的结果都是预期的100000,说明我们成功地基于AQS实现了一个简单的Mutex锁。
三、设计思想
AQS的设计思想实际很简单,可以分为三部分:同步状态的原子性管理(state)、队列的管理(CLH变体队列)以及线程的阻塞和释放(LockSupport),下面我们就逐个介绍一下。
3.1 同步状态的管理(state)
每个AQS的子类都依赖于一个volitile修饰的状态变量(state),可以通过getstate、setState以及compareAndSetState等方法进行操作,这个变量可以用于表示任意状态,比如ReentrantLock用它表示拥有锁的线程重复获取该锁的次数,CountDownLatch用它表示计数器的数值,Semphore用它表示剩余的许可数量,FutureTask用它表示任务的状态(尚未开始、正在运行、已完成和已取消)。
3.2 队列的管理
AQS最核心的就是队列的管理。AQS内部维护了两个内部类,分别是Node类(构建同步队列)和ConditionObject类(条件队列)。
3.2.1 同步队列(CLH变体队列)
AQS的核心思想就是如果被请求的共享资源(state的状态)空闲,则将当前请求资源的线程设置为有效的工作线程,并将共享资源设置为锁定状态。如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制就是用CLH变体的虚拟双向队列实现的,即将暂时获取不到锁的线程加入到队列中。
我们先简单介绍下CLH队列:
CLH(Craig,Landin,and Hagersten——三个大佬的人名)队列,是单向链表实现的队列。申请线程只在本地变量上自旋,它不断轮询前驱的状态,如果发现前驱节点释放了锁就结束自旋。
暂时介绍这么多,今天我们的重点是AQS变体的CLH队列。
该队列由一个个Node节点组成,每个Node节点维护一个prev和next引用,分别指向自己的前驱和后继节点,AQS维护两个指针,指向队列头部head和尾部tail。
当线程获取资源失败时,就会构造成一个Node节点加入CLH变体队列中,同时当前线程会被阻塞在队列中(通过LockSupport.park实现)。当持有同步状态的线程释放同步状态时,会唤醒(通过LockSupport.unpark实现)后继节点,然后此节点线程继续加入到对同步状态的争夺中。
3.2.2 条件队列
AQS内部提供了一个ConditonObject类,给维护独占同步的类以及实现Lock接口的类使用。
但是,有了CLH变种队列为什么还要条件队列呢?
因为CLH变种队列仅能解决线程阻塞和唤醒的问题,并不能提供条件和通知的功能。
因此,AQS引入了ConditionObject条件队列的概念,提供了一种更加高级的线程协作机制,能够更方便地实现特定条件的等待和唤醒。ConditonObject基于CLH变种队列实现,提供了信号通知、重入、公平性等特性,同时在使用时也更加方便和易于维护。
JUC包下的许多同步组件比如ReentrantLock、CyclicBarrier、Semaphore等,都有ConditionObject的身影。总之ConditionObject和CLH变种队列相辅相成,提供了一个完整、高效且灵活的线程协作机制,能够更好地支持更高级的线程同步操作。
3.3 线程的阻塞和释放(LockSupport)
在JSR166之前,阻塞和释放线程都是基于Java内置管程,唯一的选择的是Thread.suspend和Thread.resume,但之前的文章也提到过,由于存在死锁的风险,这两个方法都被声明废弃了。即:如果两个线程同时持有一个线程对象,一个尝试去中断,一个尝试去释放,在并发情况下,无论调用时是否进行了同步,目标线程都存在死锁的风险——如果suspend()中的线程就是即将要执行resume()的那个线程,那肯定就要产生死锁了。
JUC包有一个LockSuport类,它提供了另一种安全和可控的线程挂起和唤醒机制,以避免出现死锁和其它潜在问题:
- 显式调用:使用LockSupport,线程的挂起和唤醒操作是显式的,需要开发者明确调用park和unpark方法。
- 无需持有锁:LockSupport的park方法不会持有任何锁对象,因此不会引发死锁。线程在调用park方法挂起时,不会影响其他线程对锁的获取和释放操作。
- 精确唤醒:LockSupport的unpark方法可以精确地唤醒指定的线程。与Thread的resume方法不同,unpark方法无需等待具体的操作,可以直接唤醒指定的线程。
- 无状态变更:LockSupport的park和unpark方法不会导致线程状态的不一致性或其他潜在的问题。线程在被唤醒后,可以正常继续执行,遵循同步规则。
四、acquire和release方法源码分析
AQS里面最重要的就是两个操作和一个状态,即获取操作(acquire)、释放操作(release)和同步状态(state)。获取和释放操作又分为独占式和共享式,这两种模式大同小异,所以今天就只对独占模式下的获取(acquire)和释放(release)操作进行分析。
4.1 相关属性
再介绍之前我们先看一下相关的属性
static final class Node {//表示共享模式static final Node SHARED = new Node();//表示独占模式static final Node EXCLUSIVE = null;//表示线程已取消:由于在同步队列中等待的线程等待超时或中断//需要从同步队列中取消等待,节点进入该状态将不会变化(即要移除/跳过的节点)static final int CANCELLED = 1;//表示后继节点处于park,需要唤醒:后继节点的线程处于park,而当前节点//的线程如果进行释放或者被取消,将会通知(signal)后继节点。static final int SIGNAL = -1;//表示线程正在等待状态:即节点在等待队列中,节点线程在Condition上,//当其他线程对Condition调用signal方法后,该节点会从条件队列中转移到同步队列中static final int CONDITION = -2;//表示下一次共享模式同步状态会无条件地传播下去static final int PROPAGATE = -3;//节点的等待状态,即上面的CANCELLED/SIGNAL/CONDITION/PROPAGATE,初始值为0volatile int waitStatus;//前驱节点volatile Node prev;//后继节点volatile Node next;//与当前节点关联的排队中的线程volatile Thread thread;//同步模式改变时下一个等待节点Node nextWaiter;//判断是否是共享模式,若是则返回truefinal boolean isShared() {return nextWaiter == SHARED;}//返回节点的前驱节点,如果为null,则抛NullPointerException异常final Node predecessor() throws NullPointerException {Node p = prev;if (p == null)throw new NullPointerException();elsereturn p;}//用于创建头节点或SHARED标记Node() { // Used to establish initial head or SHARED marker}Node(Thread thread, Node mode) { // Used by addWaiterthis.nextWaiter = mode;this.thread = thread;}Node(Thread thread, int waitStatus) { // Used by Conditionthis.waitStatus = waitStatus;this.thread = thread;}
}
//同步队列的头节点,使用懒加载的方式初始化,仅能通过setHead修改。
private transient volatile Node head;
//同步队列的尾节点,同样是懒加载。仅通过enq方法修改,用于添加新的等待节点
private transient volatile Node tail;
//volatile修饰的状态变量state
private volatile int state;
//返回当前同步状态
protected final int getState() {return state;
}
//设置同步状态值
protected final void setState(int newState) {state = newState;
}
//使用CAS修改同步状态值
protected final boolean compareAndSetState(int expect, int update) {// See below for intrinsics setup to support thisreturn unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
如上所说,Node类其实就是构成CLH变体队列的一个个节点。
4.2 acquire方法
4.2.1 acquire()
分析:获取同步状态(锁)。
- tryAcquire():调用的是子类重写的方法,若返回true,则表示获取同步状态成功,后面就不再执行,反之则进入下一步。
- 此时,获取同步状态失败,构造独占式同步节点,通过addWaiter方法(见下)将此节点添加到同步队列尾部,并调用acquireQueued(见下)方法尝试acquire。
- 最后,如果acquireQueued返回ture,则调用selfInterrupt方法中断当前线程。
4.2.2 addWaiter()
分析:根据当前线程和入参mode创建一个新Node,如果队列不为空则将Node设置为尾节点,反之则调用enq初始化队列并将node插入队列。
第一个红框:以当前线程和mode为参数,创建一个节点node,将pred赋值为当前尾节点。
第二个红框:pred不为空。
将新创建的节点的前驱节点设置为pre,即将创建的节点放到尾部。
使用CAS将尾节点修改为新节点。
若修改成功,则将pred的后继节点设置为新节点,并返回新节点node。
第三个红框:如果pred为空,则代表此时同步队列为空,调用enq方法(见下)将新节点添加到同步队列,并返回node。
4.2.3 enq()
分析:与上述的addWaiter方法相似,只是多了一个队列为空时,初始化head和tail的操作(懒加载)。
第一个红框:
将t赋值为尾节点。
如果尾节点为空,使用CAS将头节点赋值为一个新创建的无状态节点,并初始化尾节点。
第二个红框:如果尾节点不为空,使用CAS将当前node添加到尾节点。
将node节点的前驱节点设置为t。
使用CAS将尾节点设置为node。
若设置成功,则修改node为t的后继节点,返回t。
4.2.4 acquireQueued()
分析:添加完节点后,立即尝试该节点是否能成功acquire。
第一个红框:判断node节点的前驱节点p是否为头节点head,如果是则尝试acquire,若node成功acquire。则调用setHead方法将node设置为head、将node的Thread设置为null、将node的prev设置为null。将原头节点的next设置为null,也就是断开原head节点与node节点的关联,这就保证了头节点永远是一个不带Thread并且头节点的prev永远为null的空节点。
第二个红框:如果node节点的前驱节点不是head,或者node尝试acquire失败,则会调用shouldParkAfterFailedAcquire方法(见下)检验node是否需要park,如果返回true则调用parkAndCheckInterrupt方法(见下)将node的线程阻塞。
第三个红框:若failed为true,则代表出现了异常,调用cancelAcquire方法(见下)取消正在进行acquire的尝试。
4.2.5 shouldParkAfterFailedAcquire()
分析:判断节点是否需要park。
第一个红框:判断前驱节点的等待状态是否为SIGNAL,若是,则表示该node应该park,等待其它前驱节点来唤醒。(此时的pred是原节点的前驱节点)
第二个红框:
如果前驱节点的等待状态大于0,也就是CANCELLED状态,也就是此节点已经无效,则需要从后往前遍历,找到一个非CANCELLED状态的节点,并将自己设置为它的后继节点。
如果前驱节点的等待状态为其它状态,使用CAS尝试将pred节点的等待状态修改为SIGNAL,然后返回false。这就意味着再执行一次acquireQueued方法的第一个if,再次tryAcquire。
4.2.6 parkAndCheckInterrupt()
分析:直接调用LockSupport的park方法将当前线程阻塞,并在被唤醒之后,返回当前线程是否中断。
4.2.7 cancelAcquire()
分析:取消正在等待获取独占同步状态的线程。
第一个红框:首先判断传入的节点是否为空,为空就直接返回,不为空就将node的Thread设置为null。
第二个红框:如果node的前驱节点的等待状态为CANCELLED,则直接断开与该节点的联系。
第三个红框:拿到pred的后继节点predNext(不一定是node了),并将node的等待状态设置为CANCELLED。如果node为尾节点,则CAS将尾节点改为pred节点,也就是把pred后面的节点全部移除(包括node节点和node节点前面等待状态为CANCELLED的节点)。
第四个红框:后继节点的唤醒和更新
(判断当前节点是否为头节点)&&((获取node的前驱节点的等待状态赋值给ws并判断其等待状态是否为SIGNAL)||(判断ws是否是除CANCELLED状态之外的状态 && 如果是则将其状态设置为SIGNAL ))&& 判断node的前驱节点的线程是否不为null
如果上述条件都满足,获取当前节点的后继节点next,如果next不为空且等待状态不为CANCELLED,则将前驱节点的后继节点设置为后继节点的后继节点,即跳过当前节点,因为只有pred的等待状态为SIGNAL才能走到这边,因此node的后继节点无需唤醒。
反之,如果pred节点无法提供给node的后继节点信息,则直接唤醒node的后继节点(调用unparkSuccessor方法(见下))。
最后置空当前节点的引用,便于垃圾回收。
4.2.8 unpakSuccessor()
分析:唤醒node节点的后继节点
第一个红框:将node节点的等待状态赋值给ws,如果ws小于0(即等待状态不是CANCELLED),则将ws的等待状态置为0(初始状态因为马上要将node的后继节点唤醒)。
第二个红框:将node节点的后继节点赋值给s,如果s==null或者s的等待状态为CANCELLED,则直接将s置空,并从队列尾部向前遍历,找到等待状态不是CANCELLED的节点t(离node最近的节点),并将其赋值给s。这里的意思就是将node之后的空节点或等待状态为CANCELLED的节点也一并去掉,直接唤醒node之后等待状态不为CANCELLED的节点。
第三个红框:如果s!=null,则执行LockSupport.unpark(s.thread)唤醒s节点。
4.3 release()方法
分析:释放同步状态。
tryRelease():首先调用子类重写的tryRelease()方法,尝试释放锁。
如果tryRelease()成功即释放锁成功,并且head节点不为空且等待状态不是初始状态,则调用unparkSuccessor方法(见4.2.8)唤醒head节点的后继节点。
4.4 acquire方法总结
release方法简单没什么好总结的,这里就总结一下acquire方法。
- 首先,acquire方法会调用tryAcquire方法尝试直接获取锁。这个方法是由子类实现的,用于决定是否允许当前线程获取锁。如果tryAcquire方法成功获取了锁,就直接返回。
- 如果tryAcquire方法无法直接获取锁,当前线程会通过调用addWaiter方法将该线程添加到等待队列中,如果队列不为空则将node放置队列尾部,如果为空则调用enq方法初始化队列,并放置队列尾部。
- 接下来会调用acquireQueued方法,线程进入自旋状态,期间会不断尝试获取锁。首先会检查该节点的前驱节点是否为head节点,如果是则意味着当前节点是老二节点,可以再次调用tryAcquire方法尝试获取锁,如果获取锁成功,那么它将成为head节点,并将head节点的前驱节点置为null。如果不是头节点或者获取锁失败,则会调用shouldParkAfterFailedAcquire方法判断当前是否需要park。
- 如果在acquireQueued中发生异常,则会执行cancelAcquire方法取消正在等待获取独占同步状态的线程。
- 最后如果acquireQueued方法返回true,则调用selfInterrupt方法中断当前线程,这是因为返回ture就代表线程被中断。
End:希望对大家有所帮助,如果有纰漏或者更好的想法,请您一定不要吝啬你的赐教🙋。
相关文章:

Java并发编程第11讲——AQS设计思想及核心源码分析
Java并发包(JUC)中提供了很多并发工具,比如前面介绍过的ReentrantLock、ReentrantReadWriteLock、CountDownLatch、Semaphore、FutureTask等锁或者同步部件,它们的实现都用到了一个共同的基类——AbstractQueuedSynchronizer&…...

什么是数据库?数据库有哪些基本分类和主要特点?
数据库是以某种有组织的方式存储的数据集合。本文从数据库的基本概念出发,详细解读了数据库的主要类别和基本特点,并就大模型时代备受瞩目的数据库类型——向量数据库进行了深度剖析,供大家在了解数据库领域的基本概念时起到一点参考作用。 …...

flutter显示出底部控件的引导页
需求:同一个页面的两个不同的入口,同一个控件的位置有变化,显示引导页时对应这个控件的引导内容的位置也需要改变;同时半透明底部显示出真实的页面内容。 这样的需要如果切图然后再往页面上贴位置无法精确的对准。 思路࿱…...

常用设计模式——模板方法模式
什么是模板方法模式 模板方法模式:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 主要解决:一些方法通用,却要在每一个子类都重写这些方法…...

idea使用git删除本地提交(未推送)
1、找到reset head 2、打开弹窗,在HEAD后面输入^ 结果为HEAD^ 注释: Reset Type 有三种: Mixed(默认方式),保留本地源码,回退 commit 和 index 信息,最常用的方式Soft 回退到某个版本…...

centos 7部署Mysql8.0主从
Mysql官网中关于部署主从的网址 环境准备: 搭建虚拟机和安装Mysql之前的文章中已经涉及,在此不再赘述。 主从IPMysql账号密码主192.168.213.4root/Root1234!从192.168.213.5root/Root1234! 1、主数据库设置 配置my.cnf 一般存放于/etc/。 主从配…...

asp.net docker-compose添加es search
打开docker-compose.yml添加 es-search:image: docker.elastic.co/elasticsearch/elasticsearch:7.17.14 打开docker-compose.override.yml添加 es-search:volumes:- data01:/usr/share/elasticsearch/dataports:- 9200:9200 docker集群中添加es search成功...

工业路由器网关的网络协议之NAT技术
在物联网通讯领域,NAT技术能将内网的一个私有IP转换成一个公网IP去接入互联网,解决组建局域网络时私有IP地址无法在公网上进行路由的问题。 NAT(Network Address Translation)的三种方式: 静态NAT 1、一个私有IP对应…...

【亲测可用】SpringBoot使用Redis的Lettuce连接池报RedisCommandTimeoutException
目录 一、问题详情 二、根本原因 三、解决方案 一、问题详情 在最近新项目的开发当中,当项目刚启动的时候访问Redis服务一切正常,但是过了几分钟后再次访问Redis就报如下错误。 Redis command timed out; nested exception is io.lettuce.core.RedisCommandTimeoutExcept…...

When Urban Region Profiling Meets Large Language Models
本文是LLM系列文章,针对《When Urban Region Profiling Meets Large Language Models》的翻译。 当城市区域轮廓遇到大型语言模型时 摘要1 引言2 前言3 方法4 实验5 结论与未来工作 摘要 基于网络数据的城市区域概况对城市规划和可持续发展至关重要。我们见证了LL…...

【python】最大的偶数
题目: """ 给出一个由非负整数组成的序列 A (A1,A2,A3,....,Av)。这个序列的长度为N判断是否存在一个偶数可以表示为在A中两个不同元素的和。若存在,找到最大的偶数,否则输出”-…...

QT 实现两款自定义的温度计/湿度控件
文章目录 0 引入1、带有标尺的温度/湿度计控件1.头文件2.核心代码 2、竖起来的温度/湿度计控件1.头文件2.实现 3、引用 0 引入 QT原生控件没有实现如仪表盘或者温度计的控件,只好自己实现,文章代码部分参考引用的文章。直接上图 图一 带有标尺的温度计…...
Fourier分析导论——第4章——Fourier级数的一些应用(E.M. Stein R. Shakarchi)
第 4 章 傅里叶级数的一些应用 Fourier series and analogous expansions intervene very naturally in the general theory of curves and surfaces. In effect, this theory, conceived from the point of view of analysis, deals obviously with the study of arbitra…...

c语言使用fdk_aac库对aac音频解码为pcm
//示例为adts的aac流数据(adts数据可以每一包都可以独立解析不需要拼凑) //解码数据的采样率同解码前的采样率,如果不满足需求,需要对数据进行重采样 #include <aacdecoder_lib.h>int m_fd -1; int m_fd2 -1;void aac2pc…...

zustand管理工具--React
npm i zustand 1.函数参数必须返回一个对象 对象内部编写状态数据和方法 2.set是用来修改数据的专门方法必须调用它来修改数据 import { useEffect } from "react"; import { create } from "zustand";// 1. 创建store const goodsStore create((set) …...

Elasticsearch内存分析
文章目录 Elasticsearch JVM内存由哪些部分组成Indexing BufferNode Query CacheShard Request CacheField Data CacheSegments Cache查询 非堆内存内存压力mat分析es的jvm缓存监控 Elasticsearch JVM内存由哪些部分组成 官方建议Elasticsearch设置堆内存为32G,因为…...

Alert警告提示(antd-design组件库)简单使用
1.Alert警告提示 警告提示,展现需要关注的信息。 2.何时使用 当某个页面需要向用户显示警告的信息时。 非浮层的静态展现形式,始终展现,不会自动消失,用户可以点击关闭。 组件代码来自: 警告提示 Alert - Ant Design 3…...

Linux提权方法总结
1、内核漏洞提权 利用内核漏洞提取一般三个环节:首先对目标系统进行信息收集,获取系统内核信息及版本信息 第二步,根据内核版本获取对应的漏洞以及exp 第三步,使用exp对目标进行攻击,完成提权 注:此处可…...

力扣第300题 最长递增子序列 c++ 动态规划题 附Java代码
题目 300. 最长递增子序列 中等 相关标签 数组 二分查找 动态规划 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例…...

Si3262 集成低功耗SOC 三合一智能门锁应用芯片
Si3262 是一款G度集成的低功耗 SOC 芯片,其集成了基于 RISC-V 核的低功耗MCU 和工作在 13.56MHz 的非接触式读写器模块。 读写器模块支持 ISO/IEC 14443 A/B/MIFARE 协议,支持自动载波侦测功能(ACD)。无需外W其他电路,…...

linux rsyslog介绍
Rsyslog网址:https://www.rsyslog.com/ Rsyslog is the rocket-fast system for log processing. It offers high-performance, great security features and a modular design. While it started as a regular syslogd, rsyslog has evolved into a kind of swis…...

项目部署之安装和配置Canal
1.Canal介绍 Canal是阿里巴巴的一个开源项目,基于java实现,整体已经在很多大型的互联网项目生产环境中使用,包括阿里、美团等都有广泛的应用,是一个非常成熟的数据库同步方案,基础的使用只需要进行简单的配置即可。 …...

基于Skywalking的全链路跟踪实现
在前文“分布式应用全链路跟踪实现”中介绍了分布式应用全链路跟踪的几种实现方法,本文将重点介绍基于Skywalking的全链路实现,包括Skywalking的整体架构和基本概念原理、Skywalking环境部署、SpringBoot和Python集成Skywalking监控实现等。 1、Skywalki…...

Spark Core
Spark Core 本文来自 B站 黑马程序员 - Spark教程 :原地址 第一章 RDD详解 1.1 为什么需要RDD 分布式计算需要 分区控制shuffle控制数据存储、序列化、发送数据计算API等一系列功能 这些功能,不能简单的通过Python内置的本地集合对象(如…...

[算法日志]图论: 广度优先搜索(BFS)
[算法日志]图论: 广度优先搜索(BFS) 广度优先概论 广度优先遍历也是一种常用的遍历图的算法策略,其思想是将本节点相关联的节点都遍历一遍后才切换到相关联节点重复本操作。这种遍历方式类似于对二叉树节点的层序遍历,即先遍历完子节点后…...

Xilinx FPGA SPIx4 配置速度50M约束语句(Vivado开发环境)
qspi_50m.xdc文件: set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design] set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design] set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design] set_property CONFIG_VOLTAGE 3.3 [curren…...

Linux Shell和权限
目录 Shell命令及运行原理 权限 1.文件基本属性 2.文件权限值的表示方法 3.文件访问权限的相关设置方法 3.(1)chmod 组名修改 3.(2)chmod 二进制修改 3.(3)chown 3.(4)chgrp 3.(5)umask 4.目录权限 Shell命令及运行原理 Linux的操作系统,狭义上是…...

Git同时配置Gitee和GitHub
Git同时配置Gitee和GitHub 一、删除原先ssh密钥二、生成密钥 这里的同时配置是针对于之前配置过单个gitee或者github而言的,如果需要看git从安装开始的配置,则可以看这一篇文章 git安装配置教程 一、删除原先ssh密钥 在C盘下用户/用户名/.ssh文件下找到…...

IGP高级特性简要介绍(OSPF-上篇)
OSPF高级特性 一、OSPF_提升故障收敛及网络恢复速度 1.FRR与BFD快速恢复故障 1.1 FRR 在传统转发模式下,当到达同一个目的网络存在多条路由时,路由器总是选择最优路由使用,并且下发到FIB表指导数据转发。 当最优路由故障时,需…...

Oracle-Ogg集成模式降级为经典模式步骤
前言: Ogg集成模式降级为经典模式的场景比较少,因为降级为经典模式会导致无法支持压缩表同步,XA事务,多线程模式,PDB模式同步等功能,除非遇到集成模式暂时无法解决的bug或者环境不支持集成模式,比如DG备库环…...