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

(面试必看!)锁策略

文章导读

  • 引言
  • 考点一、重量级锁 VS 轻量级锁
      • 1、定义与原理
      • 2、主要区别
      • 3、适用场景
  • 考点二、乐观锁 VS 悲观锁
      • 1、悲观锁(Pessimistic Locking)
      • 2、乐观锁(Optimistic Locking)
      • 3、总结
  • 考点三、读写锁
      • 1、读写锁的特性
      • 2、读写锁的实现
      • 3、读写锁的使用场景
      • 4、示例代码
  • 考点四、其他常见锁策略
      • 1、自旋锁 VS 挂起等待锁
      • 2、公平锁 VS 非公平锁
      • 3、可重入锁 VS 不可重入锁
  • 考点五、锁粗化
      • 1、定义与原理
      • 2、应用场景
      • 3、优点与注意事项
      • 4、示例
  • 考点六、锁消除
      • 1、定义
      • 2、作用
      • 3、应用场景
      • 4、示例
      • 5、实现方式
      • 6、注意事项
  • 考点七、synchronized 中的锁机制
      • 1、加锁过程
      • 2、特性
      • 3、ReentrantLock 类 与 synchronized 关键字的区别
  • 八、相关面试题

引言

本篇文章接上一篇文章(一些和多线程相关的面试考点),主要讲的是多线程中一些加锁的策略和面试考点,同样的,如果读者可以认真看完和总结积累,相信对面试会有很大帮助。这一部分文字居多,读者要组织好语言以面对面试官的提问。

考点一、重量级锁 VS 轻量级锁

重量级锁与轻量级锁是并发编程中用于实现线程同步的两种重要锁机制,它们在锁的获取和释放的开销、效率以及应用场景上有所不同。

1、定义与原理

重量级锁

  • 定义:重量级锁是基于操作系统的互斥量(Mutex Lock)或信号量(Semaphore)而实现的锁,它会导致线程在用户态和内核态之间切换,相对开销较大
  • 原理当一个线程尝试获取重量级锁时,如果该锁已被其他线程持有,则当前线程会被挂起(即进入阻塞状态),并等待锁的释放。
  • 优缺点这种机制确保了资源的独占性,但也带来了较大的开销,包括上下文切换和线程调度等

轻量级锁

  • 定义:轻量级锁是相对于重量级锁而言的,它的设计初衷是在没有多线程竞争或竞争较少的情况下,减少重量级锁的使用以提高系统性能。
  • 原理:轻量级锁主要通过CAS(Compare-and-Swap)操作来实现。当一个线程尝试获取轻量级锁时,它会利用CAS操作尝试修改对象头中的状态信息。如果该锁没有被其他线程占有,那么CAS操作就会成功,当前线程就可以获取到该锁;如果该锁已被其他线程占有,那么当前线程就会不断执行CAS操作(自旋),直到该锁被释放。
  • 优缺点这样的机制保证了当前线程能够在第一时间获取到空闲的锁,但是线程不断自旋也可能会占用了大量的CPU资源。

锁升级

  • 在锁竞争不激烈的情况下,轻量级锁可以有效提高程序的运行效率,但是如果竞争锁的线程过多或线程持有锁的时间过长时,大量的线程因为得不到锁而不断地自旋,CPU资源就会被大量的占用,程序运行效率就会大打折扣。当轻量级锁无法有效处理锁竞争时,JVM会考虑将锁升级为重量级锁,让请求锁的线程释放CPU资源,阻塞等待被唤醒(自旋状态切换成阻塞状态),这一过程就叫 锁升级

2、主要区别

重量级锁轻量级锁
开销较大,涉及操作系统层面的调度和上下文切换较小,主要通过CAS操作实现,不涉及操作系统层面的切换
效率较低,特别是在竞争较少的情况下较高,在竞争较少时能够显著提高性能
适用场景适用于高度竞争的情况,确保资源的独占性适用于竞争较少或没有竞争的情况,减少不必要的开销
实现方式基于操作系统的互斥量或信号量实现基于CAS操作实现
锁升级不存在锁升级的概念,一旦获取就是重量级锁在竞争激烈时,轻量级锁可能会升级为重量级锁

3、适用场景

  • 轻量级锁适用场景:适用于锁竞争不激烈、锁持有时间短的场景。在这种场景下,轻量级锁能够快速响应并减少线程阻塞和上下文切换的开销。
  • 重量级锁适用场景:适用于锁竞争激烈、锁持有时间长的场景。重量级锁通过阻塞竞争失败的线程来避免CPU资源的浪费,并在锁释放后唤醒阻塞的线程进行后续操作。

