当前位置: 首页 > news >正文

synchronized关键字和ReentrantLock在不同jdk版本中性能哪个高?该怎么选择呢?

synchronized关键字和ReentrantLock在不同JDK版本中的性能差异经历了显著的变化。早期,在JDK 1.5及以前的版本中,ReentrantLock通常提供了更好的性能,主要是因为synchronized关键字的实现较为简单,没有太多的优化,导致了较多的上下文切换和线程阻塞。

然而,在JDK 1.6中,Java虚拟机(JVM)对synchronized进行了重大改进,引入了锁的分层机制和适应性自旋锁,这极大地提高了synchronized的性能。因此,在JDK 1.6及以后的版本中,synchronizedReentrantLock之间的性能差距大大缩小,甚至在某些情况下synchronized的性能会优于ReentrantLock

在JDK 1.8中,进一步的优化使得synchronized的性能更加接近甚至有时超过ReentrantLock,特别是在轻量级锁和偏向锁的使用上。

性能选择

在现代JDK版本中(JDK 1.6及更高版本),synchronizedReentrantLock的性能差异并不显著,选择哪个主要取决于具体的使用场景和需求:

  • 代码简洁性:如果你关心代码的简洁性和易读性,synchronized可能是一个更好的选择,因为它不需要显式的锁管理,即不需要手动调用lock()unlock()方法。

  • 灵活性和控制:如果你需要更高级的锁控制,如可中断的等待、定时锁尝试、公平锁等,ReentrantLock提供了更多的灵活性和控制选项。

  • 线程中断:如果线程需要响应中断,ReentrantLocklockInterruptibly()方法提供了这种能力,而synchronized则不能响应中断,除非你使用Thread.sleep()Object.wait()等方法,这些方法会释放锁并可能抛出InterruptedException

  • 公平锁ReentrantLock允许你创建公平锁,而synchronized总是使用非公平锁。

总结

在大多数情况下,你可以根据上述因素来选择,但在具体选择时,还应考虑整个系统的性能瓶颈是否在于锁的竞争。如果锁的竞争不是很激烈,使用哪种锁可能对整体性能影响不大。如果锁成为性能瓶颈,你应该通过基准测试来确定在你的特定环境中哪种锁更优。

最后,无论选择哪种锁,都应该遵循良好的并发编程实践,如尽量减小锁的范围,避免过度使用锁,以及使用局部变量和不可变对象来减少同步的需要。

jdk8中synchronized内部原理

在Java 8中,synchronized关键字的实现基于Java虚拟机(JVM)中的监视器锁(monitor lock),这是通过对象头(object header)中的Mark Word来实现的。synchronized关键字有两种基本用法:用于方法和用于代码块。

监视器锁的实现原理

监视器锁是由JVM实现的,它位于每个对象的头部,包含以下信息:

  • 对象的hashcode
  • 分代年龄
  • 锁标志位
  • 线程ID
  • 锁计数器

当一个线程试图获取一个对象的锁时,它会检查对象的Mark Word中的锁标志位。如果对象未被锁定(即锁标志位表示无锁状态),线程可以尝试获取锁。如果获取成功,Mark Word会被更新,以包含当前线程的ID和锁的类型(偏向锁、轻量级锁或重量级锁)。

锁升级策略

JVM为了提高锁的性能,采用了锁升级的策略,从偏向锁升级到轻量级锁,再到重量级锁,这个过程是不可逆的。锁升级的目的是尽量避免使用重量级锁,以减少线程的挂起和唤醒所带来的开销。

  1. 偏向锁:当一个线程首次访问一个同步块时,如果该对象没有被其他线程锁定过,JVM会将锁标志位设置为偏向锁,并将Mark Word中的线程ID设置为当前线程ID。如果后续请求锁的线程是同一个线程,可以直接进入同步代码块,无需额外的同步操作。

  2. 轻量级锁:当有第二个线程试图获取锁时,偏向锁会升级为轻量级锁。轻量级锁使用CAS(Compare and Swap)操作来尝试获取锁。如果CAS操作成功,线程可以继续执行;如果失败,线程会进行自旋,尝试再次获取锁。

  3. 重量级锁:当轻量级锁无法满足需求,比如自旋次数过多或线程被调度到其他地方执行,JVM会将锁升级为重量级锁。重量级锁会导致线程的阻塞和上下文切换,性能较差。

synchronized关键字的用法

  • 用于方法:当synchronized用于方法时,锁的范围是整个方法体。锁的标识符是方法所属的对象实例(对于静态方法则是类的Class对象)。

  • 用于代码块:当synchronized用于代码块时,锁的范围仅限于代码块。锁的标识符由括号中的表达式指定,通常是某个对象实例。

总结

在Java 8中,synchronized关键字通过监视器锁和锁升级策略实现了高效的并发控制。它通过Mark Word来跟踪锁的状态,使用偏向锁、轻量级锁和重量级锁来适应不同的并发需求,从而提高了锁的性能。

自旋

自旋(Spin)是一种计算机科学中的线程同步机制,通常用于多线程环境下。当一个线程试图获取一个已经被其他线程占用的资源(如锁)时,自旋策略会让线程在一个循环中不断地检查资源是否可用,而不是立即将线程置于等待或阻塞状态。如果在自旋期间资源很快变得可用,这种方法可以避免线程上下文切换的开销,从而提高效率。

自旋锁

