Semaphore是什么?

  • Semaphore,俗称信号量,它是操作系统中PV操作的原语在java的实现。
  • 基于AbstractQueuedSynchronizer实现!
  • Semaphore的功能非常强大,大小为1的信号量就类似于互斥锁,通过同时只能有一个线程获取信号量实现。
  • 大小为n(n>0)的信号量可以实现限流的功能,它可以实现只能有n个线程同时获取信号量。

PV操作是什么?

  • PV操作是操作系统一种实现进程互斥与同步的有效方法。
  • PV操作与信号量(S)的处理相关,P表示通过的意思,V表示释放的意思。
  • 用PV操作来管理共享资源时,首先要确保PV操作自身执行的正确性。

P操作的主要动作:

  • S减1;
  • 若S减1后仍大于或等于0,则进程继续执行;
  • 若S减1后小于0,则该进程被阻塞后放入等待该信号量的等待队列中,然后转进程调度。

V操作的主要动作:

  • S加1;
  • 若相加后结果大于0,则进程继续执行;
  • 若相加后结果小于或等于0,则从该信号的等待队列中释放一个等待进程,然后再返回原进程继续执行或转进程调度。

Semaphore的使用场景

  • 可以用于做流量控制,特别是公用资源有限的应用场景!

Semaphore的使用方式