考点二、乐观锁 VS 悲观锁

乐观锁(Optimistic Locking)和悲观锁(Pessimistic Locking)是两种处理并发控制的策略,它们在数据库管理系统(DBMS)、分布式系统以及多用户环境中广泛应用,以确保数据的一致性和完整性。这两种策略的主要区别在于它们对数据并发访问的假设以及如何处理可能的冲突。

1、悲观锁(Pessimistic Locking)

  • 假设:悲观锁假设冲突随时可能发生,因此在数据被读取时就会立即锁定,以防止其他事务对其进行修改。
  • 实现方式
    • 数据库层面:通过SQL语句实现,如使用SELECT ... FOR UPDATE语句在数据库中锁定选定的数据行,直到当前事务结束(提交或回滚)。
    • 应用层面:在应用程序中,通过某些机制(如锁对象、信号量等)在代码级别控制对共享资源的访问。
  • 优点:能有效防止数据在读取后被其他事务修改,避免脏读、不可重复读和幻读等问题。
  • 缺点:在高并发场景下,大量锁定资源可能会导致性能瓶颈,甚至死锁。

2、乐观锁(Optimistic Locking)

  • 假设:乐观锁假设冲突不会频繁发生,因此在数据读取时不会加锁,而是在更新数据时通过某种机制来检查数据是否已被其他事务修改。
  • 实现方式
    • 版本号(Version Number):为数据库表中的每一行数据添加一个版本号字段,每次更新数据时版本号加一。更新数据时,检查版本号是否与读取时一致,若一致则更新并增加版本号,否则放弃更新。
    • 时间戳(Timestamp):与版本号类似,但使用时间戳来记录数据最后更新的时间,并在更新时进行比较。
    • CAS(Compare-And-Swap):在一些高级数据库或缓存系统中,可以使用CAS操作来实现乐观锁,该操作在数据更新前会比较数据是否发生了变化。
  • 优点:系统开销小,在冲突不频繁的情况下性能较好,适合读多写少的场景。
  • 缺点:在冲突频繁的情况下,大量更新操作可能因版本冲突而失败,需要重试,增加了系统的复杂性和开销。

3、总结

选择乐观锁还是悲观锁,取决于具体的应用场景和性能需求。在冲突不频繁且对性能要求较高的系统中,乐观锁可能是一个更好的选择;而在冲突频繁或需要严格保证数据一致性的系统中,悲观锁可能更为合适。此外,还可以根据业务需求和数据库特性,结合使用两种锁策略来达到最佳效果。

考点三、读写锁

读写锁(Readers-Writer Lock)是一种用于并发编程中的同步机制,它允许多个线程同时读取共享资源,但在写入时需要独占访问权限。这种锁分为读锁和写锁两部分,各自具有不同的特性和使用场景。

1、读写锁的特性

  1. 读读不互斥:多个线程可以同时获得读锁,因为读操作通常是线程安全的,不会修改数据。
  2. 读写互斥:读锁和写锁不能同时被持有,即当有一个线程持有写锁时,其他线程不能获取读锁或写锁;同样,当有一个线程持有读锁时,其他线程不能获取写锁。
  3. 写写互斥:多个线程不能同时获得写锁,因为写操作会修改数据,需要独占访问权限。

2、读写锁的实现

在Java中,读写锁通常通过ReentrantReadWriteLock类实现。这个类提供了读锁(ReadLock)和写锁(WriteLock)的获取和释放方法。

  • 公平性选择ReentrantReadWriteLock支持非公平性(默认)和公平性的锁获取方式。非公平锁的吞吐量较高,但可能导致线程饥饿;公平锁则按照请求锁的顺序来授予锁,但可能降低性能。
  • 重入性:支持重入,即同一个线程可以多次获取读锁或写锁,避免死锁。
  • 锁降级:写锁可以降级为读锁,即持有写锁的线程可以获取读锁后再释放写锁,这有助于提升并发性能。但需要注意的是,锁升级(在持有读锁的情况下获取写锁)是不被支持的。

3、读写锁的使用场景