自旋锁是自旋机制的一种应用,通常用于实现对共享资源的独占访问。当一个线程试图获取一个已经被另一个线程持有的锁时,该线程将进入一个自旋循环,不断地检查锁是否可用。一旦锁变为可用状态,线程就可以立即获取锁并继续执行。

优点

  • 减少上下文切换:自旋锁避免了线程阻塞和上下文切换,这在高频率的短时间锁竞争中特别有用,因为上下文切换本身需要消耗一定的时间。
  • 快速响应:如果锁很快就能被释放,自旋锁能够迅速响应,使线程能够立即继续执行。

缺点

  • CPU消耗:自旋锁在资源不可用时会持续消耗CPU周期,如果资源长时间不可用,这可能导致CPU资源浪费。
  • 不适合长期等待:如果线程需要等待很长时间才能获取锁,自旋锁的效率会非常低,此时阻塞线程并进行上下文切换可能是更好的选择。

Java中的自旋

在Java中,自旋锁可以通过ReentrantLock类结合LockSupport.park()LockSupport.unpark()方法实现,或者使用Atomic类提供的原子操作来实现。此外,JVM内部也使用自旋机制来优化synchronized关键字的性能,例如在轻量级锁阶段使用自旋来等待锁的释放。

自适应自旋

自适应自旋是指自旋的时间长度可以根据前一次锁的获取时间来调整。如果前一次锁等待时间较短,则下一次可能会自旋更长的时间;如果前一次等待时间较长,则可能直接放弃自旋,转而使用阻塞机制。Java的JVM实现中包含了自适应自旋的策略,以优化锁的获取效率。

ReentrantLock是怎么实现的

ReentrantLock是Java并发库java.util.concurrent.locks中的一个类,它是一个可重入的互斥锁,提供了比synchronized关键字更强大的锁定机制。ReentrantLock的设计是基于抽象的同步器AbstractQueuedSynchronizer(AQS)框架实现的。

AQS框架

AQS框架是一个用于构建锁和其他同步组件的基础框架。它使用了一个内部的FIFO线程等待队列(CLH锁队列)和一个共享的整型状态值state,通过原子操作修改state来控制锁的获取与释放。

ReentrantLock实现

ReentrantLock通过继承自AbstractQueuedSynchronizer并实现它的模板方法来实现其功能。具体来说,ReentrantLock实现了AQSisHeldExclusively()方法和tryAcquire()tryRelease()方法。

  1. 独占模式

    ReentrantLock是一个独占锁,这意味着在任何时刻只有一个线程可以持有锁。当线程尝试获取锁时,ReentrantLock会调用AQSacquire()方法,这会进一步调用tryAcquire()方法。在ReentrantLocktryAcquire()实现中,它会检查state字段,如果state为0,则没有线程持有锁,可以尝试获取锁。如果获取成功,state会增加,表示锁被获取。如果state不为0,表示已经有线程持有锁,调用线程会被加入到AQS的等待队列中,并可能被阻塞。

  2. 可重入性

    ReentrantLock支持可重入性,即已经持有锁的线程可以再次获取锁而不会引起死锁。这是通过state字段来实现的,每当同一线程再次获取锁时,state的值会递增。当线程释放锁时,会调用AQSrelease()方法,这会调用tryRelease()方法,其中state的值会递减。只有当state的值为0时,锁才真正被完全释放。
    Thread thread - 这个变量在ReentrantLock的内部类NonfairSyncFairSync中被使用,用于存储当前持有锁的线程引用。这样,当一个线程尝试获取锁时,AQS可以检查这个线程是否已经是锁的持有者,如果是,则允许线程再次获取锁,从而实现可重入性。

  3. 公平性和非公平性

    ReentrantLock提供了公平和非公平两种锁的实现。公平锁会保证线程按照它们请求锁的顺序获取锁,而非公平锁则可能让当前正在运行的线程优先获取锁,即使有其他线程已经在等待队列中。非公平锁在大多数情况下提供了更好的性能,因为它减少了线程的等待时间,但可能会导致某些线程饿死。

源码层面的实现

在源码中,ReentrantLock的核心逻辑主要体现在以下几个方法中:

  • newCondition(): 创建一个新的Condition对象,用于实现更复杂的线程等待和通知机制。
  • lock(): 获取锁,如果没有获取到,则会阻塞当前线程直到获取到锁。
  • tryLock(): 尝试获取锁,如果获取不到锁则立即返回false
  • lockInterruptibly(): 尝试获取锁,如果在等待过程中线程被中断,则抛出InterruptedException
  • unlock(): 释放锁。

总的来说,ReentrantLock利用了AQS框架的能力,通过维护state字段和线程队列,实现了独占、可重入和可选的公平锁行为。

从AbstractQueuedSynchronizer成员变量的角度详解是如何实现可重入锁的

AbstractQueuedSynchronizer(AQS)是Java并发包java.util.concurrent中的一个抽象类,它提供了一个框架用于构建依赖于“先进先出”(FIFO)等待队列的阻塞锁和相关的同步器。AQS设计的核心是使用一个volatile整型成员变量state来表示同步状态,以及一个FIFO线程等待队列来管理线程的等待和唤醒。

AQS的关键成员变量

