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

线程安全--深入探究线程等待机制和死锁问题

 ꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱
ʕ̯•͡˔•̯᷅ʔ大家好,我是xiaoxie.希望你看完之后,有不足之处请多多谅解,让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客
本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如需转载还请通知˶⍤⃝˶​
个人主页:xiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客

系列专栏:xiaoxie的JAVAEE学习系列专栏——CSDN博客●'ᴗ'σσணღ
我的目标:"团团等我💪( ◡̀_◡́ ҂)" 

( ⸝⸝⸝›ᴥ‹⸝⸝⸝ )欢迎各位→点赞👍 + 收藏⭐️ + 留言📝​+关注(互三必回)! 

 一.线程等待机制

1.什么是线程等待机制

线程等待机制是多线程编程中用于同步线程执行流程的一种技术,它允许一个线程暂停执行(即进入等待状态),直到满足特定条件或其他线程发送一个通知信号为止。在Java以及许多其他支持多线程的语言中,这种机制通常通过以下方式实现:

 1.wait() 方法

wait() 是 java.lang.Object 类的一个方法,当在一个对象上调用 wait() 时,当前线程必须首先获得该对象的监视器(即锁)。调用后,线程会释放对象的锁,并进入等待状态,直到被其他线程通过调用 notify() 或 notifyAll() 方法唤醒。

 2.notify() 和 notifyAll() 方法

notify() 唤醒在此对象监视器上等待的一个单个线程。notifyAll() 唤醒在此对象监视器上等待的所有线程。

2.wait() 方法和join()方法和sleep()方法的区别

我们都知道wait() 方法和join()方法和sleep()方法都是控制线程行为的方法那么它们之间有什么区别吗?

  1. wait() 方法

    • 属于 java.lang.Object 类的方法,必须在 synchronized 代码块或方法中调用,因为它依赖于对象的监视器(锁)。
    • 当调用 wait() 时,当前线程会释放所持有的对象监视器(锁),并进入等待状态,直到其他线程调用同一对象上的 notify() 或 notifyAll() 方法将其唤醒。
    • wait() 方法主要用于线程间同步与通信,它使得线程能够有条件地等待资源就绪。
  2. join() 方法

    • 属于 java.lang.Thread 类的实例方法,用于让当前线程等待调用该方法的目标线程终止。
    • 当调用 t.join() 时,当前线程将阻塞,直到线程 t 完成它的任务。
    • join() 有助于实现线程间的顺序执行,比如主线程等待子线程完成后再继续执行。
  3. sleep() 方法

    • 也是 java.lang.Thread 类的静态方法,但它并不涉及线程间的交互和同步。
    • sleep(long millis) 会让当前线程暂时停止执行一段时间,这段时间内线程不会消耗CPU资源,但仍保持“活着”的状态。
    • sleep() 方法调用期间,线程不会释放已经获取的任何锁资源。
    • 主要用于模拟延迟或防止繁忙循环消耗过多CPU资源。

总结起来:

1.wait() 是一种协调机制,用于线程间通信和同步,会释放锁并阻塞线程直到收到通知。

 2.join() 用于线程顺序控制,让一个线程等待另一个线程结束,同样会阻塞当前线程,但不涉及锁的管理。

 3.sleep() 是简单的线程暂停机制,仅影响单个线程的行为,用于暂停一定时间,不涉及线程间的通信和锁的状

3.线程等待机制的代码案例

题目要求:有三个线程,分别只能打印A,B和C要求按顺序打印ABC,打印10次