读写锁特别适用于读多写少的场景,如缓存系统、数据库访问、文件系统操作和消息队列等。在这些场景中,读操作远远超过写操作,使用读写锁可以显著提高并发性能。

  • 缓存系统:允许多个线程同时读取缓存数据,但只有一个线程可以进行缓存的更新或写入操作。
  • 数据库访问:多个线程可以同时读取数据库中的数据,但只有一个线程可以进行写入操作(如更新、插入或删除记录)。
  • 文件系统操作:多个线程可以同时读取文件内容,但只有一个线程可以进行写入操作(如修改文件内容或更新文件属性)。
  • 消息队列:多个线程可以同时从队列中读取消息,但只有一个线程可以进行向队列中添加或删除消息的操作。

4、示例代码

以下是一个简单的Java示例,演示了如何使用ReentrantReadWriteLock

import java.util.concurrent.locks.ReentrantReadWriteLock;public class DataContainer {private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();private int data = 0;public void writeData(int newValue) {lock.writeLock().lock();try {data = newValue;System.out.println("写入数据: " + data);} finally {lock.writeLock().unlock();}}public void readData() {lock.readLock().lock();try {System.out.println("读取数据: " + data);} finally {lock.readLock().unlock();}}
}

在这个示例中,DataContainer类包含了一个整数data作为共享资源,以及一个ReentrantReadWriteLock对象来控制对data的访问。writeData方法使用写锁来确保在写入data时没有其他线程可以读取或写入它,而readData方法则使用读锁来允许多个线程同时读取data

考点四、其他常见锁策略

1、自旋锁 VS 挂起等待锁

  • 自旋锁

    • 定义自旋锁是一种轻量级的锁,在尝试获取锁时,如果锁已被其他线程持有,则当前线程会不断循环检查锁的状态,而不是进入睡眠状态等待锁被释放。
    • 优点
      • 响应快:由于线程在等待锁时不会进入睡眠状态,因此一旦锁被释放,线程可以立即获取锁,减少了线程唤醒和调度的时间开销。
      • 避免上下文切换:自旋锁避免了线程在等待锁时的上下文切换,从而减少了系统资源的消耗。
    • 缺点
      • CPU资源浪费:如果锁被持有时间较长,自旋的线程会长时间占用CPU资源,导致CPU资源的浪费。
      • 适用场景有限:自旋锁适用于锁被持有时间较短的场景,如果锁被持有时间较长,使用自旋锁会导致性能下降。
  • 挂起等待锁

    • 定义挂起等待锁是一种重量级的锁机制,在尝试获取锁时,如果锁已被其他线程持有,则当前线程会被挂起(即进入等待队列),直到锁被释放后由操作系统唤醒。
    • 优点
      • 避免CPU资源浪费:线程在等待锁时被挂起,不会占用CPU资源,从而避免了CPU资源的浪费。
      • 适用场景广泛:挂起等待锁适用于锁被持有时间较长的场景,以及线程竞争激烈的情况。
    • 缺点
      • 线程唤醒开销大:线程被唤醒时需要进行上下文切换,这会增加系统的开销。
      • 可能导致死锁:在复杂的并发场景中,如果不当使用挂起等待锁,可能会导致死锁的发生。

2、公平锁 VS 非公平锁

  • 公平锁(Fair Lock)

    • 定义:公平锁是一种按照请求顺序授予锁的机制,即先请求锁的线程会先获得锁,后请求锁的线程会后获得锁。
    • 特性
      • 避免饥饿:所有线程都有机会获得锁,不会出现某些线程长期得不到锁的情况。
      • 可预测性:锁的获取是按顺序进行的,具有较好的可预测性。
      • 性能开销:由于需要维护一个队列来管理等待的线程,公平锁在管理上有一定的性能开销。
      • 上下文切换增加:由于公平锁可能需要频繁地切换线程,导致上下文切换的次数增加,影响性能。
  • 非公平锁(Unfair Lock)

    • 定义:非公平锁是一种不按照请求顺序授予锁的机制,即任何线程都有可能在任何时候获得锁,而不考虑请求顺序。
    • 特性
      • 高性能:由于没有队列管理的开销,非公平锁通常性能较高,特别是在高并发场景下。
      • 减少上下文切换:非公平锁可以减少线程之间的上下文切换,提升效率。
      • 可能导致饥饿:某些线程可能长时间得不到锁,导致线程饥饿。
      • 不可预测性:锁的获取是随机的,具有较低的可预测性。
  • 应用场景与选择

    • 公平锁:适用于需要保证线程获取锁的顺序和公平性的场景,如需要避免线程饥饿或保证任务处理的顺序性。
    • 非公平锁:适用于对性能要求较高,且可以接受一定程度线程饥饿现象的场景。在高并发环境下,非公平锁可以提高系统的吞吐量。

