Java ~ Collection/Executor ~ DelayQueue【总结】

news2024/9/22 17:29:40

前言


 文章

  • 相关系列:《Java ~ Collection【目录】》(持续更新)
  • 相关系列:《Java ~ Executor【目录】》(持续更新)
  • 相关系列:《Java ~ Collection/Executor ~ DelayQueue【源码】》(学习过程/多有漏误/仅作参考/不再更新)
  • 相关系列:《Java ~ Collection/Executor ~ DelayQueue【总结】》(学习总结/最新最准/持续更新)
  • 相关系列:《Java ~ Collection/Executor ~ DelayQueue【问题】》(学习解答/持续更新)
  • 涉及内容:《Java ~ Collection【总结】》
  • 涉及内容:《Java ~ Collection ~ Queue【总结】》
  • 涉及内容:《Java ~ Collection ~ PriorityQueue【总结】》
  • 涉及内容:《Java ~ Collection/Executor ~ BlockingQueue【总结】》
  • 涉及内容:《Java ~ Executor【总结】》
  • 涉及内容:《Java ~ AQS ~ ReentrantLock【总结】》
  • 涉及内容:《Java ~ Other ~ Delayed【总结】》
  • 涉及内容:《Java ~ Other ~ Comparable【总结】》

一 概述


 简介

    DelayQueue(延迟队列)类是BlockingQueue(阻塞队列)接口的实现类之一,基于数组实现,特点是元素会被延迟头部移除。延迟队列类不支持任意类型的元素,其元素被强制指定为Delayed(延迟)接口对象,即延迟接口实现类对象,否则会抛出类型转换异常。之所以强制类型是因为延迟队列会调用延迟接口定义的getDelay(TimeUnit unit)方法来获取元素的剩余延迟来实现精确延迟,因此延迟接口实现类必须实现该方法以返回有效的剩余延迟。除此之外,由于底层使用PriorityQueue(优先级队列)类的原因,延迟接口实现类还必须实现Comparable(比较能力)接口定义的compareTo(T o)方法以实现元素之间剩余延迟时间的比较,该知识点的详细内容会在下文详述。

    延迟队列类不允许存null值,或者说阻塞队列接口的所有实现类都不允许存null值。null被作为poll()及peek()方法表示延迟队列不存在元素的标记值,因此所有阻塞队列接口实现类都不允许存null值。

    延迟队列类是无界队列,意味着其最大容量理论上只受限于堆内存的大小。延迟队列类底层使用优先级队列类实现,由于其扩容机制的存在,延迟队列类也被纳入无界队列的范围中。但虽说如此,优先级队列类在实现中还受到数组实现与int类型影响,因此延迟队列的最大容量实际上为Integer.MAX_VALUE。由于其无界队列的定义,为了掩盖实际实现中受到的限制,当其保存的元素总数触达上限时会模拟堆内存不足的场景手动抛出内存溢出错误。

    延迟队列类是线程安全的,或者说阻塞队列接口的所有实现类都是线程安全的,其接口定义中强制要求实现类必须线程安全。延迟队列类采用“单锁”线程安全机制,即使用一个ReentrantLock(可重入锁)类对象来保证整体的线程安全。

    延迟队列类的迭代器是弱一致性,即可能迭代到已移除的元素及无法迭代到新插入的元素。延迟队列的迭代器实现非常直接(或者说过于直接了),其会直接将数据拷贝一份快照存入生成的迭代器中以进行迭代。这么做的好处是迭代器的实现非常的简单,但缺点也明显,当延迟队列的元素总数较大或生成的迭代器数量较多时对内存的消耗会非常严重。

    延迟队列类虽然与阻塞队列接口一样都被纳入Executor(执行器)框架的范畴,但同时也是Collection(集)框架的成员。

 结构

在这里插入图片描述

 方法的不同形式

    方法的不同形式实际上是BlockingQueue(阻塞队列)接口的定义,链接阻塞双端队列只是继承了这个定义而已。所谓方法的不同形式,是指方法在保证自身核心操作不变的情况下实现了多种不同的回应形式来应对不同场景下的使用要求。例如对于插入,当容量不足时,有些场景希望在失败时抛出异常;而有些场景则希望能直接返回失败的标记值;而有些场景又希望可以等待直至有可用空间后成功新增为止…正因如此,BlockingQueue(阻塞队列)接口特意提供了四种不同的形式风格以满足不同场景下的使用需求,因此一个方法最多(并非所有方法都实现了四种形式)可能有四种不同回应形式。具体四种回应形式如下:

异常 —— 队列接口定义 —— 当不满足操作条件时直接抛出异常;
特殊值 —— 队列接口定义 —— 当不满足操作条件时直接返回失败标记值。例如之所以不允许存null值就是因为null被作为了操作失败时的标记值;
阻塞(无限等待) —— 阻塞队列接口定义 —— 当不满足操作条件时无限等待,直至满足操作条件后执行;
超时(有限等待) —— 阻塞队列接口定义 —— 当不满足操作条件时有限等待,如果在指定等待时间之前满足操作条件则执行;否则返回失败标记值。

二 创建


  • public DelayQueue() —— 创建延迟队列。

  • public DelayQueue(Collection<? extends E> c) —— 创建按迭代器顺序包含指定集中所有元素的延迟队列。

三 方法


    需要提前说明的是:本文中的元素与延迟到期元素在概念上并不相同,元素指延迟队列中的所有元素,而延迟到期元素指的是延迟队列中已延迟到期的元素,因此延迟到期元素是元素的子集,在下文中要时刻注意这两者的区别。

 插入

  • public boolean add(E e) —— 新增 —— 向当前延迟队列的尾部插入指定元素,并根据指定元素的剩余延迟按小顶堆规则将之排序到合适位置。该方法是尾部插入方法“异常”形式的实现,当当前延迟队列存在剩余容量时插入并返回true;否则抛出非法状态异常。虽说定义如此,但实际由于延迟队列类是真正的无界队列,最大容量只受限于堆内存的大小,故而永远不会抛出非法状态异常,而只会在堆内存不足时抛出内存溢出错误。由于延迟队列类基于优先级队列类实现,因此最大容量实际还受限于Integer.MAX_VALUE。当元素总数触达该上限时,为了掩盖实际实现上的限制,会手动抛出内存溢出错误。

  • public boolean offer(E e) —— 提供 —— 向当前延迟队列的尾部插入指定元素,并根据指定元素的剩余延迟按小顶堆规则将之排序到合适位置。该方法是尾部插入方法“特殊值”形式的实现,当当前延迟队列存在剩余容量时插入并返回true;否则返回false。虽说定义如此,但实际由于延迟队列类是真正的无界队列,最大容量只受限于堆内存的大小,故而永远不会抛出非法状态异常,而只会在堆内存不足时抛出内存溢出错误。由于延迟队列类基于优先级队列类实现,因此最大容量实际还受限于Integer.MAX_VALUE。当元素总数触达该上限时,为了掩盖实际实现上的限制,会手动抛出内存溢出错误。

  • public void put(E e) —— 放置 —— 向当前延迟队列的尾部插入指定元素,并根据指定元素的剩余延迟按小顶堆规则将之排序到合适位置。该方法是尾部插入方法“阻塞”形式的实现,当当前延迟队列存在剩余容量时插入;否则无限等待至存在剩余容量为止。虽说定义如此,但实际由于延迟队列类是真正的无界队列,最大容量只受限于堆内存的大小,故而永远不会抛出非法状态异常,而只会在堆内存不足时抛出内存溢出错误。由于延迟队列类基于优先级队列类实现,因此最大容量实际还受限于Integer.MAX_VALUE。当元素总数触达该上限时,为了掩盖实际实现上的限制,会手动抛出内存溢出错误。

  • public boolean offer(E e, long timeout, TimeUnit unit) —— 提供 —— 向当前延迟队列的尾部插入指定元素,并根据指定元素的剩余延迟按小顶堆规则将之排序到合适位置。该方法是尾部插入方法“超时”形式的实现,当当前延迟队列存在剩余容量时插入并返回true;否则在指定等待时间内有限等待至存在剩余容量为止,超出指定等待时间则返回false。虽说定义如此,但实际由于延迟队列类是真正的无界队列,最大容量只受限于堆内存的大小,故而永远不会抛出非法状态异常,而只会在堆内存不足时抛出内存溢出错误。由于延迟队列类基于优先级队列类实现,因此最大容量实际还受限于Integer.MAX_VALUE。当元素总数触达该上限时,为了掩盖实际实现上的限制,会手动抛出内存溢出错误。

 移除

  • public E remove() —— 移除 —— 从当前延迟队列的头部移除并获取剩余延迟最小的延迟到期元素,并触发后续元素的重排序。该方法是头部移除方法“异常”形式的实现,当当前延迟队列存在延迟到期元素时移除并返回头延迟到期元素;否则抛出无元素异常。
        延迟队列类并没有自实现remove()方法,而是直接使用了父类AbstractQueue(抽象队列)抽象类的实现。在实现中其调用了头部移除方法“特殊值”形式的poll()方法来达成目的,使得所有抽象队列抽象类的子类只需实现poll()方法后就可以正常调用remove()方法。这种代码结构是设计模式的一种,被称为“模板模式”。