AQS中有几个关键的成员变量,它们是实现可重入锁的基础:

  1. volatile int state - 这个变量是所有同步状态的基础。在可重入锁中,它的值表示锁的重入次数。当一个线程第一次获取锁时,state的值被设置为1,之后每次同一线程再次获取锁时,state的值递增。当线程释放锁时,state的值递减,直到state为0,表示锁完全释放。

  2. Thread thread - 这个变量在ReentrantLock的内部类NonfairSyncFairSync中被使用,用于存储当前持有锁的线程引用。这样,当一个线程尝试获取锁时,AQS可以检查这个线程是否已经是锁的持有者,如果是,则允许线程再次获取锁,从而实现可重入性。

  3. Node类型的双向链表 - 这个链表是AQS中用于管理等待线程的队列。每个Node代表一个等待锁的线程。当一个线程尝试获取锁失败时,它会被插入到队列的尾部,并可能被阻塞直到锁被释放。

实现可重入性的关键方法

  • tryAcquire(int acquires) - 这个方法用于尝试获取锁。在ReentrantLock中,它会检查当前线程是否已经持有锁,如果是,则递增state的值并返回true。如果不是,它会检查是否有其他线程持有锁,如果没有,则尝试设置state并返回true,否则返回false

  • tryRelease(int releases) - 当线程释放锁时,这个方法会被调用。它会递减state的值。如果state变为0,这意味着锁被完全释放,任何等待的线程现在都有机会获取锁。

示例:ReentrantLock的实现

ReentrantLock中,NonfairSyncFairSync类继承自AQS,并实现了tryAcquiretryRelease方法。在tryAcquire方法中,如果当前线程已经持有锁,它会递增state的值,否则会检查是否有其他线程持有锁。如果state为0且当前线程能够成功获取锁,state的值将被设置为1。在tryRelease方法中,如果state大于0,它会递减state的值,如果state变为0,表示锁被完全释放。

总结