// 创建一个演示类Demo1
public class Demo1 {// 定义一个共享静态变量count,用于记录循环次数public static int count;// 程序主入口public static void main(String[] args) throws InterruptedException {// 创建一个共享的对象locker作为线程间的同步锁Object locker = new Object();// 创建线程t1,循环10次,每次检查count是否能被3整除,不能则等待,能则输出当前线程名、增加count并唤醒所有等待线程Thread t1 = new Thread(() -> {for (int i = 0; i < 10; i++) {synchronized (locker) { // 对locker对象进行同步while (count % 3 != 0) { // 如果count不是3的倍数try {locker.wait(); // 当前线程等待,释放locker锁} catch (InterruptedException e) {throw new RuntimeException(e); // 处理中断异常}}System.out.print(Thread.currentThread().getName()); // 输出当前线程名count++; // 增加count值locker.notifyAll(); // 唤醒所有等待locker锁的线程}}}, "A");// 创建线程t2,逻辑与t1类似,但检查count是否为3的倍数加1Thread t2 = new Thread(() -> {for (int i = 0; i < 10; i++) {synchronized (locker) {while (count % 3 != 1) {try {locker.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.print(Thread.currentThread().getName());count++;locker.notifyAll();}}}, "B");// 创建线程t3,逻辑与t1类似,但检查count是否为3的倍数加2Thread t3 = new Thread(() -> {for (int i = 0; i < 10; i++) {synchronized (locker) {while (count % 3 != 2) {try {locker.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println(Thread.currentThread().getName()); // 输出当前线程名并换行count++;locker.notifyAll();}}}, "C");// 启动三个线程t1.start();t2.start();t3.start();// 主线程休眠1秒,以便给其他线程运行机会Thread.sleep(1000);}
}

 输出结果:

  

在上述代码中,线程 t1t2 和 t3 分别会在满足各自条件时输出相应内容并更新 count 变量。具体过程如下:

  1. 当 t1 获取到 locker 锁后,会检查 count 是否为3的倍数。如果不是,则释放锁并调用 wait() 进入等待状态。此时,t1 不再占用锁,t2 和 t3 就有机会竞争锁。

  2. 若 t2 或 t3 其中之一成功获取锁,并满足自己的条件(即 count 为3的倍数加1或2),则会输出相应的线程名并增加 count 的值,然后调用 notifyAll() 唤醒所有等待 locker 锁的线程。

  3. 被唤醒的线程会重新开始尝试获取锁,并再次进入 while 循环检查条件。即使由于“虚假唤醒”被唤醒,由于采用了 while 循环而非 if,线程也会在未满足条件时继续等待,从而确保了正确的执行逻辑。

  4. 如此反复,直到 count 达到10*3=30,所有线程完成各自的循环,整个程序结束。在此过程中,线程间通过 wait() 和 notifyAll() 实现了同步与协作,确保了线程按序交替执行,并共同维护了对 count 变量的正确更新(count++操作是在锁内部完成的,不会出现内存可见性问题)。

注意:这里还有一个小知识点就是这里的条件判断为什么要用 while 而不是用 if?

1.多线程环境下,即使满足某个条件后调用了 wait() 方法,线程被唤醒时并不能保证条件依然成立。这是因为 notify() 或 notifyAll() 方法只会唤醒一个或所有等待的线程,但并不会立即恢复它们的执行,而是需要重新竞争锁资源。如果在当前线程被唤醒并重新获取锁之前,有其他线程改变了共享资源(如 count 变量),那么之前满足的条件可能不再满足。

2.为了确保线程安全,在进入临界区后使用 while 循环不断检查条件是一种最佳实践,这被称为“循环等待-通知”模式。只有当条件确实满足时,线程才会退出循环并执行后续操作,否则将继续等待,直到其他线程改变条件并再次唤醒它。这样可以防止出现“虚假唤醒”的问题,提高程序的健壮性。

3.当线程调用 wait() 方法时,它会释放锁并进入等待状态,直到被其他线程唤醒或者等待超时。然而,操作系统可能会出于效率或者其他因素(例如定时器精度、系统调度策略等)无预期地唤醒等待中的线程。尽管这种情况在实践中并不常见,但它是合法的,标准并未禁止此类行为。

为了避免虚假唤醒导致的错误逻辑执行,编程时推荐采用循环检查条件的方式来调用 wait() 方法,而不是简单地使用 if 判断之后立即调用 wait()

4.为什么要使用wait()方法和notify()方法