/**
 * Retrieves and removes the head of this queue.  This method differs from {@link #poll poll} only in that it throws an exception if this queue is empty.
 * 检索并移除队列的头。该方法不同于poll()方法,如果队列为空时其会抛出一个异常。
 * <p>
 * This implementation returns the result of <tt>poll</tt> unless the queue is empty.
 * 除非队列为空,否则该实现返回poll()的结果。
 *
 * @return the head of this queue 队列的头(元素)
 * @throws NoSuchElementException if this queue is empty
 *                                无元素异常:如果队列为空
 */
public E remove() {
    // 调用poll()方法获取元素。
    E x = poll();
    if (x != null)
        // 如果元素存在,直接返回。
        return x;
    else
        // 如果元素不存在,抛出无元素异常。
        throw new NoSuchElementException();
}
  • public E poll() —— 轮询 —— 从当前延迟队列的头部移除并获取剩余延迟最小的延迟到期元素,并触发后续元素的重排序。该方法是头部移除方法“特殊值”形式的实现,当当前延迟队列存在延迟到期元素时移除并返回头延迟到期元素;否则返回null。

  • public E take() throws InterruptedException —— 拿取 —— 从当前延迟队列的头部移除并获取剩余延迟最小的延迟到期元素,并触发后续元素的重排序。该方法是头部移除方法“阻塞”形式的实现,当当前延迟队列存在延迟到期元素时移除并返回头延迟到期元素;否则无限等待至存在延迟到期元素为止。

  • public E poll(long timeout, TimeUnit unit) throws InterruptedException —— 轮询 —— 从当前延迟队列的头部移除并获取剩余延迟最小的延迟到期元素,并触发后续元素的重排序。该方法是头部移除方法“超时”形式的实现,当当前延迟队列存在延迟到期元素时移除并返回头延迟到期元素;否则在指定等待时间内有限等待至存在延迟到期元素为止,超出指定等待时间则返回null。

  • public boolean remove(Object o) —— 移除 —— 从当前延迟队列中按迭代器顺序移除首个指定元素,成功则返回true;否则返回false。注意是元素,而非延迟到期元素。
        由于指定元素可能处于任意位置(不一定是头/尾),因此被称为内部移除。内部移除并不是常用的方法:一是其不符合FIFO的数据操作方式;二是各类实现为了提高性能可能会使用各种优化策略,而remove(Object o)方法往往无法适配这些策略,导致性能较/极差。

  • public void clear() —— 清理 —— 从当前延迟队列中移除所有元素。注意是元素,而非延迟到期元素。

 检查

  • public E element() —— 元素 —— 从当前延迟队列的头部获取剩余延迟最小的元素。该方法是头部检查方法“异常”形式的实现,当当前延迟队列存在元素时返回头元素;否则抛出无元素异常。注意该方法不同于头部移除方法,其获取的是元素而非延迟到期元素,因此即使头元素延迟尚未到期也会将之返回,故而只会在延迟队列为空时抛出无元素异常。
        与remove()方法相同,延迟队列类并没有自实现element()方法,而是直接使用了父类AbstractQueue(抽象队列)抽象类的实现(具体源码如下)。在实现中其调用了检查方法“特殊值”形式的peek()方法来达成目的,使得所有抽象队列抽象类的子类只需实现peek()方法后就可以正常调用element()方法。这种代码结构是设计模式的一种,被称为“模板模式”。
