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

并发编程之死锁问题介绍

一、本文概览

死锁问题在并发编程中是一个非常致命的问题,问题一旦产生,只能通过重启机器、修改代码来修复问题,下面我们通过一小段文章内容介绍下死锁以及如何死锁的预防

在这里插入图片描述

二、什么是死锁?

在介绍死锁之前,先来明确下什么是锁?

  • 锁其实就是一种同步机制,一个线程拥有对一块资源的锁,那么该线程对这块资源的处理是与其他线程互斥的!在该线程未释放锁之前,其它线程会被限制对统一资源的访问。

有了对锁概念的认知,我们再来看下死锁是什么?所谓死锁其实就是指在多线程或者多进程运行状态下,因争夺资源而导致的一种互不让步的僵局,导致各自均进入阻塞状态,如果没有外力(强制中断或者程序设置超时中断)的推动,则程序将一直处于僵持(崩溃)状态。

三、死锁产生的必要条件?

产生死锁有四个必要条件:

  • 资源互斥:资源互斥就是上面我们说的锁,线程持有的锁是需要具备独占且排他使用的
  • 不可被剥夺:线程在对持有的资源未使用完毕前,是不会被其他线程强行剥夺的
  • 请求并保持:线程在请求获取新的资源时,当前所持有的资源依旧继续占用
  • 循环等待:多个线程对于获取锁行为是一个环形,例如线程A持有锁1,需要获取锁2才能进行后续操作;线程B持有锁2,需要获取锁1才能进行后续操作,此时就形成了环

我们来看看死锁的代码示例:

package com.markus.onjava.concurrent;/*** @author: markus* @date: 2023/2/22 10:21 PM* @Description: 死锁代码演示* @Blog: https://markuszhang.com* It's my honor to share what I've learned with you!*/
public class DeadLockDemo {public static void main(String[] args) {String lockA = "lockA";String lockB = "lockB";Thread thread1 = new Thread(new Task(lockA, lockB));Thread thread2 = new Thread(new Task(lockB, lockA));thread1.start();thread2.start();}
}class Task implements Runnable {private final String lockA;private final String lockB;public Task(String lockA, String lockB) {this.lockA = lockA;this.lockB = lockB;}@Overridepublic void run() {try {synchronized (lockA) {log("contain lock:[" + lockA + "]");Thread.sleep(2000);synchronized (lockB) {log("contain lock:[" + lockB + "]");}}} catch (InterruptedException e) {e.printStackTrace();}}private void log(String msg) {System.out.println("Thread id [" + Thread.currentThread().getId() + "] msg: " + msg);}
}

控制台

在这里插入图片描述

我们可以通过jstack来查看进程中的线程状态来分析是哪些线程出现了死锁状态

# 查询进程id
➜  ~ jps
52996 Launcher
53734 Jps
53498 Launcher
53499 DeadLockDemo
5452
52862 RemoteMavenServer36
# 分析进程的堆栈信息
➜  ~ jstack 53499
2023-02-22 22:58:31
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.211-b12 mixed mode):"Thread-1" #12 prio=5 os_prio=31 tid=0x00007f9e2d84d000 nid=0x5b03 waiting for monitor entry [0x000000030a74d000]java.lang.Thread.State: BLOCKED (on object monitor)at com.markus.onjava.concurrent.Task.run(DeadLockDemo.java:38)- waiting to lock <0x000000076ac1c8d0> (a java.lang.String)- locked <0x000000076ac1c908> (a java.lang.String)at java.lang.Thread.run(Thread.java:748)"Thread-0" #11 prio=5 os_prio=31 tid=0x00007f9e2d84c800 nid=0x9c5f waiting for monitor entry [0x000000030a64a000]java.lang.Thread.State: BLOCKED (on object monitor)at com.markus.onjava.concurrent.Task.run(DeadLockDemo.java:38)- waiting to lock <0x000000076ac1c908> (a java.lang.String)- locked <0x000000076ac1c8d0> (a java.lang.String)at java.lang.Thread.run(Thread.java:748)# ... 省略部分线程堆栈信息
Found one Java-level deadlock:
=============================
"Thread-1":waiting to lock monitor 0x00007f9e2f814168 (object 0x000000076ac1c8d0, a java.lang.String),which is held by "Thread-0"
"Thread-0":waiting to lock monitor 0x00007f9e2f8169f8 (object 0x000000076ac1c908, a java.lang.String),which is held by "Thread-1"Java stack information for the threads listed above:
===================================================
"Thread-1":at com.markus.onjava.concurrent.Task.run(DeadLockDemo.java:38)- waiting to lock <0x000000076ac1c8d0> (a java.lang.String)- locked <0x000000076ac1c908> (a java.lang.String)at java.lang.Thread.run(Thread.java:748)
"Thread-0":at com.markus.onjava.concurrent.Task.run(DeadLockDemo.java:38)- waiting to lock <0x000000076ac1c908> (a java.lang.String)- locked <0x000000076ac1c8d0> (a java.lang.String)at java.lang.Thread.run(Thread.java:748)Found 1 deadlock.