使用 wait() 和 notify() 方法的必要性和应用场景主要包括以下几点:

  1. 必要性

    • 线程同步与协作:在多线程环境中,当多个线程共享资源并且需要按照某种特定顺序或条件进行操作时,wait() 和 notify() 方法是必要的。例如,在生产者-消费者问题中,生产者线程需要在缓冲区满时等待,消费者线程在缓冲区空时等待,两者都需要对方操作后才能继续执行,这就需要用到 wait() 和 notify() 来进行线程间的有效沟通。
    • 避免资源竞争与死锁:通过适时地释放锁并进入等待状态,线程能够有效地避免资源的竞争,减少死锁发生的可能性。
    • 性能优化:相比不断地轮询检查条件是否满足(称为“忙等待”),wait() 方法可以让线程在等待条件变化时释放CPU,从而节省系统资源。
  2. 应用场景

    • 生产者-消费者模型:生产者线程负责生成数据放入共享容器,当容器满时,生产者调用 wait() 方法等待;消费者线程从容器中取出数据消费,当容器空时,消费者调用 wait() 方法等待。一旦数据产生或消耗,对应的线程会调用 notify() 方法唤醒等待的线程。
    • 资源池管理:在资源池达到最大限制时,请求新资源的线程会被阻塞,直到有线程归还资源后通过 notify() 触发等待线程继续执行。
    • 信号量控制:在复杂的并发场景中,可以通过 wait() 和 notify() 控制多个线程在多个资源之间按需分配和回收。

总之,wait() 和 notify() 方法是在多线程编程中实现高效、安全线程间通信的核心工具,它们解决了线程间的同步问题,使得不同线程可以根据预设条件有序地进行工作,极大地提高了程序设计的灵活性和并发效率。不过需要注意的是,使用这两个方法时应当遵循特定的准则,如必须在同步代码块或同步方法中调用,同时还要警惕死锁和其他并发问题的发生。在现代Java编程中,java.util.concurrent 包提供的高级并发工具(如 SemaphoreBlockingQueue(阻塞队列)CountDownLatch 等)往往更加易于理解和使用,但了解底层的 wait() 和 notify() 工作原理仍然具有重要意义。

二.死锁(面试常考)

1.什么是死锁

死锁是指在多线程或多进程环境下,两个或多个进程(或线程)在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力干涉,它们都无法向前推进(即完成各自的任务)。具体地说,每个进程都至少占有一个资源,并且正在等待另一个进程中占有的资源被释放,然而这个资源又正被等待它释放资源的进程所占有,形成了一个环形等待链,这样每个进程都在等待别的进程释放资源,从而陷入了一个永久的停滞状态。

2.MySql的死锁问题(也是面试常考)

这里既然提到了死锁问题,博主就顺便也简单说明一下MySql的死锁问题吧

MySQL数据库中的死锁(Deadlock)指的是两个或多个事务在执行过程中,由于对相同资源请求不同的锁定顺序,彼此互相等待对方释放锁定资源,从而形成的一种循环等待状态,导致事务无法正常执行下去。

MySQL中的死锁主要发生在并发事务处理过程中,当两个或多个事务尝试以不同的顺序锁定相同的资源时可能发生。例如:

  • 事务A锁定了记录R1,并试图锁定记录R2;
  • 与此同时,事务B已经锁定了记录R2,并尝试锁定记录R1;
  • 由于事务A持有R1的锁,所以事务B无法获得R1的锁,而事务B持有R2的锁,事务A也无法获得R2的锁;
  • 因此,两个事务都进入了等待对方释放资源的状态,形成了死锁。

MySQL处理死锁的方式包括:

  1. 自动检测与解决: MySQL的InnoDB存储引擎具有死锁检测机制,定期检查是否存在死锁,并在检测到死锁时自动回滚其中一个事务,使其他事务得以继续执行。

  2. 预防死锁

    • 设计应用程序时确保事务尽可能短小,减少事务锁定资源的时间。
    • 确保事务对资源的锁定顺序一致,例如按照相同的索引顺序访问表。
    • 适当设置事务的隔离级别,虽然较低的隔离级别(如读已提交)可以减少死锁的可能性,但也可能导致更多的并发问题(如不可重复读或幻读)。
  3. 手动解决

    • 当遇到死锁时,DBA可以手动分析并决定是否应该杀死其中一个或多个事务,以打破死锁循环。
  4. 应用层处理

    • 在应用程序设计层面,可以通过添加重试机制来应对可能出现的死锁,当事务因死锁被回滚时,应用层可以捕获异常并重新发起事务。
  5. 配置调整

    • 调整数据库相关的参数,如增大innodb_lock_wait_timeout,当等待锁的时间超过设定阈值时,事务将自动回滚,从而避免无限期等待。