import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.Semaphore;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class SemaphoneTest1 {/*** 实现一个同时只能处理3个请求的限流器*/private static Semaphore semaphore = new Semaphore(3);/*** 定义一个线程池*/private static ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 50, 60, TimeUnit.SECONDS,new LinkedBlockingDeque<>(200));/*** 模拟执行方法*/public static void exec() {try {semaphore.acquire(1);// 模拟真实方法执行System.out.println("执行exec方法" + System.currentTimeMillis());Thread.sleep(2000);} catch (Exception e) {e.printStackTrace();} finally {semaphore.release(1);}}public static void main(String[] args) throws InterruptedException {{for (;;) {Thread.sleep(100);// 模拟请求以10个/s的速度executor.execute(() -> exec());}}}
}
  • 执行结果

Semaphore的使用结果.png

Semaphore的构造方法

/*** 默认使用非公平的方式*/
public Semaphore(int permits) {sync = new NonfairSync(permits);
}/*** permits 表示许可证的数量(资源数)* fair 表示公平性,如果这个设为 true 的话,下次执行的线程会是等待最久的线程*/
public Semaphore(int permits, boolean fair) {sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}

Semaphore构造方法源码分析

/*** 非公平锁:直接调用了父类(AQS)的实现*/
NonfairSync(int permits) {super(permits);
}/*** 公平锁:直接调用了父类(AQS)的实现*/
FairSync(int permits) {super(permits);
}/*** 调用setState(permits);方法去设置资源数*/
Sync(int permits) {setState(permits);
}/*** 给AQS的state赋值 */
protected final void setState(int newState) {state = newState;
}

Semaphore的获取锁方法:acquire(int permits);源码分析

/*** 获取锁的源码*/
public void acquire(int permits) throws InterruptedException {// 当传入的许可证数量小于0,抛异常if (permits < 0) throw new IllegalArgumentException();// 调用AQS中的获取可中断的共享资源方法sync.acquireSharedInterruptibly(permits);
}/*** 获取可中断的共享资源*/
public final void acquireSharedInterruptibly(int arg)throws InterruptedException {// 如果线程被中断,抛出异常if (Thread.interrupted())throw new InterruptedException();// 尝试获取锁,小于0说明没有锁了if (tryAcquireShared(arg) < 0)// 尝试获取共享锁或者中断doAcquireSharedInterruptibly(arg);
}

Semaphore的尝试获取锁逻辑:tryAcquireShared(arg)

/*** 公平锁的tryAcquireShared实现方式。* 相对于非公平锁多了一个校验:hasQueuedPredecessors()*/
protected int tryAcquireShared(int acquires) {for (;;) {// 如果有链表中有排队的对象!返回-1if (hasQueuedPredecessors())return -1;// 获取当前的资源数int available = getState();// 当前的资源数减去需要消耗的资源数,计算深入的资源数int remaining = available - acquires;// 只有剩余的资源数小于0(没有竞争了)或者能通过CAS将当前的资源数变为减少后的值(这些线程可以去获取锁或者等待锁),才会返回结果,否则一直循环。if (remaining < 0 ||compareAndSetState(available, remaining))// 返回剩余的资源数return remaining;}
}/*** 非公平锁的tryAcquireShared实现方式:调用nonfairTryAcquireShared(acquires)*/
protected int tryAcquireShared(int acquires) {return nonfairTryAcquireShared(acquires);
}/*** 非公平锁的尝试获取共享资源*/
final int nonfairTryAcquireShared(int acquires) {for (;;) {// 获取当前的资源数int available = getState();// 当前的资源数减去需要消耗的资源数,计算深入的资源数int remaining = available - acquires;// 如果剩余的资源数小于0(没有竞争了)或者能通过CAS将当前的资源数变为减少后的值(这些线程可以去获取锁或者等待锁)if (remaining < 0 ||compareAndSetState(available, remaining))// 返回剩余的资源数return remaining;}
}/*** 判断队列中是否有排队的*/
public final boolean hasQueuedPredecessors() {// The correctness of this depends on head being initialized// before tail and on head.next being accurate if the current// thread is first in queue.Node t = tail; // Read fields in reverse initialization orderNode h = head;Node s;// 未初始化的时候,队列头部尾部的值为null,相等----不满足// 只有一个的时候,头尾相等----不满足// 头部的下一个为null,说明只有一个----满足// 下一个的线程是当前线程,重入了----满足// 简单说:链表中只有一个或者链表是空的,返回false。链表中有多个,不满足重入的机制,返回false。只有链表中有多个数据并且持有线程是当前线程的时候才会返回true!return h != t &&((s = h.next) == null || s.thread != Thread.currentThread());
}

尝试获取共享锁或者中断:doAcquireSharedInterruptibly

/*** 尝试获取共享锁或者中断*/
private void doAcquireSharedInterruptibly(int arg)throws InterruptedException {// 添加到等待队列final Node node = addWaiter(Node.SHARED);// 定义失败标记为trueboolean failed = true;try {for (;;) {// 得到当前节点的前驱节点final Node p = node.predecessor();// 如果前置节点是头结点if (p == head) {// 尝试去获取锁:公平锁与非公平锁实现不一致!int r = tryAcquireShared(arg);// 获取的资源数大于0(获取到了资源,Semaphore)if (r >= 0) {// 设置头结点和链表,准备唤醒后继节点setHeadAndPropagate(node, r);// 取消节点的引用,方便GC去回收p.next = null; // help GC// 将失败标记改为falsefailed = false;// 跳出方法!return;}}// 代码执行到这里,说明尝试获取锁,但是获取锁失败了。// 阻塞前的准备工作操作成功(状态是-1的时候成功)// 将线程阻塞,等待他去唤醒。唤醒后返回线程的中断状态!if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())throw new InterruptedException();}} finally {// 上面代码抛出异常的时候,会执行这里的逻辑if (failed)// 取消获取锁的逻辑cancelAcquire(node);}
}/*** 添加线程到同步队列*/
private Node addWaiter(Node mode) {// 创建一个当前线程的Node节点Node node = new Node(Thread.currentThread(), mode);// Try the fast path of enq; backup to full enq on failure:尝试enq的快速路径;故障时备份到完整enq// 得到之前的尾节点Node pred = tail;// 尾节点不为空,说明队列存在if (pred != null) {// 设置当前线程节点的上一个节点是之前的尾节点node.prev = pred;// cas尝试将尾节点设置为当前线程的节点if (compareAndSetTail(pred, node)) {// 设置之前尾节点,现在的倒数第二个节点的下一个节点是当前线程节点pred.next = node;// 返回当前节点return node;}}// CAS失败或者节点没有创建,会执行这入队的操作。详细请看下面的代码enq(node);// 入队成功后,返回当前节点return node;
}/*** 设计精髓:100%创建队列或者100%入队*/
private Node enq(final Node node) {for (;;) {// 得到之前的尾节点Node t = tail;// 之前的尾节点为空,需要进行初始化队列if (t == null) { // Must initialize// 通过CAS的方式将头节点设置为当前节点if (compareAndSetHead(new Node()))// 头结点设置成功后,复制给尾节点。只有一个节点的状态tail = head;} else {// 设置当前线程节点的上一个节点是之前的尾节点node.prev = t;// cas尝试将尾节点设置为当前线程的节点if (compareAndSetTail(t, node)) {// 设置之前尾节点,现在的倒数第二个节点的下一个节点是当前线程节点t.next = node;// 返回当前节点!注意:这里是这个方法唯一返回的地方!也就是说初始化后还会继续循环一次来设置上一个下一个节点,然后进行返回。return t;}}}
}/*** 设置头结点和链表*/
private void setHeadAndPropagate(Node node, int propagate) {// 得到旧的头Node h = head; // Record old head for check below// 将当前节点设置为头节点,所属线程设置为null,前驱节点设置为nullsetHead(node);// propagate > 0:说明还有剩余共享锁可以获取,那么短路后面条件。// h == null与(h = head) == null是一个防止控制住的标准写法,因为经过了addWaiter方法,肯定会有一个节点!// h.waitStatus < 0:状态小于0。在调用doReleaseShared的时候回cas状态到0!说明有其他线程调用了doReleaseShared()。第一个是旧的头结点,第二个是新的头结点(当前节点)!// (h = head) == null:除了防止空指针,这里会将当前节点复制到h变量上if (propagate > 0 || h == null || h.waitStatus < 0 ||(h = head) == null || h.waitStatus < 0) {// 得到当前节点的下一个节点Node s = node.next;// 下一个节点为空(node是队尾)或者下一个节点是共享模式if (s == null || s.isShared())// 唤醒后继的节点并且保证继续传播doReleaseShared();}
}/*** 唤醒后继的节点并且保证继续传播*/
private void doReleaseShared() {/** Ensure that a release propagates, even if there are other* in-progress acquires/releases.  This proceeds in the usual* way of trying to unparkSuccessor of head if it needs* signal. But if it does not, status is set to PROPAGATE to* ensure that upon release, propagation continues.* Additionally, we must loop in case a new node is added* while we are doing this. Also, unlike other uses of* unparkSuccessor, we need to know if CAS to reset status* fails, if so rechecking.*/for (;;) {// 得到当前的头结点Node h = head;// 当头结点不为空并且头结点不是尾节点的时候if (h != null && h != tail) {// 获取头结点的状态int ws = h.waitStatus;// 头结点状态为-1:当前节点的后继节点包含的线程需要运行if (ws == Node.SIGNAL) {// cas将当前头结点状态设置为0(当前节点在sync队列中,等待着获取锁)失败。进入下次循环!CAS成功继续执行!if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))continue;            // loop to recheck cases// 执行唤醒锁的流程unparkSuccessor(h);}// 头结点的状态为0并且不能变为cas状态到-3(后续的acquireShared能够得以执行),继续执行!否则进入下次循环else if (ws == 0 &&!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))continue;                // loop on failed CAS}// 如果头部改变,则继续循环。没有改变就跳出循环!if (h == head)                   // loop if head changedbreak;}
}/*** 唤醒锁的流程*/
private void unparkSuccessor(Node node) {/** If status is negative (i.e., possibly needing signal) try* to clear in anticipation of signalling.  It is OK if this* fails or if status is changed by waiting thread.*/// 获取当前节点的状态int ws = node.waitStatus;// 如果状态小于0,尝试将状态变为0if (ws < 0)compareAndSetWaitStatus(node, ws, 0);/** Thread to unpark is held in successor, which is normally* just the next node.  But if cancelled or apparently null,* traverse backwards from tail to find the actual* non-cancelled successor.*/// 获取当前节点(头节点)的下一个节点Node s = node.next;// 头节点的下一个节点是空的或者下一个节点的状态是1(当前的线程被取消)if (s == null || s.waitStatus > 0) {// 设置下个节点为nulls = null;// 从尾部开始向前遍历,找到最前的一个处于正常阻塞状态的结点,直到节点重合// 从尾部遍历的原因是为了防止在高并发场景下漏掉线程for (Node t = tail; t != null && t != node; t = t.prev)if (t.waitStatus <= 0)s = t;}// 过滤后的下一个节点不为null,唤醒他if (s != null)// 唤醒下一个节点LockSupport.unpark(s.thread);
}/*** 获取锁失败后的准备逻辑,阻塞前的准备逻辑*/
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {// 获取前驱当前节点的等待状态int ws = pred.waitStatus;// 状态为-1的时候:当前节点的后继节点包含的线程需要运行,也就是unpark;if (ws == Node.SIGNAL)/** This node has already set status asking a release* to signal it, so it can safely park.*/// 前驱当前节点状态已经设置为SIGNAL,可以进行安全的阻塞return true;// 大于0(CANCELLED状态):表示当前的线程被取消;if (ws > 0) {/** Predecessor was cancelled. Skip over predecessors and* indicate retry.*/// 前驱节点已经因为超时或响应了中断,需要跳过这些状态大于0的节点,直到找到一个状态不是大于0的。do {node.prev = pred = pred.prev;} while (pred.waitStatus > 0);// 跳过中断的线程后,设置前驱节点的下一个节点为当前节点。pred.next = node;} else {/** waitStatus must be 0 or PROPAGATE.  Indicate that we* need a signal, but don't park yet.  Caller will need to* retry to make sure it cannot acquire before parking.*/// 针对于ReentrantLock,到这里的状态只能为0或者PROPAGATE(-3)// 通过CAS将前置节点的状态设置为SIGNAL(-1)compareAndSetWaitStatus(pred, ws, Node.SIGNAL);}return false;
}/*** 状态为SIGNAL(-1)成功。他需要排队,所以直接调用park方法进行阻塞*/
private final boolean parkAndCheckInterrupt() {// 阻塞LockSupport.park(this);// unpark之后,返回当前的中断状态,并清除中断标志位return Thread.interrupted();
}/*** 取消获取锁的逻辑*/
private void cancelAcquire(Node node) {// Ignore if node doesn't exist// 忽略节点不存在的时候if (node == null)return;// 设置当前节点的线程为nullnode.thread = null;// Skip cancelled predecessors:有前驱节点被取消,跳过所有被取消的// 得到前驱节点Node pred = node.prev;// 前驱节点的状态大于0,被取消while (pred.waitStatus > 0)// 将前驱结点的前驱结点设置为当前节点的前驱结点。简单理解就是将当前节点的前驱节点设置为第一个找到的正常状态(<=0)的前驱节点node.prev = pred = pred.prev;// predNext is the apparent node to unsplice. CASes below will// fail if not, in which case, we lost race vs another cancel// or signal, so no further action is necessary.// 获取当前节点的下一个节点Node predNext = pred.next;// Can use unconditional write instead of CAS here.// After this atomic step, other Nodes can skip past us.// Before, we are free of interference from other threads.// 将当前节点状态设置为1(取消状态)。这里不用CAS的原因是这个执行完其他线程会跳过取消状态,这个执行前无其他线程在执行!node.waitStatus = Node.CANCELLED;// If we are the tail, remove ourselves.// 如果当前节点是尾节点,将尾节点设置为上一个节点。简单理解就是移除当前节点。if (node == tail && compareAndSetTail(node, pred)) {compareAndSetNext(pred, predNext, null);} else {// 进入else说明node不是队尾(或者是队尾但是cas队尾失败(其实结果也不是队尾,因为被别的线程抢先了))// If successor needs signal, try to set pred's next-link// so it will get one. Otherwise wake it up to propagate.// 定义一个状态标识int ws;// 筛选后的前驱节点不是头结点// 并且当前节点状态为-1(等待唤醒)或者(当前节点不在运行或者不被取消(<= 0)并且可以将当前节点CAS到-1状态(等待唤醒))// 并且前驱节点有线程持有!if (pred != head &&((ws = pred.waitStatus) == Node.SIGNAL ||(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&pred.thread != null) {// 得到当前节点的下一个节点Node next = node.next;// 下一个节点不为空,并且下一个节点没有被取消if (next != null && next.waitStatus <= 0)// CAS将前一个节点与下一个节点连接。简单理解就是跳过(取消)当前节点!compareAndSetNext(pred, predNext, next);} else {// 唤醒下一个不被取消的节点!unparkSuccessor(node);}// 当前节点的下一个节点取消指向node.next = node; // help GC}
}

Semaphore的释放锁方法:release(int permits);源码分析

/*** 释放锁的逻辑*/
public void release(int permits) {// 传入的数量小于0,直接抛出异常if (permits < 0) throw new IllegalArgumentException();// 调用释放共享说的方法sync.releaseShared(permits);
}/*** 释放共享锁的逻辑*/
public final boolean releaseShared(int arg) {// 尝试去释放共享锁if (tryReleaseShared(arg)) {// 唤醒后继的节点并且保证继续传播doReleaseShared();// 整体返回true,表示释放共享锁成功return true;}// java规范的写法:必须有个返回值,不会执行到这里!return false;
}/*** 尝试去释放共享锁*/
protected final boolean tryReleaseShared(int releases) {for (;;) {// 获取状态:锁的数量,构造方法传入的数量int current = getState();// 得到如果释放够的总数量int next = current + releases;// 大于int的最大值,next变为负数!溢出了,抛异常!if (next < current) // overflowthrow new Error("Maximum permit count exceeded");// CAS将持有的状态(剩余资源数)设置为新的值if (compareAndSetState(current, next))return true;}
}

结束语

  • 获取更多有价值的文章,让我们一起成为架构师!
  • 关注公众号,可以让你对MySQL有非常深入的了解
  • 关注公众号,每天持续高效的了解并发编程!
  • 关注公众号,后续持续高效的了解spring源码!
  • 这个公众号,无广告!!!每日更新!!!
    作者公众号.jpg
查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. 关于TextMeshPro的命名空间与组件获取

    使用Text(TMP)需要引用命名空间TMPro命名空间 组件的名称为TMP_Text using TMPropublic class UIManager : MonoBehaviour {public TMP_Text testMeshPro;private void Start() {testMeshPro.text "This is a test sentence";} }感谢 https://blog.csdn.net/qq_376…...

    2024/4/13 21:30:12
  2. 配置个人虚拟机Linux多节点

    配置个人Linux多节点软件准备CentOS安装虚拟机网卡配置软件准备 本文主要基于Windows10上的操作 下载VMware Workstation 还有CentOS 7镜像下载地址http://mirrors.bupt.edu.cn/centos/7.9.2009/isos/x86_64/ 暂时建议下载其中的DVD版 CentOS安装 参考网上的CentOS安装教程即…...

    2024/4/13 21:30:02
  3. java打印三角形

    package struct;public class TextDemo1 {public static void main(String[] args) {//打印三角形for (int i 1; i <5; i) {for (int j 5; j> i; j--) {System.out.print(" ");}for (int j 1; j < i; j) {System.out.print("X");}for (int j …...

    2024/4/7 19:13:22
  4. centos7网卡启动不了的解决办法

    重启网卡 systemctl restart network //重启网卡 返回报错&#xff1a; Restarting network (via systemctl): Job for network.service failed. See systemctl status network.service and journalctl -xn for details. 查看网卡状态 systemctl status network.service …...

    2024/4/15 13:59:56
  5. Do while与While区别

    package struct;public class DoWhileDemo2 {public static void main(String[] args) {//do while 与 while区别int a 0;while (a<0){System.out.println(a);a;}System.out.println("");do {System.out.println(a);a;}while (a<0);} }...

    2024/4/13 21:30:07
  6. Shell 将传参字符串按指定分隔符拆分成数组,并遍历处理

    shell默认多个传参值是以空格为分隔符的 $ cat show_var.sh for i in $ doecho $i done #在shell中$*和$都是内置变量&#xff0c;表示整个参数列表$ sh show_var.sh apple banana cherry apple banana cherry 如果传参是个字符串&#xff0c;并且能够以特定字符进行分割&…...

    2024/4/18 2:57:03
  7. C语言学习第十二天-内存精讲

    程序是保存在硬盘中的&#xff0c;要载入内存才能运行&#xff0c;CPU也被设计为只能从内存中读取数据和指令。 对于CPU来说&#xff0c;内存仅仅是一个存放指令和数据的地方&#xff0c;并不能在内存中完成计算功能&#xff0c;例如要计算 a b c&#xff0c;必须将a、b、c都…...

    2024/4/18 0:59:47
  8. JavaDoc API 文档的组织方式

    JavaDoc API 文档的组织方式 此 API (应用程序编程接口) 文档包含对应于导航栏中的项目的页面, 如下所述。 概览 概览 页面是此 API 文档的首页, 提供了所有程序包的列表及其概要。此页面也可能包含这些程序包的总体说明。 程序包 每个程序包都有一个页面, 其中包含它的类…...

    2024/4/7 19:13:19
  9. --i和i--

    –i 是先运算ii-1,然后再使用i的值, 这时的i 值就是–i的值。 i-- 是先使用i的值作为表达式i–的值,然后,运算ii-1。 先gapgap-1&#xff0c;再进行与0比较!!! 先gap保持原值与0比较&#xff0c;再进行gapgap-1,进入for循环!!!...

    2024/4/28 9:51:08
  10. 40. Leetcode 104. 二叉树的最大深度 (二叉树-二叉树性质)

    给定一个二叉树&#xff0c;找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。说明: 叶子节点是指没有子节点的节点。示例&#xff1a; 给定二叉树 [3,9,20,null,null,15,7]&#xff0c;3/ \9 20/ \15 7 返回它的最大深度 3 。# Definition for a…...

    2024/5/2 9:32:41
  11. 【并发编程】并发包中工具类的基础:AQS

    AQS为什么要学&#xff1f; AQS是jdk并发包java.util.concurrent下绝大部分工具类实现的基础&#xff0c;非常重要&#xff01;AQS是工作中并发编程常用的类Lock, Latch, Barrier等&#xff0c;都是基于AQS来实现的&#xff01;了解AQS&#xff0c;后面学习一些并发工具类&…...

    2024/4/19 9:59:31
  12. 一文看懂git的使用

    分布式版本控制git 集中式版本控制svn SVN与Git的最主要的区别&#xff1f; SVN是集中式版本控制系统&#xff0c;版本库是集中放在中央服务器的&#xff0c;而干活的时候&#xff0c;用的都是自己的电脑&#xff0c;所以首先要从中央服务器…...

    2024/4/7 19:13:14
  13. 博客承诺完成情况

    4.26 - 5.2 完成5.3 - 5.9 完成5.10 - 5.16 完成5.17 - 5.23 完成5.24 - 5.30 缺1篇2021-05-31 —— 2021-06-06 缺2篇2021-06-07 —— 2021-06-13 缺2篇2021-06-14 —— 2021-06-20 缺2篇2021.6.21 —— 2021.6.27 完成2021.6.28 —— 2021.7.4 完成2021.7.5 —— 2021.7.11 缺…...

    2024/4/19 12:02:16
  14. Android手机平板两不误,使用Fragment实现兼容手机和平板的程序

    ListView的适配器。 */ private ArrayAdapter adapter; /** 用于填充ListView的数据&#xff0c;这里就简单只用了两条数据。 */ private String[] menuItems { “Sound”, “Display” }; /** 是否是双页模式。如果一个Activity中包含了两个Fragment&#xff0c;就是双页…...

    2024/4/15 5:39:14
  15. 第四章 分支结构程序设计

    4.2 关系运算符、逻辑运算符、条件运算符 4.2.1 关系运算符和关系表达式 1.关系运算符&#xff1a;用于判断两个操作数的大小关系。 关系运算符运算符含义>大于>大于等于<小于<小于等于等于!不等于 2.关系表达式&#xff1a;用关系运算符将两个表达式连接起来的式…...

    2024/5/2 9:19:25
  16. 【并发编程】synchronized在设计上的锁优化

    批量重偏向、批量撤销 从偏向锁的加锁解锁过程中可看出&#xff0c;当只有一个线程反复进入同步块时&#xff0c;偏向锁带来的性能开销基本可以忽略。当有其他线程尝试获得锁时&#xff0c;就需要等到safe point时&#xff0c;再将偏向锁撤销为无锁状态或升级为轻量级&#xf…...

    2024/5/2 8:00:35
  17. 计算机毕业设计Python+Django的学生信息管理系统(源码+系统+mysql数据库+Lw文档)

    项目介绍 本系统包含了二个用户&#xff0c;即管理员和用户。 本学生信息系统采用的数据库是Mysql&#xff0c;使用python技术开发。在设计过程中&#xff0c;充分保证了系统代码的良好可读性、实用性、易扩展性、通用性、便于后期维护、操作方便以及页面简洁等特点。 运行环…...

    2024/4/5 3:31:27
  18. 用for或while输出0-1000之间能被5整除的数,并且每行输出三个

    package struct;public class ForDemo3 {public static void main(String[] args) {//用for或while输出0-1000之间能被5整除的数&#xff0c;并且每行输出三个&#xff1b;for (int i 1; i < 1000; i) {if(i%50){System.out.print(i"\t");}if(i%(5*3)0){System.o…...

    2024/4/14 16:41:27
  19. Python数据结构之循环链表

    循环链表 循环链表的增删改查&#xff1b;循环链表的尾指针的下一个结点指向头指针&#xff1b;优点&#xff1a; 1). 每一个结点都可以遍历全部链表。 2). 而每个循环的时间复杂度都是相同的 O(1)。缺点: 1). 需要多链接一个空间。 代码部分 结点类 class Node:def __init…...

    2024/4/13 21:31:05
  20. WebRTC音视频同步机制

    WebRTC音视频同步机制实现分析 - 简书音视频同步事关多媒体产品的最直观用户体验&#xff0c;是音视频媒体数据传输和渲染播放的最基本质量保证。音视频如果不同步&#xff0c;有可能造成延迟、卡顿等非常影响用户体验的现象。因此&#xff0c;它非常重要。一...https://www.ji…...

    2024/4/13 21:30:43

最新文章

  1. LeetCode 543.二叉树的直径

    题目描述 给你一棵二叉树的根节点&#xff0c;返回该树的 直径 。 二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也可能不经过根节点 root 。 两节点之间路径的 长度 由它们之间边数表示。 示例 1&#xff1a; 输入&#xff1a;root [1,2,3,4,5]…...

    2024/5/2 9:38:27
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. Gitlab全量迁移

    Gitlab全量迁移 一、背景1.前提条件 一、背景 公司研发使用的Gitlab由于服务器下架需要迁移到新的Gitlab服务器上。Gitlab官方推荐了先备份然后再恢复的方法。个人采用官方的另外一种方法&#xff0c;就写这篇文章给需要的小伙伴参考。 源Gitlab: http://old.mygitlab.com #地…...

    2024/4/30 5:37:08
  4. 同一个pdf在windows和linux中的页数不一样

    之前认为PDF的格式&#xff0c;至少页数是不会变化的&#xff0c;结果最近发现一个文档在windows和linux中的页数不一样&#xff0c;linux中的pdf进入像word一样排版变得紧凑了&#xff0c;原本在下一页的几行进入了上一页的末尾。问了gpt后得到这样的回答&#xff1a; PDF文档…...

    2024/5/2 2:41:10
  5. JVM学习笔记

    文章目录 一、内存模型1. 程序计数器2. 栈3. 本地方法栈4. 堆5. 方法区方法区位置字符串常量池位置 6. 直接内存 二、虚拟机参数设置三、类的生命周期1. 加载2. 连接1&#xff09;验证2&#xff09;准备3&#xff09;解析 3. 初始化4. 卸载 四、类加载器1. 启动类加载器2. 扩展…...

    2024/5/1 13:33:02
  6. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/5/1 17:30:59
  7. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/4/30 18:14:14
  8. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/4/29 2:29:43
  9. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/5/2 9:28:15
  10. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/4/27 17:58:04
  11. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/4/27 14:22:49
  12. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/4/28 1:28:33
  13. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/4/30 9:43:09
  14. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/4/27 17:59:30
  15. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/4/25 18:39:16
  16. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/4/28 1:34:08
  17. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/4/26 19:03:37
  18. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/4/29 20:46:55
  19. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/4/30 22:21:04
  20. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/5/1 4:32:01
  21. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/4/27 23:24:42
  22. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/4/28 5:48:52
  23. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/4/30 9:42:22
  24. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/5/2 9:07:46
  25. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/4/30 9:42:49
  26. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  27. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  28. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  29. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  30. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  31. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  32. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  33. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  34. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  35. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  36. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  37. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  38. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  39. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  40. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  41. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  42. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  43. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  44. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  45. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57