四、如何防范死锁?

上面介绍了产生死锁的必要条件,所谓必要条件就是要都满足才能产生死锁,所以在预防的时候,我们可以任意打破死锁的4个必要条件来预防死锁,但又因为资源互斥是底层操作系统的固有特性,应用层面是无法改变的,所以我们可以通过破坏剩余的三个条件来进行预防:

  • 破坏"不可被剥夺"条件
  • 破坏"请求并保持"条件
  • 破坏"循环等待"条件

下面来举个经典的死锁案例:哲学家晚餐情景。

一个餐桌上有五名哲学家以及五根筷子,这五根筷子分别插入到五位哲学家的间隔处,哲学家想要饮食则必须同时拿起左右手两边的筷子,所以现在就有问题了,如果有人能够吃饭,那肯定会有人等待,在某种情况下还极可能造成所有人都在等待以导致死锁的情况。

在这里插入图片描述

我们来用代码实现一下这种场景:

  • 筷子持有
package com.markus.onjava.concurrent.deadlock;import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;/*** @author: markus* @date: 2023/2/25 10:12 PM* @Description: 筷子持有者* @Blog: https://markuszhang.com* It's my honor to share what I've learned with you!*/
public class StickHolder {private static class Chopstick {}private Chopstick stick = new Chopstick();// 利用阻塞队列实现当前筷子同一时刻只能被一个人持有,其他人想要获取这跟筷子,则必须等待private BlockingQueue<Chopstick> holder = new ArrayBlockingQueue<>(1);public StickHolder() {putDown();}/*** 拿起筷子*/public void pickUp() {try {holder.take(); // 不可用时会阻塞} catch (InterruptedException e) {throw new RuntimeException(e);}}/*** 放下筷子*/public void putDown() {try {holder.put(stick);} catch (InterruptedException e) {throw new RuntimeException(e);}}
}
  • 哲学家