综上所述,MySQL中的死锁问题需要结合数据库服务器的内部机制和应用程序的设计来进行综合考虑和处理。

当然,MySQL的死锁问题有很多细节值得深入探讨和扩展,下面是一些额外的点:

1.死锁的检测与处理

  1. 死锁检测算法:InnoDB存储引擎使用了一种基于等待图的死锁检测算法。每当事务请求新的锁时,都会检查是否存在循环等待的情况。如果有,InnoDB会选择牺牲(rollback)一个事务以打破死锁。

  2. innodb_deadlock_detect 参数:MySQL可以通过配置 innodb_deadlock_detect 参数来控制是否启用死锁检测功能。默认情况下,此参数为ON,表示InnoDB会积极检测死锁并在发现死锁时立即回滚一个事务。但是,关闭此选项意味着系统在等待锁超时后才有可能检测到死锁。

  3. innodb_lock_wait_timeout:这是一个影响死锁处理的重要参数,它指定了一个事务在等待锁时可以等待的最大时间(单位秒)。超时后,事务将被回滚并抛出一个错误,客户端可以根据错误代码识别死锁并选择合适的重试策略。

2.死锁的预防策略

  • 严格的事务顺序:在编写事务时,尽量保持固定的资源获取顺序,避免交叉锁定资源引起死锁。

  • 最小化锁定范围:只锁定那些真正需要修改的数据,避免不必要的大范围锁定。

  • 合理设置事务隔离级别:尽管较低的隔离级别减少了死锁的风险,但可能引入其他并发问题。根据实际需求选择合适的事务隔离级别,兼顾并发性能和一致性需求。

  • 及时提交或回滚事务:不要让事务长时间持有锁,特别是在循环中逐条处理大量记录时,应及时提交或回滚事务,释放资源。

  • 使用乐观锁或版本控制:在某些场景下,可以使用乐观锁(如CAS操作)或数据库的行版本控制机制(MVCC),这类机制在一定程度上降低了死锁发生的概率。

3.死锁监控与排查

  • SHOW ENGINE INNODB STATUS:可以查看InnoDB引擎的状态,其中包含有关最近发生的死锁的信息。

  • performance_schema:MySQL的性能模式包含了丰富的监控信息,可以帮助开发者跟踪和诊断死锁的具体情况。

  • 日志记录:通过对MySQL错误日志的监控,可以捕获到死锁相关的错误信息,帮助定位问题。

 3.Java中的死锁问题(面试常考)

1.死锁发生的必要条件(缺一不可)

  1. 互斥条件(锁的特性):至少有一个资源是不可共享的,也就是说,一段时间内仅允许一个进程使用。
  2. 持有并等待条件:已经获得了至少一个资源的进程还在等待获取其他资源,而不会释放已持有的资源。
  3. 非抢占条件(锁的特性):资源一旦被分配给一个进程,就不能被强制性地从该进程中收回,只能由进程自身主动释放。
  4. 循环等待条件:存在一个进程-资源的闭环链,每个进程都在等待下一个进程所占用的资源,循环阻塞等待了。

2.出现死锁的几个经典场景(在多线程的环境下)

1.锁顺序不一致:线程A按照顺序先锁定资源A再锁定资源B,而线程B则是先锁定资源B再锁定资源A,当两个线程同时执行时,可能因资源获取顺序不同而导致死锁

Java代码

