线程安全--深入探究线程等待机制和死锁问题
꒵˂͈꒱ 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()方法都是控制线程行为的方法那么它们之间有什么区别吗?
-
wait() 方法
- 属于
java.lang.Object
类的方法,必须在synchronized
代码块或方法中调用,因为它依赖于对象的监视器(锁)。 - 当调用
wait()
时,当前线程会释放所持有的对象监视器(锁),并进入等待状态,直到其他线程调用同一对象上的notify()
或notifyAll()
方法将其唤醒。 wait()
方法主要用于线程间同步与通信,它使得线程能够有条件地等待资源就绪。
- 属于
-
join() 方法
- 属于
java.lang.Thread
类的实例方法,用于让当前线程等待调用该方法的目标线程终止。 - 当调用
t.join()
时,当前线程将阻塞,直到线程t
完成它的任务。 join()
有助于实现线程间的顺序执行,比如主线程等待子线程完成后再继续执行。
- 属于
-
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);}
}
输出结果:
在上述代码中,线程 t1
、t2
和 t3
分别会在满足各自条件时输出相应内容并更新 count
变量。具体过程如下:
-
当
t1
获取到locker
锁后,会检查count
是否为3的倍数。如果不是,则释放锁并调用wait()
进入等待状态。此时,t1
不再占用锁,t2
和t3
就有机会竞争锁。 -
若
t2
或t3
其中之一成功获取锁,并满足自己的条件(即count
为3的倍数加1或2),则会输出相应的线程名并增加count
的值,然后调用notifyAll()
唤醒所有等待locker
锁的线程。 -
被唤醒的线程会重新开始尝试获取锁,并再次进入
while
循环检查条件。即使由于“虚假唤醒”被唤醒,由于采用了while
循环而非if
,线程也会在未满足条件时继续等待,从而确保了正确的执行逻辑。 -
如此反复,直到
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()
方法的必要性和应用场景主要包括以下几点:
-
必要性:
- 线程同步与协作:在多线程环境中,当多个线程共享资源并且需要按照某种特定顺序或条件进行操作时,
wait()
和notify()
方法是必要的。例如,在生产者-消费者问题中,生产者线程需要在缓冲区满时等待,消费者线程在缓冲区空时等待,两者都需要对方操作后才能继续执行,这就需要用到wait()
和notify()
来进行线程间的有效沟通。 - 避免资源竞争与死锁:通过适时地释放锁并进入等待状态,线程能够有效地避免资源的竞争,减少死锁发生的可能性。
- 性能优化:相比不断地轮询检查条件是否满足(称为“忙等待”),
wait()
方法可以让线程在等待条件变化时释放CPU,从而节省系统资源。
- 线程同步与协作:在多线程环境中,当多个线程共享资源并且需要按照某种特定顺序或条件进行操作时,
-
应用场景:
- 生产者-消费者模型:生产者线程负责生成数据放入共享容器,当容器满时,生产者调用
wait()
方法等待;消费者线程从容器中取出数据消费,当容器空时,消费者调用wait()
方法等待。一旦数据产生或消耗,对应的线程会调用notify()
方法唤醒等待的线程。 - 资源池管理:在资源池达到最大限制时,请求新资源的线程会被阻塞,直到有线程归还资源后通过
notify()
触发等待线程继续执行。 - 信号量控制:在复杂的并发场景中,可以通过
wait()
和notify()
控制多个线程在多个资源之间按需分配和回收。
- 生产者-消费者模型:生产者线程负责生成数据放入共享容器,当容器满时,生产者调用
总之,wait()
和 notify()
方法是在多线程编程中实现高效、安全线程间通信的核心工具,它们解决了线程间的同步问题,使得不同线程可以根据预设条件有序地进行工作,极大地提高了程序设计的灵活性和并发效率。不过需要注意的是,使用这两个方法时应当遵循特定的准则,如必须在同步代码块或同步方法中调用,同时还要警惕死锁和其他并发问题的发生。在现代Java编程中,java.util.concurrent
包提供的高级并发工具(如 Semaphore
、BlockingQueue(阻塞队列)
、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处理死锁的方式包括:
-
自动检测与解决: MySQL的InnoDB存储引擎具有死锁检测机制,定期检查是否存在死锁,并在检测到死锁时自动回滚其中一个事务,使其他事务得以继续执行。
-
预防死锁:
- 设计应用程序时确保事务尽可能短小,减少事务锁定资源的时间。
- 确保事务对资源的锁定顺序一致,例如按照相同的索引顺序访问表。
- 适当设置事务的隔离级别,虽然较低的隔离级别(如读已提交)可以减少死锁的可能性,但也可能导致更多的并发问题(如不可重复读或幻读)。
-
手动解决:
- 当遇到死锁时,DBA可以手动分析并决定是否应该杀死其中一个或多个事务,以打破死锁循环。
-
应用层处理:
- 在应用程序设计层面,可以通过添加重试机制来应对可能出现的死锁,当事务因死锁被回滚时,应用层可以捕获异常并重新发起事务。
-
配置调整:
- 调整数据库相关的参数,如增大innodb_lock_wait_timeout,当等待锁的时间超过设定阈值时,事务将自动回滚,从而避免无限期等待。
综上所述,MySQL中的死锁问题需要结合数据库服务器的内部机制和应用程序的设计来进行综合考虑和处理。
当然,MySQL的死锁问题有很多细节值得深入探讨和扩展,下面是一些额外的点:
1.死锁的检测与处理
-
死锁检测算法:InnoDB存储引擎使用了一种基于等待图的死锁检测算法。每当事务请求新的锁时,都会检查是否存在循环等待的情况。如果有,InnoDB会选择牺牲(rollback)一个事务以打破死锁。
-
innodb_deadlock_detect 参数:MySQL可以通过配置
innodb_deadlock_detect
参数来控制是否启用死锁检测功能。默认情况下,此参数为ON,表示InnoDB会积极检测死锁并在发现死锁时立即回滚一个事务。但是,关闭此选项意味着系统在等待锁超时后才有可能检测到死锁。 -
innodb_lock_wait_timeout:这是一个影响死锁处理的重要参数,它指定了一个事务在等待锁时可以等待的最大时间(单位秒)。超时后,事务将被回滚并抛出一个错误,客户端可以根据错误代码识别死锁并选择合适的重试策略。
2.死锁的预防策略
-
严格的事务顺序:在编写事务时,尽量保持固定的资源获取顺序,避免交叉锁定资源引起死锁。
-
最小化锁定范围:只锁定那些真正需要修改的数据,避免不必要的大范围锁定。
-
合理设置事务隔离级别:尽管较低的隔离级别减少了死锁的风险,但可能引入其他并发问题。根据实际需求选择合适的事务隔离级别,兼顾并发性能和一致性需求。
-
及时提交或回滚事务:不要让事务长时间持有锁,特别是在循环中逐条处理大量记录时,应及时提交或回滚事务,释放资源。
-
使用乐观锁或版本控制:在某些场景下,可以使用乐观锁(如CAS操作)或数据库的行版本控制机制(MVCC),这类机制在一定程度上降低了死锁发生的概率。
3.死锁监控与排查
-
SHOW ENGINE INNODB STATUS:可以查看InnoDB引擎的状态,其中包含有关最近发生的死锁的信息。
-
performance_schema:MySQL的性能模式包含了丰富的监控信息,可以帮助开发者跟踪和诊断死锁的具体情况。
-
日志记录:通过对MySQL错误日志的监控,可以捕获到死锁相关的错误信息,帮助定位问题。
3.Java中的死锁问题(面试常考)
1.死锁发生的必要条件(缺一不可)
- 互斥条件(锁的特性):至少有一个资源是不可共享的,也就是说,一段时间内仅允许一个进程使用。
- 持有并等待条件:已经获得了至少一个资源的进程还在等待获取其他资源,而不会释放已持有的资源。
- 非抢占条件(锁的特性):资源一旦被分配给一个进程,就不能被强制性地从该进程中收回,只能由进程自身主动释放。
- 循环等待条件:存在一个进程-资源的闭环链,每个进程都在等待下一个进程所占用的资源,循环阻塞等待了。
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.死锁的解决方法
-
预防死锁:
- 资源一次性分配:一次性为进程分配所需的全部资源,这样就可以避免循环等待条件。
- 资源有序分配:规定所有的进程都按照统一的顺序申请资源,这样可以避免循环等待。
- 破坏请求和保持条件:要求进程在请求新资源之前释放已有资源,或者在申请资源时不立即锁定资源,而是等到可以一次性获得所有所需资源时才进行锁定。
- 破坏不可剥夺条件:允许资源抢占,即当一个进程请求资源无法得到满足时,系统可以剥夺已经分配给其他进程但尚未使用的资源。
-
避免死锁:
- 动态分配资源时使用银行家算法等策略,系统在分配资源前预先计算是否有足够的资源满足所有进程的安全序列,以防止系统进入不安全状态,从而避免死锁。
-
检测死锁:
- 在系统中设置周期性的死锁检测机制,通过算法(如Wait-For Graph算法)来发现死锁。
- 当检测到死锁时,采取一定的策略进行解除,如选择一个进程取消(回滚或撤销),或者选择资源进行抢占。
-
解除死锁:
- 撤销进程:选择一个死锁进程进行回滚,释放其所占用的资源,使其余进程得以继续执行。
- 资源剥夺:强制从死锁进程手中剥夺部分资源,分配给其他进程,打破循环等待。
-
资源超时回收:
- 设置资源请求的超时时间,当请求超出指定时间仍未能获取资源时,释放已持有资源,然后重新发起请求,这样可以避免长期等待和死锁。
每种方法都有其适用场景和局限性,实际应用时需要根据系统的具体情况和性能要求选择合适的方法。在设计并发和多线程程序时,良好的编程实践和精心设计的资源管理策略也是非常重要的,例如尽量减少资源的持有时间、确保资源释放的完整性以及避免不必要的资源竞争。
以上就是关于线程安全问题的所以内容了,感谢你的阅读!
相关文章:
线程安全--深入探究线程等待机制和死锁问题
꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好,我是xiaoxie.希望你看完之后,有不足之处请多多谅解,让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如需转…...
量子计算获重大突破!微软和Quantinuum将量子计算错误率降低800倍,网友:AI算力的希望
量子计算迎来新突破。 近日,微软和量子计算公司Quantinuum宣布:发现了一种新的量子计算系统,可以将传统量子计算的错误率下降800倍,这让高性能量子计算机走进现实更近了一步。 自生成式AI爆发以来,算力是AI发展面临的…...
WordPress 6.5 “里贾纳”已经发布
WordPress 6.5 “里贾纳”已经发布,其灵感来自著名爵士小提琴家Regina Carter的多才多艺。雷吉娜是一位屡获殊荣的艺术家和著名的爵士乐教育家,以超越流派而闻名,她在古典音乐方面的技术基础和对爵士乐的深刻理解为她赢得了大胆超越小提琴所能…...
甲方安全建设之日志采集实操干货
前言 没有永远的安全,如何在被攻击的情况下,快速响应和快速溯源分析攻击动作是个重要的话题。想要分析攻击者做了什么、怎么攻击进来的、还攻击了谁,那么日志是必不可少的一项,因此我们需要尽可能采集多的日志来进行分析攻击者的…...
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复活”背后的数字永生:被期待成为下一个电商,培育市场认知和用户心智还需时间© 由 九派新闻 提供 数字永生,还是电子宠物?过去一个月,因包小柏用AI技术让爱女在数字世界“复活”一事,《流浪地球2…...
基于单片机钢琴电子节拍器系统设计
**单片机设计介绍,基于单片机钢琴电子节拍器系统设计 文章目录 一 概要二、功能设计三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机钢琴电子节拍器系统设计是一个综合性的项目,它结合了单片机编程、音频处理、用户界面设计等多个领域的…...
我的创作纪念日(year Ⅱ)
大家好,我是Kamen Black 君,今天我与大家简单分享一下我两年来在CSDN的创作历程。 print("祝大家每天快乐,love and peace!") 机缘 当初写博客是为了记录一些自己大学中做比赛的心得,没想到自己能走到这一步…...
应急响应实战笔记05Linux实战篇(1)
第1篇:SSH暴力破解 0x00 前言 SSH 是目前较可靠,专为远程登录会话和其他网络服务提供安全性的协议,主要用于给远程登录会话数据进行加密,保证数据传输的安全。SSH口令长度太短或者复杂度不够,如仅包含数字&#x…...
重装系统之后,电脑连网卡都没反应怎么办?
前言 有些电脑比较奇葩,安装完成之后会出现网卡连驱动都没有,这时候要安装电脑驱动可是真的烦躁。怎么下手呢? 如果确定电脑的网卡型号还好,直接找个电脑下载个对应的网卡驱动,用U盘复制过去就能安装。 但如果不知道…...
【三十五】【算法分析与设计】综合练习(2),22。 括号生成,77。 组合,494。 目标和,模拟树递归,临时变量自动维护树定义,递归回溯,非树结构模拟树
22. 括号生成 数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。 示例 1: 输入:n 3 输出:["((())࿰…...
QT智能指针
一.概述 Qt智能指针是一种能够在不需要手动管理内存的情况下,自动释放资源的指针。它们是C11的std::shared_ptr的一种扩展,可以用于管理Qt对象,尤其是那些不是QObject的对象。 使用智能指针可以避免内存泄露和悬垂指针等问题,同时…...
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. 技术框架概述: - Beautiful Things App Template是一个为visionOS设计的免费开源软件(FOSS),用于展示3D模型画廊。 2. 定位: - 该模板作为Beautiful Things网站的延伸,旨在为Apple Vision Pro用户…...
Qt Remote Objects (QtRO) 笔记
简介 Qt Remote Objects (QtRO) 是 Qt 的一个进程间通信模块。 术语 Source 是指提供服务或提供功能供其他程序使用的对象,是 RPC 中的被调用端。 Replica 是指 Source 对象的代理对象,用于 RPC 中的调用端,对 Replica 的调用请求将被转发…...
Unity类银河恶魔城学习记录12-6.5 p128.5 Create item by Craft源代码
此章节在原视频缺失,此过程为根据源代码推断而来,并非原视频步骤 Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释,可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩…...
UE4_如果快速做出毛玻璃效果_假景深
UE4_如果快速做出毛玻璃效果_假景深 2022-08-20 15:02 一个SpiralBlur-SceneTexture材质节点完成效果,启用半透明材质通过修改BlurAmount数值大小调整效果spiralBlur-SceneTexture custom节点,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中,最离不开的,肯定是看监控了,那么就要去了解一些wireshark的基础用法以及攻击的流量!!!! 1.Wireshark的基本用法 比如人家面试官给你一段流量包,你要会用 1.分组详情 对于我…...
Lafida多目数据集实测
Lafida 数据集 paper:J. Imaging | Free Full-Text | LaFiDa—A Laserscanner Multi-Fisheye Camera Dataset 官网数据:https://www.ipf.kit.edu/english/projekt_cv_szenen.php 官网:KIT-IPF-Software and Datasets - LaFiDa 标定数据下载&…...
excel wps中编码格式转换
EXCEL报表:另存为CSV格式,转换成UTF-8编码 - 简书 (jianshu.com) 经验证管用...
【游戏分析】非游戏领空追字符串来源
通过NPC名称找NPC数组 扫描 NPC名字 ASIC型 发现全部都有后缀 那么采用 字节集的方式去扫描 也是扫不到 说明:不是ASIC型字符串 扫描 NPC名字 Unicode型 没有结果 那么转换成字节集去扫描 终于发现结果了 把结果挨个修改字符串 发现 其中两个是可以用的 22和23 …...
golang 数组和切片
区别 1.数组长度固定,切片长度可变 2.数组是深拷贝,切片是浅拷贝,切片是引用类型 扩容规则 不同版本不一样 https://www.jb51.net/article/280481.htm#_lab2_2_1 go1.18 1.如果期望容量大于当前容量的两倍就会使用期望容量; 2.如…...
物联网实战--入门篇之(九)安卓QT--开发框架
目录 一、QT简介 二、开发环境 三、编码风格 四、设计框架 五、总结 一、QT简介 QT是一款以C为基础的开发工具,已经包含了很多常用的库,除了基本的GUI以外,还有网络、数据库、多媒体、进程通信、串口、蓝牙等常用库,开发起来…...
【leetcode面试经典150题】16.接雨水(C++)
【leetcode面试经典150题】专栏系列将为准备暑期实习生以及秋招的同学们提高在面试时的经典面试算法题的思路和想法。本专栏将以一题多解和精简算法思路为主,题解使用C语言。(若有使用其他语言的同学也可了解题解思路,本质上语法内容一致&…...
互联网面经
腾讯视频 代码:反转链表,单例模式 RAII,哪里用到 Web服务器怎样处理请求 get\post流程 项目使用的还是http1.0吗;http2.0:二进制、首部压缩、主动推送;Https Epoll/select/poll ET/LT 进程地址空间。3…...
xss介绍及作用
XSS(Cross-Site Scripting)是一种常见的网络安全漏洞,它允许攻击者向网站注入恶意的客户端脚本代码,从而在用户的浏览器中执行这些代码。 XSS攻击的原理是攻击者将恶意脚本插入到网页中的用户输入数据中,当其他用户访…...
PostgreSQL入门到实战-第二弹
PostgreSQL入门到实战 PostgreSQL安装之Windows官网地址PostgreSQL概述Windows上安装PostgreSQL更新计划 PostgreSQL安装之Windows 官网地址 声明: 由于操作系统, 版本更新等原因, 文章所列内容不一定100%复现, 还要以官方信息为准 https://www.postgresql.org/PostgreSQL概…...
3-【PS让图片动起来】系列1-【导入素材】
【问题介绍】仅做图片,现在很难吸引用户视线,越来越多地图片需要动起来增添意境,比如春日樱花花瓣掉落、冬季雪花纷纷,今天来学学怎么用PS的时间轴,让图片动起来~ 如下图,一副冬日雪景图,想给画…...
潍坊网站制作/营业推广促销
刷新JAVA锁屏软件 V1.11 (2007-04-02)首先感谢大家对本软件的支持和宽容:)V1.11修改了刚刚一些机友提出的V1.1的问题(原下载链接作废),主要是某种情况下造成的黑屏的问题。如果大家愿意继续帮忙测试,请下载使用;如果想要等待更加成熟的版本&a…...
php网站制作过程中遇到的问题及解决办法/大连seo顾问
众所周知,PMP证书的有效期是3年,如果想保持此证书的有效性,您需要完成两个步骤: 1.在三年之内向PMI申报完成60个PDU; 2.向PMI申请下一个三年续证的有效期并缴费。 流程虽然简单,但是对于首次操作的PMPer会…...
网站域名可以做端口映射吗/seo入门
1 inverse,在一对多中使用,表示是否有关联关系控制权。对于保存、删除数据有影响。 2 cascade,表示级联操作 save-update 表示级联保存和更新 delete 表示级联删除 all 表示级联保存、更新、删除 3 一级缓存,session缓存又称一级缓…...
cnzz如何查询某个网站频道的流量/2020国内十大小说网站排名
《优爱酷Excel VBA高级应用:数据动态可视化自定义毫秒级Wait等待函数》 自定义毫秒级Wait等待函数,期间不卡顿,动画如丝般顺滑,可开始暂停...优爱酷Excel VBA高级应用:数据动态可视化自定义毫秒级Wait函数,…...
潍坊网站建设制作/互动营销名词解释
当你上课感觉就像打酱油时,当你对研究生很迷茫时,当你坐在电脑前孜孜不倦时,请看下面的文章,很受用,至少我心里现在没有以前浮躁。好的文章有时能改变一个人的精神状态,下面就是其中之一。上海大学一位老师…...
seo如何推广网站/免费个人网站注册
智能手机行业竞争越来越激烈,手机厂商们对智能手机打造也告别了单纯堆砌硬件、参数的时代,开始进行提升手机的使用体验。人工智能AI带来的智慧化,无疑是提升手机体验的有效方式。如果说之前的智能手机对功能机的颠覆是人机交互,那…...