3、可重入锁 VS 不可重入锁

  • 可重入锁:可重入锁,也称为递归锁,是一种支持同一个线程多次获取同一把锁的锁机制。这意味着,如果一个线程已经持有某个锁,它仍然可以在其内部递归地再次获取该锁,而不会导致死锁。
  • 不可重入锁:不可重入锁是一种不支持同一个线程多次获取同一把锁的锁机制。当一个线程已经持有某个不可重入锁时,如果它再次尝试获取该锁,则会被阻塞,直到当前持有锁的线程释放锁。

考点五、锁粗化

锁粗化(Lock Coarsening)是一种编译器优化技术,主要用于改进多线程程序中的锁性能。这种技术通过将多个连续的、独立的锁操作合并为一个更大的锁操作,从而减少锁的竞争次数,提高程序的执行效率。以下是对锁粗化的详细解释:

1、定义与原理

  • 定义:锁粗化是将多个连续的、对同一个对象进行加锁和解锁的操作合并为一个更大的锁操作的过程。
  • 原理:在多线程编程中,频繁的加锁和解锁操作会带来额外的性能开销,包括线程切换和调度等。通过将多个小锁合并为大锁,可以减少锁的获取和释放次数,从而降低这些开销,提高程序性能。

2、应用场景

锁粗化通常用于以下场景:

  • 当编译器检测到代码中存在多个连续的、对同一个对象进行加锁和解锁的操作,且这些操作之间没有其他代码干扰时,会考虑进行锁粗化
  • 在Java中,锁粗化常用于优化循环体内的锁操作。如果循环体内有多个对同一对象的同步块,编译器可能会将这些同步块合并为一个大的同步块

3、优点与注意事项

  • 优点
    • 减少锁的获取和释放次数,降低线程切换和调度的开销。
    • 提高程序在并发环境下的执行效率。
  • 注意事项
    • 锁粗化并非总是能提高程序性能,其效果取决于具体的场景和代码实现。
    • 在某些情况下,锁粗化可能会导致锁竞争加剧,因为单个线程持有锁的时间变长,其他线程需要等待更长的时间才能获得锁
    • 锁粗化是编译器或运行时系统自动完成的,开发者无需手动干预,但可以通过编写高质量的代码来配合这种优化

4、示例

假设有以下Java代码:

public void processData(List<Data> dataList) {for (Data data : dataList) {synchronized (this) {// 处理数据的代码块1}// 一些无关的代码synchronized (this) {// 处理数据的代码块2}}
}

在这个例子中,每个循环迭代中都对this对象进行了两次加锁和解锁操作。编译器可能会将这些连续的锁操作合并为一个大的锁操作,从而优化代码性能。

考点六、锁消除

锁消除(Lock Elimination)是一种用于优化多线程程序中锁性能的技术,主要通过编译器或运行时系统在代码优化阶段,通过静态分析或动态优化检测到某些情况下不需要进行同步的代码块,并将其对应的锁操作去除。以下是关于锁消除的详细解释:

1、定义

锁消除是编译器或运行时系统在代码优化阶段,识别并消除不必要的锁操作的一种优化技术。其目标是通过减少不必要的同步操作来提高程序的性能。

2、作用

  • 提高性能:通过消除不必要的锁操作,减少了线程之间的同步开销,提高了程序的执行效率。
  • 减少资源消耗:锁的创建、销毁和同步操作都需要消耗系统资源,锁消除有助于减少这些资源的消耗。

3、应用场景

锁消除通常应用于以下场景:

  • 当一个锁只在单线程中使用时,该锁可以被消除,因为不存在多线程竞争的情况。
  • 当一个共享变量在程序中只被读取而不被修改时,对该变量的访问不需要加锁,因此可以消除相关的锁操作。

4、示例

假设有以下Java代码片段:

public class Counter {private int count = 0;public synchronized void increment() {count++;}public void process() {Counter counter = new Counter();for (int i = 0; i < 1000000; i++) {counter.increment();}}
}

在这个例子中,increment方法被synchronized关键字修饰,意味着每次调用时都会进行加锁和解锁操作。然而,如果编译器或运行时系统通过静态分析发现Counter对象在process方法内部被创建且不会被外部线程访问,那么它就可以推断出increment方法中的锁操作是不必要的,从而进行锁消除。

5、实现方式

锁消除的实现主要依赖于编译器或运行时系统的优化能力。编译器通过静态分析代码,识别出不需要进行同步的代码块,并在优化阶段将其中的锁操作去除。运行时系统则可能通过动态监控程序的运行情况,收集相关信息以辅助优化决策。

6、注意事项

  • 锁消除可能会引入潜在的并发问题,因此在进行锁消除时需要谨慎,确保消除的锁确实不会引起并发访问冲突。
  • 锁消除一般适用于具有良好的代码结构和线程安全性的程序。对于复杂的程序或存在线程安全问题的程序,可能不适合进行锁消除。

考点七、synchronized 中的锁机制

1、加锁过程

synchronized 关键字在Java中被JVM划分成4个状态:无锁,偏向锁,轻量级锁,重量级锁。这4个状态其实就是锁升级的过程,且该过程是不可逆的,如无法从重量级锁转变成轻量级锁,但可以从轻量级锁转变成重量级锁。

  • 无锁状态:初始时默认 synchronized 修饰的对象是不加锁的(乐观锁特性),即认为不存在资源竞争。
  • 偏向锁:当发现存在资源竞争时,synchronized 会给对象头加上一层 ”偏向锁标记“,记录这个锁属于哪个线程(此时并没有真正加锁),如果后续没有其他线程来竞争资源,那么就不用加锁,反之就会从偏向锁状态进入轻量级锁。
  • 轻量级锁:随着锁的竞争加剧,线程就会进入轻量级锁的状态,占用CPU资源,不断自旋直到加锁成功。
  • 重量级锁:当锁竞争达到一定程度,轻量级锁无法处理时,synchronized 会使线程进入重量级锁状态,请求锁的线程阻塞等待,释放CPU资源,直到锁被释放后才被唤醒。

2、特性

在以上加锁过程中可以总结出以下 synchronized 的特性:

  1. 既是乐观锁,也是悲观锁
  2. 既是轻量级锁,也是重量级锁
  3. 是可重入锁
  4. 是非公平锁
  5. 不是读写锁

3、ReentrantLock 类 与 synchronized 关键字的区别

ReentranLock 是可重⼊互斥锁,和synchronized定位类似,都是⽤来实现互斥效果,保证线程安全
区别

  • ReentrantLock 类有独立的加锁(lock),超时加锁(trylock,尝试加锁一段时间后得不到锁就放弃)和解锁(unlock)操作,加锁解锁需要手动设置,而 synchronized 关键字是全自动的。

  • synchronized是非公平锁,ReentrantLock默认是⾮公平锁,但是可以通过构造方法传入⼀个 true 开启公平锁模式。

    // ReentrantLock 
    的构造⽅法public ReentrantLock(boolean fair) {sync = fair ? new FairSync() : new NonfairSync();}
    
  • 更强⼤的唤醒机制。synchronized 是通过 Object 的 wait/notify 实现等待-唤醒。每次唤醒的是⼀个随机等待的线程。ReentrantLock 搭配 Condition类实现等待-唤醒,可以更精确控制唤醒某个指定的线程。

    总结
    在锁竞争不太激烈的情况下使用 synchronized 关键字可以提高效率,但是在锁竞争激烈的情况下,使用ReentrantLock 可以更加灵活的调整加锁行为,防止因死等而拖慢程序运行效率。

八、相关面试题

还是一样,相关面试题不会给出具体答案,需要读者自己总结。

  1. 你是怎么理解乐观锁和悲观锁的,具体怎么实现呢?
  2. 介绍下读写锁?
  3. 什么是⾃旋锁,为什么要使⽤⾃旋锁策略呢,缺点是什么?
  4. 什么是偏向锁?
  5. synchronized 实现原理是什么?

相关文章:

(面试必看!)锁策略

文章导读 引言考点一、重量级锁 VS 轻量级锁1、定义与原理2、主要区别3、适用场景 考点二、乐观锁 VS 悲观锁1、悲观锁&#xff08;Pessimistic Locking&#xff09;2、乐观锁&#xff08;Optimistic Locking&#xff09;3、总结 考点三、读写锁1、读写锁的特性2、读写锁的实现…...

RAGflow:开源AI框架的创新与应用

在当今科技飞速发展的时代&#xff0c;人工智能&#xff08;AI&#xff09;已经成为各行各业不可或缺的一部分。特别是在文档处理和数据分析领域&#xff0c;AI的应用更是无处不在。今天&#xff0c;我要向大家介绍一个开源的AI框架引擎——RAGflow。它能够在深度文档理解方面执…...

AI的学习明确路径

1.不要一开始学习数学。 首先&#xff0c;学习python的语法和工具包。 python的工具包有&#xff1a;numpy,pandas,matlap,sciklt-learn. 然后&#xff0c;学习机械学习算法&#xff0c;学习1.树模型&#xff0c;随机森林 。 2.神经网络。 上kaggle中&#xff0c;找人家的经…...

【C++】巧用缺省参数与函数重载:提升编程效率的秘密武器

C语法相关知识点可以通过点击以下链接进行学习一起加油&#xff01;命名空间 本章将分享缺省参数与函数重载相关知识&#xff0c;为了更加深入学习C打下了坚实的基础。本章重点在于缺省参数与函数重载使用前提与注意事项 &#x1f308;个人主页&#xff1a;是店小二呀 &#x1…...

mysql排查死锁的几个查询sql

SHOW PROCESSLIST; select * from information_schema.INNODB_TRX; select * from information_schema.INNODB_LOCKS; select * from information_schema.INNODB_LOCK_WAITS;...

快速部署私有化大模型 毕昇(使用docker-compose方式)

docker安装 1. # Linux系统安装docker&#xff0c;以CentOS/RHEL为例&#xff0c;其他操作系统请参考docker官方安装方法 # 如果已经安装过docker 期望重装&#xff0c;先卸载 sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \d…...

B端:导航条就框架提供的默认样式吗?非也,看过来。

导航条不一定必须使用框架提供的默认样式&#xff0c;你可以根据项目需求和设计风格进行自定义。通过使用框架提供的自定义选项、CSS样式覆盖、自行设计或者使用其他UI库或组件&#xff0c;你可以实现独特且符合需求的导航条样式。 下面发一些参考给友友们&#xff0c;可以让设…...

idea的git与SVN切换

1、选择setting->Version Control&#xff0c;新增或者编辑&#xff0c;选择目录&#xff0c;使用git或者svn管理 2、选择项目中的vcs.xml,打开选择要用的&#xff0c;注释掉不用的版本即可...

互联网家政小程序,为大众带来高效、便捷的服务

随着人口老龄化的严重和社会生活节奏的加快&#xff0c;大众对家政服务的需求日益增加&#xff0c;家政行业的市场规模逐渐扩大&#xff01; 在科技的推动下&#xff0c;家政行业开始向数字化发展&#xff0c;“互联网家政”的模式推动了市场的快速发展。互联网家政小程序借助…...

【常用库】【pytorch】基本部件

基本元件 1. 卷积 2. batchnorm loss函数 torch.nn.MSELoss() >>> a torch.rand(3) >>> a tensor([0.2161, 0.2227, 0.9175]) >>> b torch.rand(3) >>> b tensor([0.6976, 0.9149, 0.4918]) >>> mse torch.nn.MSELOSS() &…...

深入Scrapy框架:掌握其工作流程

深入Scrapy框架&#xff1a;掌握其工作流程 引言 作为一名资深的Python程序员&#xff0c;我对各种数据采集工具有着深刻的理解。Scrapy&#xff0c;作为一个上场率极高的爬虫框架&#xff0c;以其高效、灵活和强大的特性&#xff0c;成为数据采集领域的不二选择。在本文中&a…...

从零开始学习机器学习,掌握AI未来的关键!

从零开始学习机器学习 1. 介绍1.1 人工智能&#xff08;AI&#xff09;概述1.2 机器学习在人工智能中的应用1.3 机器学习基础概念 2. 监督学习2.1 什么是监督学习2.2 回归分析2.3 分类问题2.4 模型评估和选择 3. 无监督学习3.1 什么是无监督学习3.2 聚类算法3.3 降维技术 4. 深…...

CI/CD(持续集成/持续部署)

CI/CD(持续集成/持续部署)是软件开发过程中的一种方法,旨在提高开发效率和软件质量。以下是对CI/CD的具体解释: 1.持续集成(Continuous Integration,CI): 概念:开发人员将代码频繁地合并到主分支中,每次提交都会触发自动化构建和测试过程。目的:及时发现和修复集成…...

实现字母的大小写转换。多组输入输出(c语言)

1.我们先输入字母&#xff08;用getchar的函数&#xff09;&#xff0c;判断是不是字母&#xff0c;我们可以用a<tmp<z或者A<tmp<Z,注意&#xff1a;小写转换大写用tmp-32&#xff0c;大写转换小写用tmp32.. #include<stdio.h> int main() {int a 0;while …...

2024华为OD机试真题-最小矩阵宽度Python-C卷D卷-200分

2024华为OD机试题库-(C卷+D卷)-(JAVA、Python、C++) 题目描述 给定一个矩阵,包含 N * M 个整数,和一个包含 K 个整数的数组。 现在要求在这个矩阵中找一个宽度最小的子矩阵,要求子矩阵包含数组中所有的整数。 输入描述 第一行输入两个正整数 N,M,表示矩阵大小。 接下来 N …...

【Vue3】标签的 ref 属性

【Vue3】标签的 ref 属性 背景简介开发环境开发步骤及源码 背景 随着年龄的增长&#xff0c;很多曾经烂熟于心的技术原理已被岁月摩擦得愈发模糊起来&#xff0c;技术出身的人总是很难放下一些执念&#xff0c;遂将这些知识整理成文&#xff0c;以纪念曾经努力学习奋斗的日子。…...

llama-factory 系列教程 (六),linux shell 脚本自动实现批量大模型的训练、部署与评估

背景 最近在做大模型微调训练的评估&#xff0c;每次都要手动训练大模型&#xff0c;手动评估。 发现这样太浪费时间了&#xff0c;于是就尝试着使用linux shell 脚本&#xff0c;利用 for 循环自动实现大模型的训练、部署与评估。 实验&#xff1a;在不同的文本分类数据集尺…...

python安全脚本编写之流量泛洪

多线程与流量泛洪 并发操作 如果一个单核的cpu&#xff0c;是并不存在严格意义的并发&#xff0c;只是因为处理时间极短&#xff0c;所以感觉上是并发操作的。 针对多核CPU&#xff0c;4核CPU&#xff0c;严格意义上的并发处理是4个 线程和进程 每一个应用程序&#xff0c;至少…...

一文看懂Java反射、注解、UML图和Lambda表达式

反射 定义: 反射是 java 开发语言的特征之一&#xff0c;它允许 java 程序对自身进行检查(自审)&#xff0c;并能直接操作程序内部属性&#xff0c;即就是将类中的各种成分映射成一个 java 对象&#xff0c;利用反射技术可以对一个类进行解剖&#xff0c;将各个组成部分映射成…...

【漏洞复现】搜狗输入法简单绕过Windows锁屏机制

免责申明 本公众号的技术文章仅供参考&#xff0c;此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等&#xff08;包括但不限于&#xff09;进行检测或维护参考&#xff0c;未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息…...

JAVA Spring学习Day1

Maven Maven配置&#xff1a; Maven是Java项目的构建工具&#xff0c;使用pom.xml配置文件管理项目依赖、插件和构建目标。Spring Boot项目搭建&#xff1a; Spring Boot是基于Spring框架的快速开发框架&#xff0c;通过约定大于配置的理念简化了Spring应用的搭建和开发。 …...

linux常见面试题(三)

18 什么事SQL注入 由于程序员的水平及经验参差不齐&#xff0c;大部分程序员在编写代码的时候&#xff0c;没有对用户输入数据的合法性进行判断。 ​ 应用程序存在安全隐患。用户可以提交一段数据库查询代码&#xff0c;根据程序返回的结果&#xff0c;获得某些他想得知的数据…...

【JS】ES6新类型Map与Set

一、Map Map 对象保存键值对&#xff0c;并且能够记住键的原始插入顺序。任何值&#xff08;对象或者原始值&#xff09;都可以作为键或值。 描述 Map 对象是键值对的集合。Map 中的一个键只能出现一次&#xff1b;它在 Map 的集合中是独一无二的。 Map 对象按键值对迭代——…...

FETCH FIRST ROW ONLY和 DISTINCT ON和 LIMIT 1的用法

以下是 PostgreSQL 中函数 FETCH FIRST ROW ONLY、DISTINCT ON 和 LIMIT 1 的用法、含义、例子以及适用版本的信息总结&#xff1a; FETCH FIRST ROW ONLY 用法和含义 FETCH FIRST ROW ONLY 用于限制查询结果集&#xff0c;只返回第一行。它可以和 ORDER BY 子句一起使用&am…...

前端小白安装node、vue、Express、Electron及(Electron桌面端exe应用开发)

一、node.js &#xff08;一&#xff09;、下载 下载地址 Node.js — 在任何地方运行 JavaScript (nodejs.org) 参考文章&#xff1a;Node.js安装及环境配置超详细教程【Windows系统】_windows 安装nodejs-CSDN博客 &#xff08;二&#xff09;、安装 安装路径可以更换&a…...

solidity多态【很重要】

多态是面向对象编程&#xff08;OOP&#xff09;的一个核心概念&#xff0c;允许不同类的对象被视为同一类型的实例&#xff0c;并根据实际类型来响应相同的方法调用。 这意味着同一个接口可以用来引用属于不同类的对象&#xff0c;而这些对象可以有自己的方法实现&#xff0c…...

Jangow-1.0.1靶机漏洞复现(未完成)

首先&#xff0c;这个靶机只能使用VirtualBox打开&#xff0c;靶机下载地址为 https://download.vulnhub.com/jangow/jangow-01-1.0.1.ova 虚拟机软件下载地址为 Download_Old_Builds – Oracle VM VirtualBox 开启靶机后访问ip进入如下页面&#xff0c;点击site进入到一个…...

软件测试--python基础

一、python基础 (1)第一个python (2)python解释器 (3)基础语法 ①字面量 什么是字面量 常用的值类型 字符串 ②注释 ③变量 什么是变量 变量的特征 变量的目的是存储运行过程的数据 存储的目的是为了&#xff1a;重复使用 ④数据类型 type()语句 变量有类型吗&#xff1f;…...

GPIO子系统

1. GPIO子系统视频概述 1.1 GPIO子系统的作用 芯片内部有很多引脚&#xff0c;这些引脚可以接到GPIO模块&#xff0c;也可以接到I2C等模块。 通过Pinctrl子系统来选择引脚的功能(mux function)、配置引脚&#xff1a; 当一个引脚被复用为GPIO功能时&#xff0c;我们可以去设…...

学会这个Python库,接口测试so easy

前言 我们在做接口测试时&#xff0c;大多数返回的都是json属性&#xff0c;我们需要通过接口返回的json提取出来对应的值&#xff0c;然后进行做断言或者提取想要的值供下一个接口进行使用。 但是如果返回的json数据嵌套了很多层&#xff0c;通过查找需要的词&#xff0c;就…...

永久免费网站建设/长沙网站优化排名推广

关注"无线技术联盟"提供有价值的物联网市场信息和最新的技术分析利用Python爬取了蓝牙联盟上近一年BQB认证公司的清单&#xff0c;把爬到的有价值的东西写出来分享给大家。1蓝牙认证产品如果配备了蓝牙功能且要在产品外观上注明蓝牙的标识在国际市场上流通&#xff0…...

公司网站要多少钱/爱站网排行榜

...

辽宁省城乡建设网站/深圳网络营销策划公司

XML三种解析方式&#xff1a; SAX解析&#xff1a;基于事件驱动&#xff0c;事件机制基于回调函数的&#xff0c;得到节点和节点之间内容时也会回调事件 PULL解析&#xff1a;相同基于事件驱动&#xff0c;仅仅只是回调时是常量 DOM解析&#xff1a;是先把XML文件装入内存中。在…...

浪漫免费表白网站/湖南seo网站开发

以下所说的所有东西若要服用药物以补充&#xff0c;则不可过量服用&#xff0c;过量服用容易引起早熟(不一定会中毒)&#xff0c;早熟则停止成长发育&#xff0c;导致身体只长宽度不长高度。 一、延缓骨骺线闭合 想要长高不要在骨骺线上下功夫。 因为在人体内激素是一个很麻烦的…...

专门做玉的网站/seo的概念是什么

微服务技术栈选型&#xff0c;看了这个别的可以不用看了 摘要&#xff1a; 本文由PPmoney架构师敖小剑分享&#xff1a;微服务的核心技术&#xff0c;目前可选的开源微服务框架&#xff0c;以及为微服务提供支撑的基础设施。 前言 大家好&#xff0c;我是敖小剑&#xff0c;…...

电商平台网站制作费用/百度排名怎么做

1案例一 下图显示一个递归函数 假设内存有一块空间&#xff0c;这个程序可以用 &#xff0c;N传进来部为0&#xff0c;它递归调用PrintN&#xff0c;传进去99999 ,调用这个函数前要把printN&#xff08;100000&#xff09;状态存进内存&#xff0c;执行完在恢复。最后存在系统…...