/**
 * Retrieves, but does not remove, the head of this queue. This method differs from {@link #peek peek} only in that it throws an exception if this
 * queue is empty.
 * 检索,但不移除队列的头(元素)。该方法不同于peek()方法,如果队列为空时其会抛出一个异常。
 * <p>
 * This implementation returns the result of <tt>peek</tt> unless the queue is empty.
 * 除非队列为空,否则该实现返回peek()的结果。
 *
 * @return the head of this queue 队列的头(元素)
 * @throws NoSuchElementException if this queue is empty
 *                                无元素异常:如果队列为空
 * @Description: 元素:用于返回队列的头元素(但不移除)。当队列中不存在元素时抛出无元素异常。
 */
public E element() {
    E x = peek();
    if (x != null)
        return x;
    else
        throw new NoSuchElementException();
}
  • public E peek() —— 窥视 —— 从当前延迟队列的头部获取剩余延迟最小的元素。该方法是头部检查方法“特殊值”形式的实现,当当前延迟队列存在元素时返回头元素;否则返回null。注意该方法不同于头部移除方法,其获取的是元素而非延迟到期元素,因此即使头元素延迟尚未到期也会将之返回,故而只会在延迟队列为空时抛出无元素异常。

 流失

  • public int drainTo(Collection<? super E> c) —— 流失 —— 将当前延迟队列中的所有延迟到期元素流失到指定集中,并返回流失的延迟到期元素总数。被流失的延迟到期元素将不再存在于当前延迟队列中。

  • public int drainTo(Collection<? super E> c, int maxElements) —— 流失 —— 将当前延迟队列中最多指定数量的延迟到期元素流失到指定集中,并返回流失的延迟到期元素总数。被流失的延迟到期元素将不再存在于当前延迟队列中。

 查询

  • public int size() —— 大小 —— 获取当前延迟队列的元素总数。注意是元素,而非延迟到期元素。

  • boolean isEmpty() —— 是否为空 —— 判断当前延迟队列是否为空,是则返回true;否则返回false。

  • public int remainingCapacity() —— 剩余容量 —— 获取当前延迟队列的剩余容量。由于延迟队列类是无界队列,因此该方法将永远返回Integer.MAX_VALUE。

  • public Object[] toArray() —— 转化数组 —— 获取按迭代器顺序包含当前延迟队列中所有元素的新数组。注意是元素,而非延迟到期元素。

  • public <T> T[] toArray(T[] a) —— 转化数组 —— 获取按迭代器顺序包含当前延迟队列中所有元素的泛型数组。如果参数泛型数组长度足以容纳所有元素,则令之承载所有元素后返回。并且如果参数泛型数组的长度大于当前延迟队列的元素总数,则将已承载所有元素的参数泛型数组的size索引位置设置为null,表示从当前延迟队列中承载的元素到此为止。当然,该方案只对不允许保存null元素的集有效。如果参数泛型数组的长度不足以承载所有元素,则重分配一个相同泛型且长度与当前延迟队列元素总数相同的新泛型数组以承载所有元素后返回。注意是元素,而非延迟到期元素。

 迭代器

  • public Iterator iterator() —— 迭代器 —— 创建可遍历当前延迟队列中元素的迭代器。注意是元素,而非延迟到期元素。

    事实上,上文中只列举了大部分常用方法。由于延迟队列类是集接口的实现类,因此其也实现了其定义的所有方法,例如contains(Object o)、removeAll(Collection<?> c)、containsAll(Collection<?> c)等。但由于这些方法的执行效率不高,并且与延迟队列类的主流使用方式并不兼容/兼容性差,因此通常是不推荐使用的,有兴趣的童鞋可以去查看源码实现。

