【JUC基础】JUC入门基础
目录
- 什么是JUC
- 线程和进程
- 锁
- 传统的 synchronized
- Lock 锁
- Synchronized 与 Lock 的区别
- 生产者和消费者问题
- Synchronized 版
- Lock版
- Condition 的优势:精准通知和唤醒线程
- 8 锁现象
- 问题1:两个同步方法,先执行发短信还是打电话?
- 问题2:问题1基础上让发短信延迟 4s
- 问题三:换成一个普通方法结果?
- 问题四:如果使用的是两个对象,一个调用发短信,一个调用打电话,那么整个顺序是怎么样的呢?
- 问题五、六:如果我们把 synchronized 的方法加上 static 变成静态方法,那么顺序又是怎么样的呢?
- 问题七:如果使用一个静态同步方法、一个同步方法、一个对象调用顺序是什么?
- 问题八:如果我们使用一个静态同步方法、一个同步方法、两个对象调用顺序是什么?
什么是JUC
JUC 就是 java.util.concurrent
下面的类包,专门用于多线程的开发。
Lock:可重入锁、可重入读锁、可重入写锁
线程和进程
Java默认有几个线程?
答:2个线程。 main线程、GC线程
Java 真的可以开启线程吗?
答:开不了。Java 是没有权限去开启线程、操作硬件的,这是一个 native 的一个本地方法,它调用的底层的 C++ 代码。
// Thread类源码
public synchronized void start() {/*** This method is not invoked for the main method thread or "system"* group threads created/set up by the VM. Any new functionality added* to this method in the future may have to also be added to the VM.** A zero status value corresponds to state "NEW".*/if (threadStatus != 0)throw new IllegalThreadStateException();/* Notify the group that this thread is about to be started* so that it can be added to the group's list of threads* and the group's unstarted count can be decremented. */group.add(this);boolean started = false;try {start0();started = true;} finally {try {if (!started) {group.threadStartFailed(this);}} catch (Throwable ignore) {/* do nothing. If start0 threw a Throwable thenit will be passed up the call stack */}}}//这是一个C++底层,Java是没有权限操作底层硬件的private native void start0();
线程的状态有哪几种?
// Thread类源码
public enum State { //新生NEW,//运行RUNNABLE,//阻塞BLOCKED,//等待WAITING,//超时等待TIMED_WAITING,//终止TERMINATED;
}
并发:多线程操作同一个资源。CPU 只有一核,模拟出来多条线程。可以使用CPU快速交替,来模拟多线程。
并行:CPU多核,多个线程可以同时执行。 可以使用线程池。
获取CPU的核数:
// 获取CPU的核数
System.out.println(Runtime.getRuntime().availableProcessors());
wait / sleep:
- 1、来自不同的类 wait =>
Object
,sleep =>Thread
// 一般情况企业中使用休眠
import java.util.concurrent.TimeUnit;TimeUnit.DAYS.sleep(1); //休眠1天
TimeUnit.SECONDS.sleep(1); //休眠1s
- 2、关于锁的释放 wait 会释放锁,sleep不会释放锁
- 3、使用的范围是不同的 wait 必须在同步代码块中,sleep 可以在任何地方睡
- 4、是否需要捕获异常 sleep 必须要捕获异常,wait 也是需要捕获异常,notify 和 notifyAll 不需要捕获异常
锁
传统的 synchronized
public class test {public static void main(String[] args) {//并发:多线程操作同一个资源类,将资源类丢入线程中Ticket ticket = new Ticket();new Thread(()->{for (int i = 0; i < 40; i++) {ticket.sale();}},"A").start();new Thread(()->{for (int i = 0; i < 40; i++) {ticket.sale();}},"B").start();new Thread(()->{for (int i = 0; i < 40; i++) {ticket.sale();}},"C").start();}
}// 资源类 OOP 属性、方法
class Ticket {private int number = 30;//卖票的方式public synchronized void sale() {if (number > 0) {System.out.println(Thread.currentThread().getName() + "卖出了第" + (number--) + "张票剩余" + number + "张票");}}
}
Lock 锁
// ReentrantLock源码/*** Creates an instance of {@code ReentrantLock}.* This is equivalent to using {@code ReentrantLock(false)}.*/public ReentrantLock() {sync = new NonfairSync(); //非公平锁:十分不公平,可以插队;(默认为非公平锁)}/*** Creates an instance of {@code ReentrantLock} with the* given fairness policy.** @param fair {@code true} if this lock should use a fair ordering policy*/public ReentrantLock(boolean fair) {sync = fair ? new FairSync() : new NonfairSync(); //公平锁:十分公平,必须先来后到}
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class test {public static void main(String[] args) {Ticket2 ticket = new Ticket2();new Thread(() -> {for (int i = 0; i < 40; i++) {ticket.sale();}}, "A").start();new Thread(() -> {for (int i = 0; i < 40; i++) {ticket.sale();}}, "B").start();new Thread(() -> {for (int i = 0; i < 40; i++) {ticket.sale();}}, "C").start();}
}//lock三部曲
//1、 Lock lock=new ReentrantLock();
//2、 lock.lock() 加锁
//3、 finally=> 解锁:lock.unlock();
class Ticket2 {private int number = 30;// 创建锁Lock lock = new ReentrantLock();//卖票的方式public void sale() {lock.lock(); // 开启锁try {if (number > 0) {System.out.println(Thread.currentThread().getName() + "卖出了第" + (number--) + "张票剩余" + number + "张票");}} finally {lock.unlock(); // 关闭锁}}
}
Synchronized 与 Lock 的区别
- Synchronized 内置的 Java关键字,Lock是一个 Java 类。
- Synchronized 无法判断获取锁的状态,Lock可以判断。
- Synchronized 会自动释放锁,Lock 必须要手动加锁和手动释放锁,可能会遇到死锁。
- Synchronized 线程1(获得锁->阻塞)、线程2(等待);Lock 就不一定会一直等待下去,Lock 会有一个trylock 去尝试获取锁,不会造成长久的等待。
- Synchronized 是可重入锁,不可以中断的,非公平的;Lock是可重入的,可以判断锁,可以自己设置公平锁和非公平锁。
- Synchronized 适合锁少量的代码同步问题,Lock适合锁大量的同步代码。
生产者和消费者问题
Synchronized 版
- Synchronized、wait、notify
/*** 线程之间的通信问题:生产者和消费者问题! 等待唤醒,通知唤醒* 线程交替执行 A B 操作同一个变量 num = 0* A num+1* B num-1*/
//顺序:判断待->业务->通知
public class test {public static void main(String[] args) {Data data = new Data();new Thread(() -> {for (int i = 0; i < 10; i++) {try {data.increment();} catch (InterruptedException e) {e.printStackTrace();}}}, "A").start();new Thread(() -> {for (int i = 0; i < 10; i++) {try {data.decrement();} catch (InterruptedException e) {e.printStackTrace();}}}, "B").start();}
}class Data {private int number = 0;//+1public synchronized void increment() throws InterruptedException {if (number != 0) {//等待this.wait();}number++;System.out.println(Thread.currentThread().getName() + "=>" + number);// 通知其他线程,我-1完毕了this.notifyAll();}//-1public synchronized void decrement() throws InterruptedException {if (number == 0) {//等待this.wait();}number--;System.out.println(Thread.currentThread().getName() + "=>" + number);// 通知其他线程,我-1完毕了this.notifyAll();}
}/*A=>1B=>0A=>1B=>0...
*/
俩个加俩个减 存在问题(虚假唤醒):
如果有四个线程,会出现虚假唤醒。
if 改为 while 即可,防止虚假唤醒。
结论:
就是用 if 判断的话,唤醒后线程会从 wait 之后的代码开始运行,但是不会重新判断if条件,直接继续运行 if 代码块之后的代码,而如果使用 while 的话,也会从 wait 之后的代码运行,但是唤醒后会重新判断循环条件,如果不成立再执行 while 代码块之后的代码块,成立的话继续 wait。这也就是为什么用 while 而不用if的原因了,因为线程被唤醒后,执行开始的地方是 wait 之后。
public class test {public static void main(String[] args) {Data data = new Data();new Thread(() -> {for (int i = 0; i < 10; i++) {try {data.increment();} catch (InterruptedException e) {e.printStackTrace();}}}, "A").start();new Thread(() -> {for (int i = 0; i < 10; i++) {try {data.decrement();} catch (InterruptedException e) {e.printStackTrace();}}}, "B").start();new Thread(() -> {for (int i = 0; i < 10; i++) {try {data.increment();} catch (InterruptedException e) {e.printStackTrace();}}}, "C").start();new Thread(() -> {for (int i = 0; i < 10; i++) {try {data.decrement();} catch (InterruptedException e) {e.printStackTrace();}}}, "D").start();}
}class Data {private int number = 0;//+1public synchronized void increment() throws InterruptedException {while (number != 0) {//等待this.wait();}number++;System.out.println(Thread.currentThread().getName() + "=>" + number);// 通知其他线程,我-1完毕了this.notifyAll();}//-1public synchronized void decrement() throws InterruptedException {while (number == 0) {//等待this.wait();}number--;System.out.println(Thread.currentThread().getName() + "=>" + number);// 通知其他线程,我-1完毕了this.notifyAll();}
}
Lock版
- Lock、await(Condition)、signal(Condition)
public class test {public static void main(String[] args) {Data2 data = new Data2();new Thread(() -> {for (int i = 0; i < 10; i++) {try {data.increment();} catch (InterruptedException e) {e.printStackTrace();}}}, "A").start();new Thread(() -> {for (int i = 0; i < 10; i++) {try {data.decrement();} catch (InterruptedException e) {e.printStackTrace();}}}, "B").start();new Thread(() -> {for (int i = 0; i < 10; i++) {try {data.increment();} catch (InterruptedException e) {e.printStackTrace();}}}, "C").start();new Thread(() -> {for (int i = 0; i < 10; i++) {try {data.decrement();} catch (InterruptedException e) {e.printStackTrace();}}}, "D").start();}
}class Data2 {private int num = 0;Lock lock = new ReentrantLock();Condition condition = lock.newCondition();// +1public void increment() throws InterruptedException {lock.lock();try {// 判断等待while (num != 0) {condition.await();}num++;System.out.println(Thread.currentThread().getName() + "=>" + num);// 通知其他线程 +1 执行完毕condition.signalAll();}finally {lock.unlock();}}// -1public void decrement() throws InterruptedException {lock.lock();try {// 判断等待while (num == 0) {condition.await();}num--;System.out.println(Thread.currentThread().getName() + "=>" + num);// 通知其他线程 +1 执行完毕condition.signalAll();}finally {lock.unlock();}}
}
Condition 的优势:精准通知和唤醒线程
要指定通知的下一个进行顺序,可以使用 Condition 来指定通知进程。
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*** Description:* A 执行完 调用B* B 执行完 调用C* C 执行完 调用A**/
public class test {public static void main(String[] args) {Data3 data3 = new Data3();new Thread(() -> {for (int i = 0; i < 10; i++) {data3.printA();}},"A").start();new Thread(() -> {for (int i = 0; i < 10; i++) {data3.printB();}},"B").start();new Thread(() -> {for (int i = 0; i < 10; i++) {data3.printC();}},"C").start();}
}class Data3 {private Lock lock = new ReentrantLock();private Condition condition1 = lock.newCondition();private Condition condition2 = lock.newCondition();private Condition condition3 = lock.newCondition();private int num = 1; // 实现1A 2B 3Cpublic void printA() {lock.lock();try {// 业务代码 判断 -> 执行 -> 通知while (num != 1) {condition1.await();}System.out.println(Thread.currentThread().getName() + "==> AAAA" );// 唤醒,唤醒指定的人Bnum = 2;condition2.signal();}catch (Exception e) {e.printStackTrace();}finally {lock.unlock();}}public void printB() {lock.lock();try {// 业务代码 判断 -> 执行 -> 通知while (num != 2) {condition2.await();}System.out.println(Thread.currentThread().getName() + "==> BBBB" );num = 3;condition3.signal();}catch (Exception e) {e.printStackTrace();}finally {lock.unlock();}}public void printC() {lock.lock();try {// 业务代码 判断 -> 执行 -> 通知while (num != 3) {condition3.await();}System.out.println(Thread.currentThread().getName() + "==> CCCC" );num = 1;condition1.signal();}catch (Exception e) {e.printStackTrace();}finally {lock.unlock();}}
}
/*
A==> AAAA
B==> BBBB
C==> CCCC
A==> AAAA
B==> BBBB
C==> CCCC
...
*/
8 锁现象
如何判断锁的是谁?锁会锁住:对象、Class
问题1:两个同步方法,先执行发短信还是打电话?
import java.util.concurrent.TimeUnit;public class test {public static void main(String[] args) throws InterruptedException {Phone phone = new Phone();new Thread(() -> {phone.sendMs();}).start();TimeUnit.SECONDS.sleep(1);new Thread(() -> {phone.call();}).start();}
}class Phone {public synchronized void sendMs() {System.out.println("发短信");}public synchronized void call() {System.out.println("打电话");}
}//发短信
//打电话
问题2:问题1基础上让发短信延迟 4s
import java.util.concurrent.TimeUnit;public class test {public static void main(String[] args) throws InterruptedException {Phone phone = new Phone();new Thread(() -> {try {phone.sendMs();} catch (InterruptedException e) {e.printStackTrace();}}).start();TimeUnit.SECONDS.sleep(1);new Thread(() -> {phone.call();}).start();}
}class Phone {public synchronized void sendMs() throws InterruptedException {TimeUnit.SECONDS.sleep(4);System.out.println("发短信");}public synchronized void call() {System.out.println("打电话");}
}//发短信
//打电话
问题一问题二说明并不是顺序执行,而是 synchronized 锁住的对象是方法的调用,对于两个方法用的是同一个锁,谁先拿到谁先执行,另外一个等待。
问题三:换成一个普通方法结果?
hello 是一个普通方法,不受 synchronized 锁的影响,不用等待锁的释放。
import java.util.concurrent.TimeUnit;public class test {public static void main(String[] args) throws InterruptedException {Phone phone = new Phone();new Thread(() -> {try {phone.sendMs();} catch (InterruptedException e) {e.printStackTrace();}}).start();TimeUnit.SECONDS.sleep(1);new Thread(() -> {phone.hello();}).start();}
}class Phone {public synchronized void sendMs() throws InterruptedException {TimeUnit.SECONDS.sleep(4);System.out.println("发短信");}public synchronized void call() {System.out.println("打电话");}public void hello() {System.out.println("hello");}
}
//hello
//发短信
问题四:如果使用的是两个对象,一个调用发短信,一个调用打电话,那么整个顺序是怎么样的呢?
两个对象两把锁,不会出现等待的情况,发短信睡了4s,所以先执行打电话
import java.util.concurrent.TimeUnit;public class test {public static void main(String[] args) throws InterruptedException {Phone phone1 = new Phone();Phone phone2 = new Phone();new Thread(() -> {try {phone1.sendMs();} catch (InterruptedException e) {e.printStackTrace();}}).start();TimeUnit.SECONDS.sleep(1);new Thread(() -> {phone2.call();}).start();}
}class Phone {public synchronized void sendMs() throws InterruptedException {TimeUnit.SECONDS.sleep(4);System.out.println("发短信");}public synchronized void call() {System.out.println("打电话");}public void hello() {System.out.println("hello");}
}
//打电话
//发短信
问题五、六:如果我们把 synchronized 的方法加上 static 变成静态方法,那么顺序又是怎么样的呢?
static 静态方法来说,对于整个类 Class 来说只有一份,对于不同的对象使用的是同一份方法,相当于这个方法是属于类的,如果静态 static 方法使用 synchronized 锁定,那么这个 synchronized 锁会锁住整个对象,不管多少个对象,对于静态的锁都只有一把锁,谁先拿到这个锁就先执行,其他的进程都需要等待。
import java.util.concurrent.TimeUnit;public class test {public static void main(String[] args) throws InterruptedException {new Thread(() -> {try {Phone.sendMs();} catch (InterruptedException e) {e.printStackTrace();}}).start();TimeUnit.SECONDS.sleep(1);new Thread(() -> {Phone.call();}).start();}
}class Phone {public static synchronized void sendMs() throws InterruptedException {TimeUnit.SECONDS.sleep(4);System.out.println("发短信");}public static synchronized void call() {System.out.println("打电话");}
}
//发短信
//打电话
问题七:如果使用一个静态同步方法、一个同步方法、一个对象调用顺序是什么?
因为一个锁的是Class类的模板,一个锁的是对象的调用者。所以不存在等待,直接运行
import java.util.concurrent.TimeUnit;public class test {public static void main(String[] args) throws InterruptedException {Phone phone1 = new Phone();
// Phone phone2 = new Phone();new Thread(() -> {try {Phone.sendMs();} catch (InterruptedException e) {e.printStackTrace();}}).start();TimeUnit.SECONDS.sleep(1);new Thread(() -> {phone1.call();}).start();}
}class Phone {public static synchronized void sendMs() throws InterruptedException {TimeUnit.SECONDS.sleep(4);System.out.println("发短信");}public synchronized void call() {System.out.println("打电话");}public void hello() {System.out.println("hello");}
}
//打电话
//发短信
问题八:如果我们使用一个静态同步方法、一个同步方法、两个对象调用顺序是什么?
两把锁锁的不是同一个东西
import java.util.concurrent.TimeUnit;public class test {public static void main(String[] args) throws InterruptedException {Phone phone1 = new Phone();Phone phone2 = new Phone();new Thread(() -> {try {Phone.sendMs();} catch (InterruptedException e) {e.printStackTrace();}}).start();TimeUnit.SECONDS.sleep(1);new Thread(() -> {phone2.call();}).start();}
}class Phone {public static synchronized void sendMs() throws InterruptedException {TimeUnit.SECONDS.sleep(4);System.out.println("发短信");}public synchronized void call() {System.out.println("打电话");}public void hello() {System.out.println("hello");}
}
//打电话
//发短信
相关文章:

【JUC基础】JUC入门基础
目录 什么是JUC线程和进程锁传统的 synchronizedLock 锁Synchronized 与 Lock 的区别 生产者和消费者问题Synchronized 版Lock版Condition 的优势:精准通知和唤醒线程 8 锁现象问题1:两个同步方法,先执行发短信还是打电话?问题2&a…...

自然语言处理: 第十章GPT的API使用
理论基础 现在的以GPT为首的生成类模型,它拥有对话的能力,它会根据你输入的暗示(prompt)或者指令(instruct)生成对应的回答。所以,不同的输入会导致不同的输出(其实由于chatgpt最终生成的答案是beam_search 以及随机采样的机制,所…...

docker使用harbor进行镜像仓库管理演示以及部分报错解决
目录 一.安装harbor和docker-compose 1.下载 2.将该文件修改为这样,修改好自己的hostname和port,后文的用户和密码可以不改也可以改,用于登录 3.安装 二.修改daemon.json文件和/etc/hosts文件 三.使用powershell作windows端域名映射 四…...

【精算研究01/10】 计量经济学的性质和范围
一、说明 计量经济学是使用统计方法来发展理论或测试经济学或金融学中的现有假设。计量经济学依赖于回归模型和零假设检验等技术。计量经济学也可以用来预测未来的经济或金融趋势。 图片来源:https://marketbusinessnews.com 二、 计量经济之简介 计量经济学是对经济…...

【python知识】用 Tkinter实现“剪刀-石头-布”和“弹球游戏 ”
一、提要 Tkinter是一个Python内置模块,它提供了一个简单易用的界面来创建GUI。 在实现一些动态的画面、如游戏还是需要一些创新性思维的。在本文中,我们将使用 Tkinter 探索 Python GUI 编程。我们将介绍 Tkinter 的基础知识,并演示如何使用…...

Android 绘制之文字测量
drawText() 绘制文字 绘制进度条:paint.strokeCap Paint.CAP.RONUD 线条两边样式 设置文字字体:paint.typeFace Resources.Compat.getFont(context,font) 设置加粗 paint.isFakeBoldText 设置居中: paint.setTextAlign Paint.Align.CENTER //居中, 并不是真正的居中 往…...

基于AVR128单片机智能传送装置
一、系统方案 1、板载可变电阻(电位器)R29的电压作为处理器ATmega128的模数转换模块中单端ADC0的模拟信号输入(跳线JP13短接)。 2、调节电位器,将改变AD转换接口ADC0的模拟信号输入,由处理器完成ADC0的A/D转…...

Nexus私有仓库+IDEA配置远程推送
目录 一、docker安装nexus本地私服,Idea通过maven配置deploy本地jar包(简单) 二、docker push镜像到第三方nexus远程私服(shell命令操作) 三、springboot通过maven插件自动生成docker镜像并push到nexus私服…...

idea2023项目上传到gitee
1、按照gitee插件 File——>Settings plugins——>Marketplace下面搜索gitee,然后按照gitee插件 2、上传项目 VCS_——>Share Project on Gitee 如果第一次没登录的需要先登录,登录完后就可以上传了...

【golang】派生数据类型---指针 标识符、关键字等
1、指针 对比C/C中的指针,go语言中的指针显得极为简洁,只是简单的获取某个空间的地址 或者 根据指针变量中的内容 获取对应存储空间的内容等操作。 具体示例如下: go中使用指针需要注意的点: 可以通过指针改变它所指向的内存空…...

深度学习技术
深度学习是什么? 深度学习,英文名为Deep Learning,其实就是机器学习的一种高级形式。它的灵感来源于人脑神经网络的工作方式,是一种让机器可以自主地从数据中学习和提取特征的技术。你可以把它想象成一位小侦探,通过不…...
TCP/IP网络江湖——物理层护江山:网络安全的铁壁防线(物理层下篇:物理层与网络安全)
TCP/IP网络江湖——物理层护江山:网络安全的铁壁防线(物理层下篇:物理层与网络安全) 〇、引言一、物理层的隐私与保密1.1 加密技术的护盾1.2 安全传输协议的密约1.3 物理层的安全控制1.4 面对未知威胁的准备二、电磁干扰与抵御2.1 电磁干扰的威胁2.2 抗干扰技术的应用2.3 屏…...

python-数据可视化-使用API
使用Web应用程序编程接口 (API)自动请求网站的特定信息而不是整个网页,再对这些信息进行可视化 使用Web API Web API是网站的一部分,用于与使用具体URL请求特定信息的程序交互。这种请求称为API调用 。请求的数据将以易于处理的…...

窗口看门狗
从下往上看: 1. 时钟设置 RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE);//使能独立看门狗时钟 WWDG_SetPrescaler(WWDG_Prescaler_8);//看门狗预分频器WWDG counter clock (PCLK1/4096)/8 2.设置窗口值 实际就是设置WWDG_CR的低七位值, 但是这个值要大于0x40(也就是…...

开发新能源的好处
风能无论是总装机容量还是新增装机容量,全球都保持着较快的发展速度,风能将迎来发展高峰。风电上网电价高于火电,期待价格理顺促进发展。生物质能有望在农业资源丰富的热带和亚热带普及,主要问题是降低制造成本,生物乙…...

error: can‘t find Rust compiler
操作系统 win11 pip install -r requirements.txt 报错如下 Using cached https://pypi.tuna.tsinghua.edu.cn/packages/56/fc/a3c13ded7b3057680c8ae95a9b6cc83e63657c38e0005c400a5d018a33a7/pyreadline3-3.4.1-py3-none-any.whl (95 kB) Building wheels for collected p…...

全面解析MES系统中的车间退料管理
一、车间退料管理的定义: 车间退料是指在生产过程中,将不合格或多余的物料、半成品或成品从车间环节返还到供应链的过程。车间退料管理则是指对这一退料过程进行规范化、系统化的管理和跟踪。 二、车间退料管理的流程: 1. 退料申请…...

探究finally代码块是否执行
情况一:try代码块正常执行,无异常,finally代码块无retrun; 代码演示 public class Test38 {public static void main(String[] args) {int foo foo();System.out.println("foo:" foo);}public static int foo() {tr…...

leetcode刷题(字符串相加、包含每个查询的最小区间、模拟行走机器人、环形子数组的最大和、满足不等式的最大值、四数之和、树中距离之和)
目录 1、字符串相加 2、包含每个查询的最小区间 3、模拟行走机器人 4、环形子数组的最大和 5、满足不等式的最大值 6、四数之和 7、 树中距离之和 1、字符串相加 class Solution:def addStrings(self, num1: str, num2: str) -> str:i len(num1) - 1 # num1的末…...
Grafana reporter定时报表踩坑记录
前言:本以为测试grafana reporter功能能很顺利,但按照网上大佬分享的记录进行操作,屡屡报错,不知是因为我的grafana部署在k8s中之前由低版本升级到高版本导致的,还是其他原因,在grafana中安装Grafana Image Renderer 一直报错。 Github地址:https://github.com/IzakMar…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
React 第五十五节 Router 中 useAsyncError的使用详解
前言 useAsyncError 是 React Router v6.4 引入的一个钩子,用于处理异步操作(如数据加载)中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误:捕获在 loader 或 action 中发生的异步错误替…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...

shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...

uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...
Python实现简单音频数据压缩与解压算法
Python实现简单音频数据压缩与解压算法 引言 在音频数据处理中,压缩算法是降低存储成本和传输效率的关键技术。Python作为一门灵活且功能强大的编程语言,提供了丰富的库和工具来实现音频数据的压缩与解压。本文将通过一个简单的音频数据压缩与解压算法…...

Axure 下拉框联动
实现选省、选完省之后选对应省份下的市区...

Neko虚拟浏览器远程协作方案:Docker+内网穿透技术部署实践
前言:本文将向开发者介绍一款创新性协作工具——Neko虚拟浏览器。在数字化协作场景中,跨地域的团队常需面对实时共享屏幕、协同编辑文档等需求。通过本指南,你将掌握在Ubuntu系统中使用容器化技术部署该工具的具体方案,并结合内网…...

若依登录用户名和密码加密
/*** 获取公钥:前端用来密码加密* return*/GetMapping("/getPublicKey")public RSAUtil.RSAKeyPair getPublicKey() {return RSAUtil.rsaKeyPair();}新建RSAUti.Java package com.ruoyi.common.utils;import org.apache.commons.codec.binary.Base64; im…...