AQS通过state变量和等待队列来管理锁的获取和释放,以及线程的等待和唤醒。ReentrantLock利用了AQS的这些机制来实现可重入性,即允许一个已经持有锁的线程再次获取锁,同时保持锁的独占性和线程安全。

 /*** 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) // overflowthrow 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 ownerreturn getExclusiveOwnerThread() == Thread.currentThread();}final ConditionObject newCondition() {return new ConditionObject();}// Methods relayed from outer classfinal 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}}/*** 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());elseacquire(1);}protected final boolean tryAcquire(int acquires) {return nonfairTryAcquire(acquires);}}/*** 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;}}

加锁&释放锁

		// Syncpublic void lock() {sync.lock();}// NonfairSync非公平锁final void lock() {if (compareAndSetState(0, 1))//直接忽略等待队列,当前线程直接获取锁setExclusiveOwnerThread(Thread.currentThread());elseacquire(1);}// AQSpublic final void acquire(int arg) {if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))//当前线程加入等待队列,自旋selfInterrupt();}// AQSfinal 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)) {//head获取锁setHead(node);p.next = null; // help GCfailed = false;return interrupted;}if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())//当前线程挂起interrupted = true;}} finally {if (failed)cancelAcquire(node);}}// NonfairSyncprotected final boolean tryAcquire(int acquires) {return nonfairTryAcquire(acquires);}    //NonfairSyncfinal 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) // overflowthrow new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}// FairSyncprotected final boolean tryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {  // 先让等待队列的head获取锁,当前线程加入等待队列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;}}// 释放锁public void unlock() {sync.release(1);}// AQSpublic final boolean release(int arg) {if (tryRelease(arg)) {Node h = head;if (h != null && h.waitStatus != 0)unparkSuccessor(h);return true;}return false;}//AQSprivate void unparkSuccessor(Node node) {int ws = node.waitStatus;if (ws < 0)compareAndSetWaitStatus(node, ws, 0);Node s = node.next;if (s == null || s.waitStatus > 0) {s = null;for (Node t = tail; t != null && t != node; t = t.prev)if (t.waitStatus <= 0)s = t;}if (s != null)LockSupport.unpark(s.thread);//唤醒线程,继续执行acquireQueued自旋}// Syncprotected 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;}

jdk8 synchronized锁定代码块,有10个线程被阻塞等待,当锁释放后,jvm会选取其中一个线程唤醒并获取锁,还是唤醒所有线程竞争锁呢? 唤醒一个线程是否仅执行一个线程的上下文切换,唤醒10个线程是否会执行10次上下文切换?

在 JDK8 中,synchronized 锁定代码块时,如果有10个线程被阻塞等待,当锁释放后,JVM 会选取其中一个线程唤醒并获取锁,而不是唤醒所有线程来竞争锁。这种机制有助于减少上下文切换的开销和线程调度的复杂性。

具体来说,JVM 使用了一种基于队列的机制来管理被阻塞的线程。当一个线程释放锁时,JVM 从队列中选取一个等待最久的线程进行唤醒。这个被唤醒的线程将尝试获取锁,如果成功则继续执行它的任务。

关于上下文切换的问题:

  1. 唤醒一个线程:在这种情况下,JVM 只会执行一次上下文切换,即从当前持有锁的线程切换到被唤醒的线程。

  2. 唤醒所有线程:如果唤醒所有等待的线程,会引发更多的上下文切换。假设有10个线程等待,当锁释放时,所有线程被唤醒并竞争锁,这将导致多个上下文切换,因为每个线程都需要由操作系统调度并尝试获取锁。最终,只有一个线程能够成功获取锁,其他线程会再次被阻塞,从而造成不必要的上下文切换开销。

因此,JVM 选择唤醒一个线程的策略,旨在提高系统的效率和性能,避免大量不必要的上下文切换和线程调度开销。

对于 Java 中的 synchronized 锁定代码块,JVM 在处理被阻塞线程的机制如下:

  1. 锁释放后唤醒机制:当一个线程释放锁时,JVM 会唤醒一个被阻塞的线程,而不是所有等待的线程。这种唤醒策略是为了减少上下文切换和线程调度的开销。

  2. 上下文切换

    • 唤醒一个线程:仅涉及一次上下文切换,即从当前持有锁的线程切换到被唤醒的线程。
    • 唤醒所有线程:如果 JVM 唤醒所有等待的线程,会导致多个上下文切换,因为每个线程都需要被操作系统调度并尝试获取锁。这会引发更多的竞争和不必要的上下文切换。

不过,为了更准确地回答你的问题,以下是更详细的解释:

锁的具体实现细节

Java 的 synchronized 锁是依靠对象监视器 (Monitor) 实现的,在 HotSpot JVM 中,具体的锁实现包括偏向锁、轻量级锁和重量级锁。

偏向锁和轻量级锁
  • 偏向锁:主要优化单线程重入,减少锁的开销。
  • 轻量级锁:线程竞争不激烈时,用自旋等待减少上下文切换。
重量级锁
  • 当锁竞争激烈时,会升级为重量级锁。
  • 进入重量级锁的线程会被阻塞,并加入等待队列。

JVM 中的线程唤醒机制

当重量级锁被释放时,JVM 使用以下机制处理等待线程:

  1. 通知机制:锁释放时,JVM 使用条件变量 (Condition Variables) 的 notify()notifyAll() 方法。

    • notify(): 唤醒等待队列中的一个线程。
    • notifyAll(): 唤醒所有等待队列中的线程,但大多数情况下,synchronized 块默认使用类似于 notify() 的机制,唤醒一个线程。
  2. 线程调度

    • 唤醒一个线程:减少上下文切换开销,只涉及一次上下文切换。
    • 唤醒所有线程:会导致多个上下文切换,每个线程都需要被操作系统调度和尝试获取锁。

因此,当一个线程释放 synchronized 锁时,JVM 通常会选择唤醒一个线程,而不是所有等待的线程。这种策略优化了性能,避免了不必要的上下文切换和资源竞争。

综上所述,我可以确认的是:在 JDK8 中,当 synchronized 锁被释放时,JVM 会唤醒一个被阻塞的线程,而不是所有等待的线程。唤醒一个线程涉及一次上下文切换,而唤醒多个线程会导致多次上下文切换,增加系统开销。

相关文章:

synchronized关键字和ReentrantLock在不同jdk版本中性能哪个高?该怎么选择呢?

synchronized关键字和ReentrantLock在不同JDK版本中的性能差异经历了显著的变化。早期&#xff0c;在JDK 1.5及以前的版本中&#xff0c;ReentrantLock通常提供了更好的性能&#xff0c;主要是因为synchronized关键字的实现较为简单&#xff0c;没有太多的优化&#xff0c;导致…...

【旭日x3派】部署官方yolov5全流程

地平线旭日x3派部署yolov5--全流程 前言一、深度学习环境安装二、安装docker三、部署3.1、安装工具链镜像3.2、配置天工开物OpenExplorer工具包3.3、创建深度学习虚拟空间&#xff0c;安装依赖&#xff1a;3.4、下载yolov5项目源码并运行3.5、pytorch的pt模型文件转onnx3.6、最…...

java LinkedList 怎么保证线程安全

在 Java 中&#xff0c;LinkedList 本身并不是线程安全的。如果需要在多线程环境中使用 LinkedList&#xff0c;可以采取以下几种方法来保证线程安全性&#xff1a; 1. 使用 Collections.synchronizedList Java 提供了一个实用的方法 Collections.synchronizedList 来包装 Li…...

uniapp+vue3开发微信小程序踩坑集

本文主要记录使用uniappvue3开发微信小程序遇见的各种常见问题及注意点。&#xff08;持续更新&#xff09; 问题&#xff1a; 自定义组件为什么有些样式加不上去 给自定义组件增加class的时候&#xff0c;有时候不生效有时候生效&#xff0c;一度让我怀疑自己记忆错乱。后来…...

办公软件WPS与Office的区别

临近计算机考试很多同学在纠结我是报wps好&#xff1f;还是ms office好&#xff1f;下面就来详细说说。 1、wps属于国内金山公司的办公软件&#xff0c;里面包含word、Excel和PPT。考试是2021年开始的&#xff01; 2、MS&#xff08;Microsoft 微软&#xff09; office属于美…...

[数据集][目标检测]睡岗检测数据集VOC+YOLO格式3290张4类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;3316 标注数量(xml文件个数)&#xff1a;3316 标注数量(txt文件个数)&#xff1a;3316 标注…...

使用Java编写网络爬虫

使用Java编写网络爬虫 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 网络爬虫是一种自动化程序&#xff0c;用于从互联网上获取信息并收集数据。在Java中编写…...

生鲜水果行业wordpress主题

水果蔬菜wordpress外贸自建站模板 水果、脐橙、牛油果、菠萝、凤梨、鲜枣、苹果、芒果、瓜果、百香果wordpress外贸独立站模板。 https://www.jianzhanpress.com/?p3932 生鲜wordpress外贸出口网站模板 水果、蔬菜、肉蛋奶、水产、干货等生鲜产品wordpress外贸出口公司网站…...

3.3V到5V的负电源产生电路(电荷泵电压反相器)SGM3204输出电流0.2A封装SOT23-6

前言 SGM3204 非稳压 200mA 电荷泵负电源产生电路&#xff0c;LCEDA原理图请访问资源 SGM3204电荷泵负电源产生电路 SGM3204电荷泵负电源产生电路 一般描述 SGM3204从 1.4V 至 5.5V 的输入电压范围产生非稳压负输出电压。 该器件通常由 5V 或 3.3V 的预稳压电源轨供电。由于…...

Excel 宏录制与VBA编程 —— 15、MsgBox参数详解

Msgbox参数具体如下 Msgbox参数使用1 Msgbox参数使用2&#xff08;返回值示例&#xff09; &ensp ;###### 关注 笔者 - jxd...

Kafka~消息发送过程与ISR机制了解

消息发送过程 使用Kafka发送消息时&#xff0c;一般有两种方式分别是&#xff1a; 同步发送异步发送 同步发送时&#xff0c;可以在发送消息后&#xff0c;通过get方法等待消息结果&#xff0c;这种情况能够准确的拿到消息最终的发送结果&#xff0c;要么是成功、要么是失败…...

multiprocessing.Queue 多个进程生产和多个进程消费怎么处理

在这个示例中&#xff0c;我们创建了一个队列 q&#xff0c;并通过 multiprocessing.Manager().Queue() 来确保队列可以在多个进程之间共享。我们定义了 consumer 和 producer 函数&#xff0c;分别用于从队列中获取数据和向队列中放入数据。 在主进程中&#xff0c;我们创建了…...

配置 Python 解释器及虚拟环境

配置 Python 解释器及虚拟环境 配置 Python 解释器&#xff1a; 1. 打开 PyCharm&#xff0c;进入“File”&#xff08;文件&#xff09;菜单&#xff0c;选择“Settings”&#xff08;设置&#xff09;。 2. 在弹出的设置窗口中&#xff0c;选择“Project: [项目名称]”下的…...

JeecgBoot中如何对敏感信息进行脱敏处理?

数据脱敏即将一些敏感信息通过加密、格式化等方式处理&#xff0c;展示给用户一个新的或是格式化后的信息&#xff0c;避免了敏感信息的暴露。 一、接口脱敏注解 针对接口数据实现脱敏加密&#xff0c;只加密&#xff0c;一般此方案用于数据加密展示。 1.1 注解介绍 注解作用域…...

【Docker】存储数据卷

目录 1、挂载数据卷到容器里 2、查询挂载文件 3、容器与主机之间映射共享卷 4、三个容器之间使用共享卷 5、卷数据的备份与恢复 5.1 备份 5.2 恢复 1、挂载数据卷到容器里 docker run -itd --name test02 -v /data nginx docker exec -it test02 bashls / docker inspe…...

《昇思25天学习打卡营第12天 | 昇思MindSpore基于MindSpore的GPT2文本摘要》

12天 本节学习了基于MindSpore的GPT2文本摘要。 1.数据集加载与处理 1.1.数据集加载 1.2.数据预处理 2.模型构建 2.1构建GPT2ForSummarization模型 2.2动态学习率 3.模型训练 4.模型推理...

深入解析npm unpublish命令:使用场景与实践指南

npm&#xff08;Node Package Manager&#xff09;是JavaScript编程语言的包管理器&#xff0c;广泛用于Node.js应用程序。npm unpublish命令允许用户从npm仓库中撤回&#xff08;unpublish&#xff09;一个包的特定版本。本文将详细介绍npm unpublish命令的使用场景、操作步骤…...

有趣的仿神经猫html5圈小猫游戏源码

有趣的仿神经猫html5圈小猫游戏源码,点击小圆点&#xff0c;围住小猫游戏。猫已经跑到地图边缘&#xff0c;你输了。内含json数据&#xff0c;部署到服务器方可运行 微信扫码免费获取源码...

Redis 7.x 系列【10】数据类型之有序集合(ZSet)

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 本系列Redis 版本 7.2.5 源码地址&#xff1a;https://gitee.com/pearl-organization/study-redis-demo 文章目录 1. 概述2. 常用命令2.1 ZADD2.2 ZCARD2.3 ZSCORE2.4 ZRANGE2.5 ZREVRANGE2.6 ZRANK2.7…...

操作系统-文件的物理结构(文件分配方式)

文章目录 总览文件块和磁盘块连续分配顺序访问直接访问&#xff08;随机访问&#xff09;为什么连续分配同时支持这两种访问模式&#xff1f; 链接分配隐式链接显示链接小结索引分配链接方案多层索引混合索引小结 总结 总览 文件数据存放在外存中 文件块和磁盘块 文件内通过逻…...

Spring Boot集成jsoup实现html解析

1.什么是jsoup jsoup 是一款 Java 的 HTML 解析器&#xff0c;可直接解析某个 URL 地址、HTML 文本内容。它提供了一套非常省力的 API&#xff0c;可通过 DOM&#xff0c;CSS 以及类似于 jQuery 的操作方法来取出和操作数据&#xff0c;可操作 HTML 元素、属性、文本。 JSo…...

[240629] 阿里云揭秘其数据中心设计和自研网络,用于大语言模型训练 | Jina AI 发布最新的神经网络重排序模型

目录 阿里云揭秘其数据中心设计和自研网络&#xff0c;用于大语言模型训练Jina AI 发布最新的神经网络重排序模型 阿里云揭秘其数据中心设计和自研网络&#xff0c;用于大语言模型训练 阿里云近日公布了其专为大型语言模型 (LLM) 训练流量而设计的基于以太网的网络设计&#x…...

【Docker0】网络更改

目录 1. 停止docker服务 2. 关闭docker默认桥接网络接口 3. 从系统删除docker0接口 4. 创建一个名为bridge0的新接口 5. 添加ip地址和子网掩码 6. 启用bridge0接口 7. &#xff08;如果没起来就执行该句&#xff09; 8. 查看ip 1. 停止docker服务 sudo service docker…...

IDEA中导入Maven项目

IDEA中导入Maven项目 方式1&#xff1a;使用Maven面板&#xff0c;快速导入项目 打开IDEA&#xff0c;选择右侧Maven面板&#xff0c;点击 号&#xff0c;选中对应项目的pom.xml文件&#xff0c;双击即可 说明&#xff1a;如果没有Maven面板&#xff0c;选择 View > Appe…...

px、em、rem、rpx 作用和用法详解

px px像素&#xff08;Pixel&#xff09;。相对长度单位。像素px是相对于显示器屏幕分辨率而言的。 PX特点 IE无法调整那些使用px作为单位的字体大小&#xff1b; 国外的大部分网站能够调整的原因在于其使用了em或rem作为字体单位&#xff1b; Firefox能够调整px和em&#xff…...

Linux 常用命令 - dd 【复制及转换文件内容】

简介 dd 命令源自于磁盘复制&#xff08;disk dump&#xff09;的缩写&#xff0c;是 Linux 和 Unix 系统中用于转换和复制文件的一个强大工具。它可以在复制过程中进行格式转换&#xff0c;支持不同的块大小&#xff0c;能够直接对硬盘设备进行操作&#xff0c;非常适合进行备…...

全网唯一免费无水印AI视频工具!

最近Morph Studio开始免费公测&#xff01;支持高清画质&#xff0c;可以上传语音&#xff0c;同步口型&#xff0c;最重要的是生成的视频没有水印&#xff01; Morph Studio国内就可以访问&#xff0c;可以使用国内邮箱注册&#xff08;我用的163邮箱&#xff09;&#xff0c;…...

kafka(四)消息类型

一、同步消息 1、生产者 同步发送的意思就是&#xff0c;一条消息发送之后&#xff0c;会阻塞当前线程&#xff0c;直至返回 ack。 由于 send 方法返回的是一个 Future 对象&#xff0c;根据 Futrue 对象的特点&#xff0c;我们也可以实现同 步发送的效果&#xff0c;只需在调…...

Emacs之显示blame插件:blamer、git-messenger(一百四十四)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…...

【10分钟速通webpack,全流程打包,编译,发包,全干货,附代码 】

需求 后端有个nodejs 基础库&#xff0c;用typescript编写&#xff0c;需要发包到代码仓库上&#xff0c;被其它业务引入。这其中就涉及了&#xff1a; 编译&#xff0c; 打包&#xff0c;发包。 工作流速览 前提依赖 webpack主体 npm install --save-dev webpack webpack…...

设计模式深入解析与实例应用

目录 工厂模式1.简单工厂模式2.工厂方法模式3.抽象工厂模式 策略模式责任链模式概述模板方法模式概述单例模式概述 工厂模式 工厂模式是一种创建型设计模式&#xff0c;它提供了一种创建对象的最佳实践&#xff0c;旨在将对象的创建过程与使用过程分离&#xff0c;以提高代码的…...

服务器数据恢复—异常断电导致RAID6阵列中磁盘出现坏扇区的数据恢复案例

服务器存储数据恢复环境&#xff1a; 一台存储中有一组由12块SAS硬盘组建的RAID6磁盘阵列&#xff0c;划分为一个卷&#xff0c;分配给几台Vmware ESXI主机做共享存储。该卷中存放了大量Windows虚拟机&#xff0c;这些虚拟机系统盘是统一大小&#xff0c;数据盘大小不确定&…...

前端工程化08-新的包管理工具pnpm

1、历史原因解读 pnpm这个东西发布的时间是比较早的&#xff0c;但是在最近一两年的时候才开始流行&#xff0c;甚至是可以说非常的盛行&#xff0c;那么这个包到底是个什么东西的&#xff0c;那么我们先说下&#xff0c;原来的包管理工具到底有那些问题&#xff1f;比如说我们…...

章十九、JavaVUE —— 框架、指令、声明周期、Vue-cli、组件路由、Element

目录 一、 框架 ● vue.js 框架 ● 特点 ● Vue 安装 二、 第一个vue程序 ● 创建项目 ​编辑 ● 导入 vue.js ● 创建vue对象&#xff0c;设置属性&#xff0c;使用模版渲染到页面 介绍 — Vue.js (vuejs.org) 三、 vue指令 ● v-text ● v-html ● v-…...

正则表达式阅读理解

这段正则表达式可以匹配什么呢&#xff1f; 超级复杂的一段正则表达式。 ((max|min)\\s*\\([^\\)]*(,[^\\)]*)*\\)|[a-zA-Z][a-zA-Z0-9]*(_[a-zA-Z][a-zA-Z0-9]*)?(\\*||%)?|[0-9](\\.[0-9])?|\\([^\\)]*(,[^\\)]*)*\\))(\\s*[-*/%]\\s*([a-zA-Z][a-zA-Z0-9]*(_[a-zA-Z][…...

Apache Calcite Linq4j学习

Lin4j简介 Linq4j是Apache Calcite项目中的一个模块&#xff0c;它提供了类似于LINQ&#xff08;Language-Integrated Query&#xff09;的功能&#xff0c;用于在Java中进行数据查询和操作。Linq4j可以将逻辑查询转换为物理查询&#xff0c;支持对集合进行筛选、映射、分组等…...

FPGA SATA高速存储设计

今天来讲一篇如何在fpga上实现sata ip&#xff0c;然后利用sata ip实现读写sata 盘的目的&#xff0c;如果需要再速度和容量上增加&#xff0c;那么仅仅需要增加sata ip个数就能够实现增加sata盘&#xff0c;如果仅仅实现data的读写整体来说sata ip设计比较简单&#xff0c;下面…...

MySQL----为什么选择使用MySQL

在我们日常做项目的过程中&#xff0c;不论是个人还是企业&#xff0c;大多数会选择使用MySQL数据库作为后端数据库存储&#xff0c;它到底有什么优势&#xff0c;能够做到如此广为流传呢&#xff1f; 优点 稳定性&#xff1a;MySQL具有良好的稳定性和可靠性&#xff0c;能够保…...

01.音视频小白系统入门(新专栏)

目录 一、基础知识 二、音频 三、视频 四、流媒体服务器 五、收获 音视频技术在远程办公、在线教育、远程医疗等领域的应用广泛。 学习音视频技术有助于提升职业竞争力&#xff0c;满足市场需求。 掌握音视频基础知识对未来发展至关重要&#xff0c;基础不牢会导致后续学习…...

C++:enum枚举共用体union

enum枚举 C继承C的枚举用法 (1)典型枚举类型定义&#xff0c;枚举变量定义和使用 (2)枚举类型中的枚举值常量不能和其他外部常量名称冲突&#xff1a; 举例1宏定义&#xff0c;举例2另一个枚举 // 定义一个名为Color的枚举类型 enum Color {RED, // 红色&#xff0c;默认值…...

动手学深度学习(Pytorch版)代码实践 -计算机视觉-47转置卷积

47转置卷积 import torch from torch import nn from d2l import torch as d2l# 输入矩阵X和卷积核矩阵K实现基本的转置卷积运算 def trans_conv(X, K):h, w K.shapeY torch.zeros((X.shape[0] h - 1, X.shape[1] w - 1))for i in range(X.shape[0]):for j in range(X.shap…...

LinkedIn被封原因和解封方法

对于初识领英和对领英生态规则不熟悉的人来说&#xff0c;很容易造成领英账号被封号(被限制登录)的情况&#xff0c;那么如何才能避免和解决领英帐号被封号(被限制登录)的难题呢&#xff1f; 领英帐号被封号或被限制登录主要会有两类情况。 首先要搞清楚&#xff0c; Linkedi…...

redis sentinel 部署

安装Redis 建议版本不要太低 > 6.2&#xff0c;我这里是redis 7.2.5 curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg echo "deb [signed-by/usr/share/keyrings/redis-archive-keyring.gpg] http…...

spring boot (shiro)+ websocket测试连接不上的简单检测处理

1、用前端连接测试的demo一切正常&#xff0c;但是到了项目中连接不上了 一开始以为是地址错&#xff0c;但是换了apifox测试也是不可以。 2、考虑是shiro进行了拦截了&#xff0c;所以就访问不到了地址&#xff0c;那么就放行。 3、再次用apifox测试&#xff0c;成功了。 当然…...

Jenkins - Python 虚拟环境

Jenkins - Python 虚拟环境 引言Python 虚拟环境创建 Python 虚拟环境安装 virtualenv&#xff08;可选&#xff09;创建虚拟环境激活虚拟环境安装依赖包退出虚拟环境&#xff08;可选&#xff09;注意 Python 虚拟环境实践 引言 Automation 脚本通常会部署到 Jenkins 上运行&…...

每日一道算法题 面试题 08.08. 有重复字符串的排列组合

题目 面试题 08.08. 有重复字符串的排列组合 - 力扣&#xff08;LeetCode&#xff09; Python class Solution:def permutation(self, S: str) -> List[str]:# 以索引记录字符是否用过lelen(S)idx[_ for _ in range(le) ]# 组合得到的字符串combine[]*leans[]# 递归def fu…...

Apache Kylin资源管理全指南:优化你的大数据架构

标题&#xff1a;Apache Kylin资源管理全指南&#xff1a;优化你的大数据架构 摘要 Apache Kylin是一个开源的分布式分析引擎&#xff0c;旨在为大规模数据集提供高性能的SQL查询能力。在Kylin中进行有效的资源管理对于确保查询性能和系统稳定性至关重要。本文将详细介绍如何…...

计算机网络微课堂(湖科大教书匠)TCP部分

计算机网络微课堂&#xff08;湖科大教书匠&#xff09;TCP部分 【计算机网络微课堂&#xff08;有字幕无背景音乐版&#xff09;】 TCP的流量控制 一般来说&#xff0c;我们希望数据传输得更快一些。但如果发送方把数据发送得过快&#xff0c;接收方就可能来不及接收&#…...

C++ 字符串介绍

在C编程中&#xff0c;字符串是非常重要的数据类型之一。字符串用于表示文本信息&#xff0c;处理字符串是许多程序的基本需求。C提供了多种方式来处理字符串&#xff0c;包括C风格的字符串&#xff08;C-strings&#xff09;和C标准库中的std::string类。本文将介绍这两种字符…...

[Cloud Networking] BGP

1. AS (Autonomous System) 由于互联网规模庞大&#xff0c;所以网络会被分为许多 自治系统&#xff08;AS-Autonomous system&#xff09;。 所属类型ASN名称IPv4 数量IPv6数量运营商ISPAS3356LEVEL3 - Level 3 Parent, LLC, US29,798,83273,301,954,048互联网企业AS15169GO…...

HTML内容爬取:使用Objective-C进行网页数据提取

网页爬取简介 网页爬取&#xff0c;通常被称为网络爬虫或爬虫&#xff0c;是一种自动浏览网页并提取所需数据的技术。这些数据可以是文本、图片、链接或任何网页上的元素。爬虫通常遵循一定的规则&#xff0c;访问网页&#xff0c;解析页面内容&#xff0c;并存储所需信息。 …...

JavaDS预备知识

集合框架 Java 集合框架 Java Collection Framework &#xff0c;又被称为容器 container &#xff0c;是定义在 java.util 包下的一组接口 interfaces和其实现类 classes 。 其主要表现为将多个元素 element 置于一个单元中&#xff0c;对数据进行创建(Create)、读取(Retrieve…...

平安养老险宿州中心支公司积极参与“78奋力前行”集体健步行活动

7月3日&#xff0c;平安养老保险股份有限公司&#xff08;以下简称“平安养老险”&#xff09;宿州中心支公司组织员工参加由宿州市保险行业协会2024年“78奋力前行”线下集体健步行活动。 平安养老险宿州中心支公司员工高举公司旗帜&#xff0c;与同业伙伴一起出发&#xff0…...

科普文:Linux服务器性能调优概叙

概叙 Java web应用性能分析之服务端慢和优化概叙_cpu飙高java-CSDN博客 Java web应用性能分析之【CPU飙升分析概述】_web页面性能分析cpu占满是因为死循环,还是循环过多-CSDN博客 在我们的软件服务中&#xff0c;软件部署的服务器&#xff0c;一般都是linux服务器&#xff0c…...

面向对象-封装

一.包 1.简介 当我们把所有的java类都写src下的第一层级&#xff0c;如果是项目中&#xff0c;也许会有几百个java文件。 src下的文件会很多&#xff0c;开发的时候不方便查找&#xff0c;也不方便维护如果较多的文件中有同名的&#xff0c;十分麻烦 模块1中有一个叫test.ja…...

【物联网工程导论期末复习完整知识点】第四章物联网智能硬件与嵌入式

第四章物联网智能硬件与嵌入式 第四章物联网智能硬件与嵌入式嵌入式技基本概念嵌入式系统发展过程嵌入式系统的体系结构嵌入式系统的特点 物联网智能硬件智能硬件&#xff08;Intelligent Hardware&#xff09;的基本概念人工智能人机交互物联网智能硬件人机交互的特点 可穿戴计…...

将生活与出行融合揽境凭什么可以做到?

中国消费者对SUV的钟爱与热衷,堪称市场中的一股强大潮流。他们对其的认可,不仅仅停留在功能性的满足,更是对品质、品味与生活态度的追求。SUV所代表的宽敞空间、卓越通过性和引人注目的外观,恰恰迎合了中国消费者对于舒适、实用与时尚并重的需求。从整个SUV市场来看,30万级…...

年轻化的新一代迈腾,颜值并不丑,三大屏高通8155

年轻化的新一代迈腾,颜值并不丑,三大屏高通8155,像新势力中国汽车市场的竞争是越来越激烈,要想脱颖而出,即便是合资品牌旗下的主力常青树车型,现在也要拥抱变化了。就拿大众迈腾这款车来说,长期以来已经形成了一套固定的印象标签,无非就是中规中矩的沉稳商务风格。但全…...

从29W降至17W!成豪华车“价格屠夫”,190ps配四驱,月销仅401

国内汽车市场,说到豪车那么德系奔驰绝对榜上有名,作为一线豪华品牌,奔驰曾经不管是口碑还是销量都非常棒,为广大车迷上市了很多经典的标杆车型,可以毫不夸张的说,曾经只要开着一辆奔驰车回村,即便是最紧凑型的A级车,也能带来很高的回头率,地位瞬间就不一样了,可是随着…...

Nginx配置若依前后端分离项目验证码不显示,403,405,404错误解决方式

server { listen 80; server_name 域名; location / { # 静态文件服务配置&#xff08;可选&#xff09; 前端打包后的位置dist里面的文件root /www/wwwroot/web; index index.html; try_files $uri $uri/ /index.html; } # 根据文件前端项目 .env.production里面内容进…...

栈的特性及代码实现(C语言)

目录 栈的定义 栈的结构选取 链式储存结构和顺序栈储存结构的差异 栈的代码实现 "stack.h" "stack.c" 总结 栈的定义 栈&#xff1a;栈是限定仅在表尾进行插入和删除操作的线性表。 我们把运行插入的和删除的一段叫做栈顶&#xff08;TOP&#xff…...

Git-01

Git是一个免费且开源的分布式版本控制系统&#xff0c;它可以跟踪文件的修改、记录变更的历史&#xff0c;并且在多人协作开发中提供了强大的工具和功能。 Git最初是由Linus Torvalds开发的&#xff0c;用于Linux内核的开发&#xff0c;现在已经成为了广泛使用的版本控制系统&a…...