四 实现


 元素

    延迟队列类强制元素必须是延迟接口类型,即元素必须是延迟接口实现类对象。如此设计的原因是因为延迟队列类会调用延迟接口定义的getDelay(TimeUnit unit)方法来获取元素的剩余延迟来实现精确延迟,因此元素类必须实现该方法以返回有效的剩余延迟。除此之外,元素类还必须实现比较能力接口定义的compareTo(T o)方法以实现元素剩余延迟的比较,即元素类必须在compareTo(T o)方法中调用getDelay(TimeUnit unit)方法来比较两个元素剩余延迟的大小,这与延迟队列类底层使用优先级队列类实现有关。

    元素只有在延迟到期的情况下才允许被头部移除,即只有延迟到期元素才能被头部移除,这是实现延迟队列类的核心操作。所谓的延迟到期是指元素的剩余延迟小于等于0,小于0是因为元素在延迟过期后未能被实时的头部移除。当移除者(执行移除方法的线程)到来时,该延迟到期元素可被直接头部移除;而对于尚未延迟到期的元素,则移除者必须等待其延迟到期后方可头部移除。

 优先级队列

    延迟队列类自身没有实现相关的数据模型,其底层使用优先级队列类实现。优先级队列类不是常规的FIFO实现,元素在内部会根据剩余延迟按小顶堆的规则进行排序。在延迟队列类的实现中,会将剩余延迟最小的元素排序在优先级队列的头部,即头元素,表示其获得了最高的优先级。这便是元素类必须在compareTo(T o)方法中实现剩余延迟比较的根本原因,因为比较是排序的基本条件。

    当移除者到来时,会先获取底层优先级队列的头元素并判断。如果头元素不存在,说明延迟队列中没有可头部移除的延迟到期元素,令当前移除者进入有限/无限等待状态(具体视执行的头部移除方法的形式而定);如果头元素存在且延迟到期,说明延迟队列中存在可头部移除的延迟到期元素,当前移除者可直接将之从底层优先级队列中头部移除,并唤醒一个等待中的移除者(如果存在的话)对底层优先级队列的后续头元素进行头部移除(能否移除成功视底层优先级队列后续头元素是否延迟到期而定);而如果头元素存在但尚未延迟到期,则这是最复杂的情况,需要继续判断领导者是否存在。如果领导者存在,令当前移除者进入有限/无限等待状态;如果领导者不存在,则将当前移除者设置为领导者,并令之进入专属有限等待状态,即其等待时间与头元素的剩余延迟相同。

    以上是头部移除方法“阻塞”形式的流程,其它形式的流程与之大致相同,但会根据实际需求进行调整。

 领导者

    所谓领导者,本质是专属等待底层优先级队列头元素延迟到期的移除者,确保头元素在延迟到期时可被实时头部移除,以实现精确延迟。延迟队列类使用了领导者 - 追随者模式的变种模式以实现最大限度的减少非必要等待。即当一个移除者成为领导者后,会专属等待底层优先级队列的头元素延迟到期,而其它移除者则会进入有限/无限等待状态,从而避免大量移除者定时等待同一个头元素的情况。当领导者超时唤醒后,此时的头元素也已经延迟到期而成为了延迟到期元素,允许被头部移除。成功执行头部移除的领导者在结束之前需要唤醒一个等待中的移除者,以期望其对底层优先级队列的后续头元素进行专属等待(如果后续头元素存在且未延迟到期),即成为新的领导者(不一定能成功,因为存在并发竞争)。

在这里插入图片描述

    领导者无法保证在头元素延迟到期后必然将之头部移除。由于等待时间与头元素的剩余延迟相同,领导者基本可以在头元素延迟到期的同时因为超时而唤醒,从而实时头部移除已成为延迟到期元素的头元素。但这并不是必然的,由于程序运行时间消耗、CPU时间片分配、新移除者的外部竞争及其它定时移除者的内部竞争等原因,领导者无法保证必然将头元素头部移除,甚至无法保证自身是因超时而唤醒。典型的场景是:头元素延迟到期,但领导者由于上述列举的各项原因尚未因超时而唤醒。而此时恰好有新移除者成功头部移除了头元素并对领导者发送了信号,使得领导者并非因为等待超时而唤醒。头部移除头延迟到期元素失败的领导者根据头部移除方法的形式及程序的运行状态,会进行再次等待或返回null。

    领导者可能在其定时等待期间被撤销。这是可以预想到的,因为领导者是专属等待底层优先级队列头元素延迟到期的线程,因此如果在等待期间底层优先级队列头元素发生改变,例如尾部插入了一个剩余延更小的元素而将之排序成为新头元素,则该领导者就失去了精确等待的作用(因为其等待时间与新头元素的剩余延迟未必相同),需要将之撤销。撤销后的领导者会唤醒一个等待中的移除者(可能是自己,因为其自身也在等待,也可能是其它移除者),以期望其对底层优先级队列的新头元素进行专属等待,即成为新的领导者(不一定能成功,因为存在并发竞争)。因此,移除者必须准备好在等待过程中获得/失去领导地位。

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

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