public class Demo2 {public static void main(String[] args) {Object lockerA = new Object();Object lockerB = new Object();Thread A = new Thread(() -> {synchronized (lockerA) {System.out.println("线程A获取锁A");try {Thread.sleep(100); // 模拟处理时间} catch (InterruptedException e) {e.printStackTrace();}synchronized (lockerB) {System.out.println("线程A获取锁B");}}});Thread B = new Thread(() -> {synchronized (lockerB) {System.out.println("线程B获取锁B");try {Thread.sleep(100); // 模拟处理时间} catch (InterruptedException e) {e.printStackTrace();}synchronized (lockerA) {System.out.println("线程B获取锁A");}}});A.start();B.start();}
}

2.资源分配不当:假设线程A持有了资源R1并请求资源R2,线程B持有了资源R2并请求资源R1,这时线程A和线程B都将阻塞,形成死锁。

Java代码:

public class Demo3 {// 定义两种资源对象static class Resource {private String name;public Resource(String name) {this.name = name;}@Overridepublic String toString() {return "Resource: " + name;}}public static void main (String[]args){// 创建资源R1和R2Resource r1 = new Resource("R1");Resource r2 = new Resource("R2");// 创建线程A和线程BThread threadA = new Thread(() -> {synchronized (r1) {System.out.println(Thread.currentThread().getName() + " 获取 " + r1);synchronized (r2) {System.out.println(Thread.currentThread().getName() + " 获取 " + r2);}}}, "线程A");Thread threadB = new Thread(() -> {synchronized (r2) {System.out.println(Thread.currentThread().getName() + " 获取 " + r2);synchronized (r1) {System.out.println(Thread.currentThread().getName() + " 获取 " + r1);}}}, "线程B");// 启动线程threadA.start();threadB.start();}
}

3.经典的哲学家就餐问题:五位哲学家围绕圆桌而坐,每位哲学家有一只手拿筷子,他们需要两只筷子才能就餐。当所有哲学家都拿起左边的筷子后,大家都在等待右边筷子,形成死锁。

 4.死锁的解决方法

  1. 预防死锁

    • 资源一次性分配:一次性为进程分配所需的全部资源,这样就可以避免循环等待条件。
    • 资源有序分配:规定所有的进程都按照统一的顺序申请资源,这样可以避免循环等待。
    • 破坏请求和保持条件:要求进程在请求新资源之前释放已有资源,或者在申请资源时不立即锁定资源,而是等到可以一次性获得所有所需资源时才进行锁定。
    • 破坏不可剥夺条件:允许资源抢占,即当一个进程请求资源无法得到满足时,系统可以剥夺已经分配给其他进程但尚未使用的资源。
  2. 避免死锁

    • 动态分配资源时使用银行家算法等策略,系统在分配资源前预先计算是否有足够的资源满足所有进程的安全序列,以防止系统进入不安全状态,从而避免死锁。
  3. 检测死锁

    • 在系统中设置周期性的死锁检测机制,通过算法(如Wait-For Graph算法)来发现死锁。
    • 当检测到死锁时,采取一定的策略进行解除,如选择一个进程取消(回滚或撤销),或者选择资源进行抢占。
  4. 解除死锁

    • 撤销进程:选择一个死锁进程进行回滚,释放其所占用的资源,使其余进程得以继续执行。
    • 资源剥夺:强制从死锁进程手中剥夺部分资源,分配给其他进程,打破循环等待。
  5. 资源超时回收

    • 设置资源请求的超时时间,当请求超出指定时间仍未能获取资源时,释放已持有资源,然后重新发起请求,这样可以避免长期等待和死锁。

每种方法都有其适用场景和局限性,实际应用时需要根据系统的具体情况和性能要求选择合适的方法。在设计并发和多线程程序时,良好的编程实践和精心设计的资源管理策略也是非常重要的,例如尽量减少资源的持有时间、确保资源释放的完整性以及避免不必要的资源竞争。

以上就是关于线程安全问题的所以内容了,感谢你的阅读!

 

 

相关文章:

线程安全--深入探究线程等待机制和死锁问题

꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解&#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如需转…...

量子计算获重大突破!微软和Quantinuum将量子计算错误率降低800倍,网友:AI算力的希望

量子计算迎来新突破。 近日&#xff0c;微软和量子计算公司Quantinuum宣布&#xff1a;发现了一种新的量子计算系统&#xff0c;可以将传统量子计算的错误率下降800倍&#xff0c;这让高性能量子计算机走进现实更近了一步。 自生成式AI爆发以来&#xff0c;算力是AI发展面临的…...

WordPress 6.5 “里贾纳”已经发布

WordPress 6.5 “里贾纳”已经发布&#xff0c;其灵感来自著名爵士小提琴家Regina Carter的多才多艺。雷吉娜是一位屡获殊荣的艺术家和著名的爵士乐教育家&#xff0c;以超越流派而闻名&#xff0c;她在古典音乐方面的技术基础和对爵士乐的深刻理解为她赢得了大胆超越小提琴所能…...

甲方安全建设之日志采集实操干货

前言 没有永远的安全&#xff0c;如何在被攻击的情况下&#xff0c;快速响应和快速溯源分析攻击动作是个重要的话题。想要分析攻击者做了什么、怎么攻击进来的、还攻击了谁&#xff0c;那么日志是必不可少的一项&#xff0c;因此我们需要尽可能采集多的日志来进行分析攻击者的…...

dm8 开启归档模式

dm8 开启归档模式 1 命令行 [dmdbatest1 dm8]$ disql sysdba/Dameng123localhost:5237服务器[localhost:5237]:处于普通打开状态 登录使用时间 : 3.198(ms) disql V8 SQL> select name,status$,arch_mode from v$database;行号 NAME STATUS$ ARCH_MODE ----------…...

“AI复活”背后的数字永生:被期待成为下一个电商,培育市场认知和用户心智还需时间

“AI复活”背后的数字永生&#xff1a;被期待成为下一个电商&#xff0c;培育市场认知和用户心智还需时间© 由 九派新闻 提供 数字永生&#xff0c;还是电子宠物&#xff1f;过去一个月&#xff0c;因包小柏用AI技术让爱女在数字世界“复活”一事&#xff0c;《流浪地球2…...

基于单片机钢琴电子节拍器系统设计

**单片机设计介绍&#xff0c;基于单片机钢琴电子节拍器系统设计 文章目录 一 概要二、功能设计三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机钢琴电子节拍器系统设计是一个综合性的项目&#xff0c;它结合了单片机编程、音频处理、用户界面设计等多个领域的…...

我的创作纪念日(year Ⅱ)

大家好&#xff0c;我是Kamen Black 君&#xff0c;今天我与大家简单分享一下我两年来在CSDN的创作历程。 print("祝大家每天快乐&#xff0c;love and peace&#xff01;") 机缘 当初写博客是为了记录一些自己大学中做比赛的心得&#xff0c;没想到自己能走到这一步…...

应急响应实战笔记05Linux实战篇(1)

第1篇&#xff1a;SSH暴力破解 0x00 前言 ​ SSH 是目前较可靠&#xff0c;专为远程登录会话和其他网络服务提供安全性的协议&#xff0c;主要用于给远程登录会话数据进行加密&#xff0c;保证数据传输的安全。SSH口令长度太短或者复杂度不够&#xff0c;如仅包含数字&#x…...

重装系统之后,电脑连网卡都没反应怎么办?

前言 有些电脑比较奇葩&#xff0c;安装完成之后会出现网卡连驱动都没有&#xff0c;这时候要安装电脑驱动可是真的烦躁。怎么下手呢&#xff1f; 如果确定电脑的网卡型号还好&#xff0c;直接找个电脑下载个对应的网卡驱动&#xff0c;用U盘复制过去就能安装。 但如果不知道…...

【三十五】【算法分析与设计】综合练习(2),22。 括号生成,77。 组合,494。 目标和,模拟树递归,临时变量自动维护树定义,递归回溯,非树结构模拟树

22. 括号生成 数字 n 代表生成括号的对数&#xff0c;请你设计一个函数&#xff0c;用于能够生成所有可能的并且 有效的 括号组合。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;["&#xff08;&#xff08;&#xff08;&#xff09;&#xff09;&#xff0…...

QT智能指针

一.概述 Qt智能指针是一种能够在不需要手动管理内存的情况下&#xff0c;自动释放资源的指针。它们是C11的std::shared_ptr的一种扩展&#xff0c;可以用于管理Qt对象&#xff0c;尤其是那些不是QObject的对象。 使用智能指针可以避免内存泄露和悬垂指针等问题&#xff0c;同时…...

C++笔记之pkg-config详解,以及g++、gcc编译时使用pkg-config

C++笔记之pkg-config详解,以及g++、gcc编译时使用pkg-config —— 2024-04-05 code review 文章目录 C++笔记之pkg-config详解,以及g++、gcc编译时使用pkg-config1.pkg-config详解`pkg-config` 的基本用法在 `g++`/`gcc` 编译时使用 `pkg-config`注意事项2.示例C++,普通编译…...

[Apple Vision Pro]开源项目 Beautiful Things App Template

1. 技术框架概述&#xff1a; - Beautiful Things App Template是一个为visionOS设计的免费开源软件&#xff08;FOSS&#xff09;&#xff0c;用于展示3D模型画廊。 2. 定位&#xff1a; - 该模板作为Beautiful Things网站的延伸&#xff0c;旨在为Apple Vision Pro用户…...

Qt Remote Objects (QtRO) 笔记

简介 Qt Remote Objects (QtRO) 是 Qt 的一个进程间通信模块。 术语 Source 是指提供服务或提供功能供其他程序使用的对象&#xff0c;是 RPC 中的被调用端。 Replica 是指 Source 对象的代理对象&#xff0c;用于 RPC 中的调用端&#xff0c;对 Replica 的调用请求将被转发…...

Unity类银河恶魔城学习记录12-6.5 p128.5 Create item by Craft源代码

此章节在原视频缺失&#xff0c;此过程为根据源代码推断而来&#xff0c;并非原视频步骤 Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩…...

UE4_如果快速做出毛玻璃效果_假景深

UE4_如果快速做出毛玻璃效果_假景深 2022-08-20 15:02 一个SpiralBlur-SceneTexture材质节点完成效果&#xff0c;启用半透明材质通过修改BlurAmount数值大小调整效果spiralBlur-SceneTexture custom节点&#xff0c;HLSL语言float3 CurColor 0;float2 BaseUV MaterialFloa…...

c# wpf LiveCharts 绑定 简单试验

1.概要 c# wpf LiveCharts 绑定 简单试验 2.代码 <Window x:Class"WpfApp3.Window2"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d"http://schem…...

【Kafka】Kafka安装、配置、使用

【Kafka】安装Kafka 1. 安装Kafka2. Kafka使用2.0 集群分发脚本xsync(重要)2.0.1 scp命令2.0.2 rsync远程同步工具2.0.3 写一个集群分发脚本xsync (Shell 脚本) 2.1 Zookeeper安装2.2 对Kafka进行分发2.2.1 执行同步脚本2.2.2 三台云主机配置Kafka环境变量 1. 安装Kafka Kafka…...

2024HW-->Wireshark攻击流量分析

在HW中&#xff0c;最离不开的&#xff0c;肯定是看监控了&#xff0c;那么就要去了解一些wireshark的基础用法以及攻击的流量&#xff01;&#xff01;&#xff01;&#xff01; 1.Wireshark的基本用法 比如人家面试官给你一段流量包&#xff0c;你要会用 1.分组详情 对于我…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)

可以使用Sqliteviz这个网站免费编写sql语句&#xff0c;它能够让用户直接在浏览器内练习SQL的语法&#xff0c;不需要安装任何软件。 链接如下&#xff1a; sqliteviz 注意&#xff1a; 在转写SQL语法时&#xff0c;关键字之间有一个特定的顺序&#xff0c;这个顺序会影响到…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明

AI 领域的快速发展正在催生一个新时代&#xff0c;智能代理&#xff08;agents&#xff09;不再是孤立的个体&#xff0c;而是能够像一个数字团队一样协作。然而&#xff0c;当前 AI 生态系统的碎片化阻碍了这一愿景的实现&#xff0c;导致了“AI 巴别塔问题”——不同代理之间…...

Spring数据访问模块设计

前面我们已经完成了IoC和web模块的设计&#xff0c;聪明的码友立马就知道了&#xff0c;该到数据访问模块了&#xff0c;要不就这俩玩个6啊&#xff0c;查库势在必行&#xff0c;至此&#xff0c;它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据&#xff08;数据库、No…...

服务器--宝塔命令

一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行&#xff01; sudo su - 1. CentOS 系统&#xff1a; yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

Go 并发编程基础:通道(Channel)的使用

在 Go 中&#xff0c;Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式&#xff0c;用于在多个 Goroutine 之间传递数据&#xff0c;从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...

【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看

文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...

WebRTC从入门到实践 - 零基础教程

WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC&#xff1f; WebRTC&#xff08;Web Real-Time Communication&#xff09;是一个支持网页浏览器进行实时语音…...