package com.markus.onjava.concurrent.deadlock;import java.util.concurrent.TimeUnit;/*** @author: markus* @date: 2023/2/25 10:19 PM* @Description: 哲学家* @Blog: https://markuszhang.com* It's my honor to share what I've learned with you!*/
public class Philosopher implements Runnable {private final int seat;private final StickHolder left, right;public Philosopher(int seat, StickHolder left, StickHolder right) {this.seat = seat;this.left = left;this.right = right;}@Overridepublic String toString() {return "P" + seat;}@Overridepublic void run() {// 循环执行吃饭的动作while (true) {// 拿起右手边的筷子right.pickUp();// 拿起左手边的筷子left.pickUp();System.out.println(this + " eating");// 放下右手边的筷子right.putDown();// 放下左手边的筷子left.putDown();}}
}
  • 晚餐现场
package com.markus.onjava.concurrent.deadlock;import com.markus.onjava.Nap;import java.util.Arrays;
import java.util.concurrent.CompletableFuture;/*** @author: markus* @date: 2023/2/25 10:23 PM* @Description: 哲学家的晚餐演示* @Blog: https://markuszhang.com* It's my honor to share what I've learned with you!*/
public class DiningPhilosophers {/*筷子持有者*/private StickHolder[] sticks;/*哲学家*/private Philosopher[] philosophers;public DiningPhilosophers(int n) {sticks = new StickHolder[n];Arrays.setAll(sticks, i -> new StickHolder());philosophers = new Philosopher[n];// 通过模数n选择右手边的筷子,并将最后一个哲学家指向第一位哲学家旁边,整体形成一个环Arrays.setAll(philosophers, i -> new Philosopher(i, sticks[i], sticks[(i + 1) % n])); Arrays.stream(philosophers).forEach(CompletableFuture::runAsync);}public static void main(String[] args) {// 立刻返回,不阻塞new DiningPhilosophers(5);// 主流程等待100s后再退出(此时我们可以观察哲学家的用餐场景)new Nap(100, "Shutdown");}
}

执行晚餐现场的代码后,我们可以发现,起初还能正常的执行,但一会就会形成互相等待的场景,这种等待形成了一个环,也就造成了死锁。

在这里插入图片描述

我们也可以通过jstack命令来确认下互相等待的情况:

➜  ~ jps
1593
10331 Jps
10318 Launcher
8862 JStack
10319 DiningPhilosophers
➜  ~ jstack 10319
2023-02-26 14:51:08
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.211-b12 mixed mode):"ForkJoinPool.commonPool-worker-5" #17 daemon prio=5 os_prio=31 tid=0x00007fb25188f800 nid=0x6a07 waiting on condition [0x000000030668e000]java.lang.Thread.State: WAITING (parking)at sun.misc.Unsafe.park(Native Method)- parking to wait for  <0x000000076b249450> (a java.util.concurrent.ForkJoinPool)at java.util.concurrent.ForkJoinPool.awaitWork(ForkJoinPool.java:1824)at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1693)at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)"ForkJoinPool.commonPool-worker-7" #19 daemon prio=5 os_prio=31 tid=0x00007fb211809000 nid=0x9503 waiting on condition [0x000000030658b000]java.lang.Thread.State: WAITING (parking)at sun.misc.Unsafe.park(Native Method)- parking to wait for  <0x000000076b249450> (a java.util.concurrent.ForkJoinPool)at java.util.concurrent.ForkJoinPool.awaitWork(ForkJoinPool.java:1824)at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1693)at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)"ForkJoinPool.commonPool-worker-6" #18 daemon prio=5 os_prio=31 tid=0x00007fb211808800 nid=0x6703 waiting on condition [0x0000000306488000]java.lang.Thread.State: WAITING (parking)at sun.misc.Unsafe.park(Native Method)- parking to wait for  <0x000000076b18a040> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)at java.util.concurrent.ArrayBlockingQueue.take(ArrayBlockingQueue.java:403)at com.markus.onjava.concurrent.deadlock.StickHolder.pickUp(StickHolder.java:30)at com.markus.onjava.concurrent.deadlock.Philosopher.run(Philosopher.java:31)at java.util.concurrent.CompletableFuture$AsyncRun.run$$$capture(CompletableFuture.java:1626)at java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java)at java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:1618)at java.util.concurrent.ForkJoinTask.doExec$$$capture(ForkJoinTask.java:289)at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java)at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)"ForkJoinPool.commonPool-worker-4" #16 daemon prio=5 os_prio=31 tid=0x00007fb2540cd000 nid=0x9703 waiting on condition [0x0000000306385000]java.lang.Thread.State: WAITING (parking)at sun.misc.Unsafe.park(Native Method)- parking to wait for  <0x000000076b189f70> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)at java.util.concurrent.ArrayBlockingQueue.take(ArrayBlockingQueue.java:403)at com.markus.onjava.concurrent.deadlock.StickHolder.pickUp(StickHolder.java:30)at com.markus.onjava.concurrent.deadlock.Philosopher.run(Philosopher.java:31)at java.util.concurrent.CompletableFuture$AsyncRun.run$$$capture(CompletableFuture.java:1626)at java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java)at java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:1618)at java.util.concurrent.ForkJoinTask.doExec$$$capture(ForkJoinTask.java:289)at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java)at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)"ForkJoinPool.commonPool-worker-3" #15 daemon prio=5 os_prio=31 tid=0x00007fb253849000 nid=0x9903 waiting on condition [0x0000000306282000]java.lang.Thread.State: WAITING (parking)at sun.misc.Unsafe.park(Native Method)- parking to wait for  <0x000000076b189ea0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)at java.util.concurrent.ArrayBlockingQueue.take(ArrayBlockingQueue.java:403)at com.markus.onjava.concurrent.deadlock.StickHolder.pickUp(StickHolder.java:30)at com.markus.onjava.concurrent.deadlock.Philosopher.run(Philosopher.java:31)at java.util.concurrent.CompletableFuture$AsyncRun.run$$$capture(CompletableFuture.java:1626)at java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java)at java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:1618)at java.util.concurrent.ForkJoinTask.doExec$$$capture(ForkJoinTask.java:289)at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java)at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)"ForkJoinPool.commonPool-worker-2" #14 daemon prio=5 os_prio=31 tid=0x00007fb252030800 nid=0x6303 waiting on condition [0x000000030617f000]java.lang.Thread.State: WAITING (parking)at sun.misc.Unsafe.park(Native Method)- parking to wait for  <0x000000076b189dd0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)at java.util.concurrent.ArrayBlockingQueue.take(ArrayBlockingQueue.java:403)at com.markus.onjava.concurrent.deadlock.StickHolder.pickUp(StickHolder.java:30)at com.markus.onjava.concurrent.deadlock.Philosopher.run(Philosopher.java:31)at java.util.concurrent.CompletableFuture$AsyncRun.run$$$capture(CompletableFuture.java:1626)at java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java)at java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:1618)at java.util.concurrent.ForkJoinTask.doExec$$$capture(ForkJoinTask.java:289)at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java)at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)"ForkJoinPool.commonPool-worker-1" #13 daemon prio=5 os_prio=31 tid=0x00007fb25383a000 nid=0x6133 waiting on condition [0x000000030607c000]java.lang.Thread.State: WAITING (parking)at sun.misc.Unsafe.park(Native Method)- parking to wait for  <0x000000076b189d00> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)at java.util.concurrent.ArrayBlockingQueue.take(ArrayBlockingQueue.java:403)at com.markus.onjava.concurrent.deadlock.StickHolder.pickUp(StickHolder.java:30)at com.markus.onjava.concurrent.deadlock.Philosopher.run(Philosopher.java:31)at java.util.concurrent.CompletableFuture$AsyncRun.run$$$capture(CompletableFuture.java:1626)at java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java)at java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:1618)at java.util.concurrent.ForkJoinTask.doExec$$$capture(ForkJoinTask.java:289)at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java)at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)

通过对上面基础知识的学习,我们可以知道代码产生死锁的原因有以下几点:

  • 一根筷子(资源)同一时刻只能被一位哲学家使用,也就是资源互斥
  • 哲学家每人都持有一根筷子,并且均尝试去获取另一根筷子,就是请求并保持
  • 哲学家持有的筷子不能被强制回收,只能由自己完成任务主动释放,也就是不可被剥夺
  • 哲学家的等待形成了一个环,造成循环等待

前面我们说了资源互斥是系统特性,我们先忽略打破这个条件,下面我们来通过其他三个条件来实现预防死锁的解决方案:

  • 打破循环等待-我们可以看到,哲学家都是尝试先拿起右边的筷子再拿起右边的筷子,这样就互相之间就形成了环,我们可以指定某一位哲学家不按照这样的顺序取筷子,则形成不了环,也就不会造成情况了。
package com.markus.onjava.concurrent.deadlock;import com.markus.onjava.Nap;import java.util.Arrays;
import java.util.concurrent.CompletableFuture;/*** @author: markus* @date: 2023/2/25 10:23 PM* @Description: 哲学家的晚餐演示* @Blog: https://markuszhang.com* It's my honor to share what I've learned with you!*/
public class DiningPhilosophers {/*筷子持有者*/private StickHolder[] sticks;/*哲学家*/private Philosopher[] philosophers;public DiningPhilosophers(int n) {sticks = new StickHolder[n];Arrays.setAll(sticks, i -> new StickHolder());philosophers = new Philosopher[n];Arrays.setAll(philosophers, i -> new Philosopher(i, sticks[i], sticks[(i + 1) % n]));philosophers[1] = new Philosopher(1, sticks[0], sticks[1]); // [1] 通过将第2位哲学家颠倒拿放筷子的顺序来修正死锁Arrays.stream(philosophers).forEach(CompletableFuture::runAsync);}public static void main(String[] args) {new DiningPhilosophers(5);new Nap(100, "Shutdown");}
}
  • 打破循环条件还有另一种方案,就是调大资源数超出你的机器的CPU物理核数,这样就导致同一时刻,肯定会有一位哲学家不参与活动的进行,这也就形成不了循环等待的情况
  • 我们还可以通过打破请求并保持的条件
/*** 拿起筷子*/
public void pickUp() {try {
//      holder.take(); // 不可用时会阻塞holder.poll(100, TimeUnit.MILLISECONDS);// 超时自己中断,不再尝试去获取锁} catch (InterruptedException e) {
//      throw new RuntimeException(e);}
}
  • 不可被剥夺条件实现起来比较麻烦,核心思想就是如果拿不到就去旁边手中抢过来。

综上,预防死锁的方式可以通过打破那四个必要条件的其中一个即可,其中打破循环等待条件又是最容易的,我们通常会通过这种思路进行预防。

五、本文总结

上述就是对死锁的简单介绍,包括死锁是什么,什么情况下会导致死锁(四个必要条件)以及如何预防死锁(打破四个必要条件之一即可),我们也可以看出在Java语言层面上是无法支持我们来避免死锁的,所以我们只能通过谨慎的设计来避免这个问题。避免并发问题,最简单有效的方法就是永远不要共享资源,但这看来也是不现实的,所以在设计的时候,我们也可以通过画布画出资源的依赖关系来谨慎设计方案等等其他方法来避免系统出现死锁。

相关文章:

并发编程之死锁问题介绍

一、本文概览 死锁问题在并发编程中是一个非常致命的问题&#xff0c;问题一旦产生&#xff0c;只能通过重启机器、修改代码来修复问题&#xff0c;下面我们通过一小段文章内容介绍下死锁以及如何死锁的预防 二、什么是死锁&#xff1f; 在介绍死锁之前&#xff0c;先来明确下什…...

【python学习笔记】:SQL常用脚本(一)

1、行转列的用法PIVOT CREATE table test (id int,name nvarchar(20),quarter int,number int) insert into test values(1,N苹果,1,1000) insert into test values(1,N苹果,2,2000) insert into test values(1,N苹果,3,4000) insert into test values(1,N苹果,4,5000) insert…...

Spring是怎么解决循环依赖的

1.什么是循环依赖&#xff1a; 这里给大家举个简单的例子&#xff0c;相信看了上一篇文章大家都知道了解了spring的生命周期创建流程。那么在Spring在生命周期的哪一步会出现循环依赖呢&#xff1f; 第一阶段&#xff1a;实例化阶段 Instantiation 第二阶段&#xff1a;属性赋…...

HTML创意动画代码

目录1、动态气泡背景2、创意文字3、旋转立方体1、动态气泡背景 <!DOCTYPE html> <html> <head><title>Bubble Background</title><style>body {margin: 0;padding: 0;height: 100vh;background: #222;display: flex;flex-direction: colum…...

软工第一次个人作业——阅读和提问

软工第一次个人作业——阅读和提问 项目内容这个作业属于哪个课程2023北航敏捷软件工程这个作业的要求在哪里个人作业-阅读和提问我在这个课程的目标是体验敏捷开发过程&#xff0c;掌握一些开发技能&#xff0c;为进一步发展作铺垫这个作业在哪个具体方面帮助我实现目标对本课…...

urho3d的自定义文件格式

Urho3D尽可能使用现有文件格式&#xff0c;仅在绝对必要时才定义自定义文件格式。当前使用的自定义文件格式有&#xff1a; 二进制模型格式&#xff08;.mdl&#xff09; Model geometry and vertex morph data byte[4] Identifier "UMDL" or "UMD2" …...

spark第一章:环境安装

系列文章目录 spark第一章&#xff1a;环境安装 文章目录系列文章目录前言一、文件准备1.文件上传2.文件解压3.修改配置4.启动环境二、历史服务器1.修改配置2.启动历史服务器总结前言 spark在大数据环境的重要程度就不必细说了&#xff0c;直接开始吧。 一、文件准备 1.文件…...

MySQL---存储过程与存储函数的相关概念

MySQL—存储过程与存储函数的相关概念 存储函数和存储过程的主要区别&#xff1a; 存储函数一定会有返回值的存储过程不一定有返回值 存储过程和函数能后将复杂的SQL逻辑封装在一起&#xff0c;应用程序无需关注存储过程和函数内部复杂的SQL逻辑&#xff0c;而只需要简单地调…...

PMP值得考吗?

第一&#xff0c;PMP的价值体现 1、PMP是管理岗位必考证书。 多数企业会选择优先录用持PMP证书的管理人才&#xff0c;PMP成为管理岗位的必考证书。PMP在很多外企和国内中大型企业非常受重视&#xff0c;中石油、中海油、华为等等都会给内部员工做培训。 这些机构对项目管理…...

Quartus 报错汇总(持续更新...)

1、Error (10663): Verilog HDL Port Connection error at top_rom.v(70): output or inout port "stcp" must be connected to a structural net expression输出变量stcp在原设计文件中已经定义为reg型&#xff0c;在实例化时不能再定义为reg型&#xff0c;而应该是…...

Netty权威指南总结(一)

一、为什么选择Netty&#xff1a;API使用简单&#xff0c;开发门槛低&#xff0c;屏蔽了NIO通信的底层细节。功能强大&#xff0c;预制了很多种编解码功能&#xff0c;支持主流协议。定制能力强&#xff0c;可以通过ChannelHandler对通信框架进行灵活地拓展。性能高、成熟、稳定…...

Elasticsearch:如何轻松安全地对实时 Elasticsearch 索引重新索引你的数据

在很多的时候&#xff0c;由于一些需求&#xff0c;我们不得不修改索引的映射&#xff0c;也即 mapping&#xff0c;这个时候我们需要重新索引&#xff08;reindex&#xff09;来把之前的数据索引到新的索引中。槽糕的是&#xff0c;我们的这个索引还在不断地收集实时数据&…...

【算法笔记】前缀和与差分

第一课前缀和与差分 算法是解决问题的方法与步骤。 在看一个算法是否优秀时&#xff0c;我们一般都要考虑一个算法的时间复杂度和空间复杂度。 现在随着空间越来越大&#xff0c;时间复杂度成为了一个算法的重要指标&#xff0c;那么如何估计一个算法的时间复杂度呢&#xf…...

python实战应用讲解-【实战应用篇】函数式编程-八皇后问题(附示例代码)

目录 知识储备-迭代器相关模块 itertools 模块 创建新的迭代器 根据最短输入序列长度停止的迭代器...

【Servlet篇】如何解决Request请求中文乱码的问题?

前言 前面一篇文章我们探讨了 Servlet 中的 Request 对象&#xff0c;Request 请求对象中封装了请求数据&#xff0c;使用相应的 API 就可以获取请求参数。 【Servlet篇】一文带你读懂 Request 对象 也许有小伙伴已经发现了前面的方式获取请求参数时&#xff0c;会出现中文乱…...

SpringBoot:SpringBoot简介与快速入门(1)

SpringBoot快速入门1. SpringBoot简介2. SpringBoot快速入门2.1 创建SpringBoot项目&#xff08;必须联网&#xff0c;要不然创建失败&#xff0c;在模块3会讲到原因&#xff09;2.2 编写对应的Controller类2.3 启动测试3. Spring官网构建工程4. SpringBoot工程快速启动4.1 为什…...

RabbitMQ学习(十一):RabbitMQ 集群

一、集群1.1 为什么要使用集群前面我们介绍了如何安装及运行 RabbitMQ 服务&#xff0c;不过这些是单机版的&#xff0c;无法满足目前真实应用的 要求。如果 RabbitMQ 服务器遇到内存崩溃、机器掉电或者主板故障等情况&#xff0c;该怎么办&#xff1f;单台 RabbitMQ 服务器可以…...

学渣适用版——Transformer理论和代码以及注意力机制attention的学习

参考一篇玩具级别不错的代码和案例 自注意力机制 注意力机制是为了transform打基础。 参考这个自注意力机制的讲解流程很详细&#xff0c; 但是学渣一般不知道 key&#xff0c;query&#xff0c;value是啥。 结合B站和GPT理解 注意力机制是一种常见的神经网络结构&#xff0…...

网上这么多IT的培训机构,我们该怎么选?

说实话&#xff0c;千万不要把这个答案放在网上来找&#xff0c;因为你只能得到别人觉得合适的或者机构的广告&#xff1b;当然个人的培训经历可以听一听的&#xff0c;毕竟不靠谱的机构也有&#xff0c;比如让你交一两万去上线上课程或者一百号来人坐一起看视频&#xff0c;这…...

数据结构与算法—跳表(skiplist)

目录 前言 跳表 查询时间分析 1、时间复杂度 o(logn) 2、空间复杂度O(n) 动态插入和删除 跳表动态更新 跳表与红黑树比较 跳表实现 前言 二分查找用的数组 链表可不可以实现二分查找呢&#xff1f; 跳表 各方面性能比较优秀的动态数据结构&#xff0c;可以支持快速…...

系统设计 --- MongoDB亿级数据查询优化策略

系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log&#xff0c;共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题&#xff0c;不能使用ELK只能使用…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)

船舶制造装配管理现状&#xff1a;装配工作依赖人工经验&#xff0c;装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书&#xff0c;但在实际执行中&#xff0c;工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...

算法岗面试经验分享-大模型篇

文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer &#xff08;1&#xff09;资源 论文&a…...

4. TypeScript 类型推断与类型组合

一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式&#xff0c;自动确定它们的类型。 这一特性减少了显式类型注解的需要&#xff0c;在保持类型安全的同时简化了代码。通过分析上下文和初始值&#xff0c;TypeSc…...

git: early EOF

macOS报错&#xff1a; Initialized empty Git repository in /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/.git/ remote: Enumerating objects: 2691797, done. remote: Counting objects: 100% (1760/1760), done. remote: Compressing objects: 100% (636/636…...

五子棋测试用例

一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏&#xff0c;有着深厚的文化底蕴。通过将五子棋制作成网页游戏&#xff0c;可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家&#xff0c;都可以通过网页五子棋感受到东方棋类…...

Vue3中的computer和watch

computed的写法 在页面中 <div>{{ calcNumber }}</div>script中 写法1 常用 import { computed, ref } from vue; let price ref(100);const priceAdd () > { //函数方法 price 1price.value ; }//计算属性 let calcNumber computed(() > {return ${p…...

Linux系统:进程间通信-匿名与命名管道

本节重点 匿名管道的概念与原理匿名管道的创建命名管道的概念与原理命名管道的创建两者的差异与联系命名管道实现EchoServer 一、管道 管道&#xff08;Pipe&#xff09;是一种进程间通信&#xff08;IPC, Inter-Process Communication&#xff09;机制&#xff0c;用于在不…...

大模型智能体核心技术:CoT与ReAct深度解析

**导读&#xff1a;**在当今AI技术快速发展的背景下&#xff0c;大模型的推理能力和可解释性成为业界关注的焦点。本文深入解析了两项核心技术&#xff1a;CoT&#xff08;思维链&#xff09;和ReAct&#xff08;推理与行动&#xff09;&#xff0c;这两种方法正在重新定义大模…...

触发DMA传输错误中断问题排查

在STM32项目中&#xff0c;集成BLE模块后触发DMA传输错误中断&#xff08;DMA2_Stream1_IRQHandler进入错误流程&#xff09;&#xff0c;但单独运行BLE模块时正常&#xff0c;表明问题可能源于原有线程与BLE模块的交互冲突。以下是逐步排查与解决方案&#xff1a; 一、问题根源…...