相关文章

【玩转Python系列】【小白必看】使用Python爬取双色球历史数据并可视化分析

文章目录 前言导入库![在这里插入图片描述](https://img-blog.csdnimg.cn/05ab496a2ac045e6ad0b175292462fac.png)发送请求给指定网址伪装自己发送请求并获取响应设置编码解析HTML并获取结果创建CSV文件并写入数据打印输出结果加载自定义字体绘制折线图完整代码 结束语 前言 本…

(学习笔记)matplotlib.pyplot模块下基本画图函数的整理

matplotlib版本&#xff1a;3.7.1 python版本&#xff1a;3.10.12 基本函数 matplotlib版本&#xff1a;3.7.1python版本&#xff1a;3.10.12 1. plt.plot()函数1.1 plt.plot(x, y)1.2 plt.plot(x, y, **kwargs) 2. plt.xlable(), plt.ylable()3. plt.title()4. plt.show()5.p…

Pytorch(二)

一、分类任务 构建分类网络模型 必须继承nn.Module且在其构造函数中需调用nn.Module的构造函数无需写反向传播函数&#xff0c;nn.Module能够利用autograd自动实现反向传播Module中的可学习参数可以通过named_parameters()返回迭代器 from torch import nn import torch.nn.f…

如何注册Ddns域名?用快解析新手也可以轻松搞定!

对于每一个上网的朋友来说&#xff0c;如果平时经常需要访问外网&#xff0c;就需要用到Ddns域名了&#xff0c;不过这个域名的注册比较麻烦&#xff0c;也没有那么容易&#xff0c;因此很多朋友对此也有很多的疑惑。那么&#xff0c;Ddns域名注册怎么操作呢&#xff1f;其实利…

直流电机的系统辨识——LZW

前言 本文采用基于最小二乘的线性辨识方法和基于Nonlinear ARX模型的非线性辨识方法对图1所示的直流电机进行系统辨识&#xff0c;并分别设计H∞控制器&#xff0c;分析比较控制效果。 图1 实验器材 目录 前言一、数据采集二、系统辨识1.最小二乘法&#xff08;线性辨识&#…

认识自动化测试

目录 简述 手动测试 自动化测试 测试类型 单元测试 集成测试 端到端测试&#xff08;E2E&#xff09; 快照测试 测试覆盖率 代码覆盖率 需求覆盖率 总结 自动化测试有以下几个概念&#xff1a; 单元测试集成测试E2E 测试快照测试测试覆盖率TDD 以及 BDD 等 简述 …

【消息中间件】原生PHP对接Uni H5、APP、微信小程序实时通讯消息服务

文章目录 视频演示效果前言一、分析二、全局注入MQTT连接1.引入库2.写入全局连接代码 二、PHP环境建立总结 视频演示效果 【uniapp】实现买定离手小游戏 前言 Mqtt不同环境问题太多&#xff0c;新手可以看下 《【MQTT】Esp32数据上传采集&#xff1a;最新mqtt插件&#xff08;支…

GAMES101 笔记 Lecture13 光线追踪1

目录 Why Ray Tracing?(为什么需要光线追踪&#xff1f;)Basic Ray Tracing Algorithm(基础的光线追踪算法)Ray Casting(光线的投射)Generating Eye Rays(生成Eye Rays) Recursive(Whitted-Styled) Ray Tracing Ray-Surface Intersection(光线和平面的交点)Ray Rquation(射线方…

盘点:查快递教程

在“寄快递”成为常态的当下&#xff0c;如何快速进行物流信息查询&#xff0c;是收寄人所关心的问题。在回答这个问题之前&#xff0c;首先我们要知道&#xff0c;物流信息查询&#xff0c;有哪些方法&#xff1f; 1、官网单号查询 知道物流公司和单号的情况下&#xff0c;直…

管理类联考——写作——论说文——实战篇——标题篇

角度3——4种材料类型、4个立意对象、5种写作态度 经过审题立意后&#xff0c;我们要根据我们的立意&#xff0c;确定一个主题&#xff0c;这个主题必须通过文章的标题直接表达出来。 标题的基本要求 主题清晰&#xff0c;态度明确 第一&#xff0c;阅卷人看到一篇论说文的标…

【动态规划part13】| 300.最长递增子序列、674.最长连续递增序列、718.最长重复数组

目录 &#x1f388;LeetCode 300.最长递增子序列 &#x1f388;LeetCode 674. 最长连续递增序列 &#x1f388;LeetCode 718. 最长重复子数组 &#x1f388;LeetCode 300.最长递增子序列 链接&#xff1a;300.最长递增子序列 给你一个整数数组 nums &#xff0c;找到其…

camund——2、cancelActivityInstance()与多实例下getActiveActivityIds()获取不到当前任务的节点。

在多实例&#xff08;会签或者并行网关&#xff09;时如果使用以下代码来进行驳回时&#xff0c;使用 **List activeActivityIds runtimeService.getActiveActivityIds(instanceId);**来获取当前活动的节点会出现获取不到情况。 runtimeService.createProcessInstanceModific…

基于Linux操作系统中的MySQL用户权限管理(三十二)

用户权限管理 目录 一、概述 二、用户权限类型 1、ALL PRIVILEGES 2、CREATE 3、DROP 4、SELECT 5、INSERT 6、UPDATE 7、DELETE 8、INDEX 9、ALTER 10、CREATE VIEW和CREATE ROUTINE 11、SHUTDOWN 12、GRANT OPTION 三、用户赋权 四、权限删除 五、用户删除 …

RTThread实际开发问题统计

文章目录 开启DMA rx中断&#xff0c;数据帧总是接收不全就产生中断&#xff1f;PB3/PB4等和JTAG复用的管脚不能使用&#xff1f;uart使用DMA传输&#xff0c;调用close再open之后就接收不到数据了&#xff1f; 开启DMA rx中断&#xff0c;数据帧总是接收不全就产生中断&#x…

C语言指针应该这么学?

数组名的意义&#xff1a; 1. sizeof(数组名)&#xff0c;这里的数组名表示整个数组&#xff0c;计算的是整个数组的大小。 2. &数组名&#xff0c;这里的数组名表示整个数组&#xff0c;取出的是整个数组的地址。 3. 除此之外所有的数组名都表示首元素的地址。 根据以上数…

[CrackMe]Cruehead.1.exe的逆向及注册机编写

1. 逆向分析过程 作者弄了很多个对话框来迷惑破解者, 然后真正有用的对话框只有这个 这个窗口过程函数处理的是父窗口 其他的不关心, 只关心WM_COMMAND消息 里面有3个分支, 其中最重要的是按下register按钮的那个 整个逻辑非常清晰, 其算法是把name的每个字符转成大写字母…

测试测试用例设计常见面试题

测试|测试用例设计常见面试题 文章目录 测试|测试用例设计常见面试题1.怎么模拟弱网&#xff08;测试技巧&#xff09;2.怎么测试接口&#xff08;测试技巧&#xff09;3.怎么对冒泡排序测试&#xff08;代码类&#xff09;4.怎么对linux的zip命令进行测试&#xff08;软件类&a…

Spring Boot项目的创建

hi 大家好,又见面了,今天继续讲解Spring Boot 文章目录 &#x1f436;1.什么是Spring Boot?&#x1f436;2.Spring Boot的优势&#x1f436;3.Spring Boot项目创建&#x1f33c;3.1使用ieda创建&#x1f95d;3.1.1下载插件Spring Boot Helper&#x1f95d;3.1.2创建项目 &…

基于ThreadPoolExecutor实现动态线程池

项目上&#xff0c;我们是根据业务的使用频率&#xff0c;基于ThreadPoolExecutor自定义一个线程池&#xff0c;线程池的核心线程数、最大线程数、阻塞队列的容量都是估计的设置的&#xff0c;但是不知道线程资源的真正使用情况。 1.ThreadPoolExecutor配置参数动态修改 先来…

Linux Day04

目录 一、文件压缩与解压命令 1.1 tar cvf 文件名 ---打包命令生成.tar 1.2 tar xvf 文件名 ----解开包 生成文件 1.3 gzip .tar 压缩 生成.tar.gz压缩包 1.4 gzip -d .tar.gz 解压成包 1.5 直接把压缩包解压成文件 tar zxf .tar.gz 二、Linux 系统上 C 程序的…