并发编程---java锁
java锁
- 一 多线程锁synchronized案例分析
- 1.1synchronized介绍
- 1.2 synchronized案例分析
- 1.2.1.标准访问,请问先打印邮件还是短信?
- 1.2.2.邮件⽅法暂停4秒钟,请问先打印邮件还是短信?
- 分析
- 1.2.3.新增⼀个普通⽅法hello(),请问先打印邮件还是hello?
- 1.2.4.两部⼿机,请问先打印邮件还是短信?
- 1.2.5.两个静态同步⽅法,同⼀部⼿机,请问先打印邮件还是短信?
- 1.2.6.两个静态同步⽅法,2部⼿机,请问先打印邮件还是短信?
- 1.2.7.1个普通同步⽅法,1个静态同步⽅法,1部⼿机,请问先打印邮件还是短信?
- 1.2.8.1个普通同步⽅法,1个静态同步⽅法,2部⼿机,请问先打印邮件还有短信?
- 1.2.8 总结
- 二⼈⼯窗⼝排队购票(回顾)
- 三 公平锁⾮公平锁 (⽕⻋站⼈⼯窗⼝排队购票)
- 四 可重⼊锁/递归锁
- 锁的配对
- 五 ⾃旋锁
- 六 读写锁/独占/共享
一 多线程锁synchronized案例分析
1.1synchronized介绍
关键字synchronized可以保证在同一时刻,只有一个线程可以执行某个方法或某个代码块,同时synchronized可以保证一个线程的变化可见(可见性),即可以代替volatile使用方法
1.普通同步方法(实例方法),锁是当前实例对象 ,进入同步代码前要获得当前实例的锁
2.静态同步方法,锁是当前类的class对象 ,进入同步代码前要获得当前类对象的锁
3.同步方法块,锁是括号里面的对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁
1.2 synchronized案例分析
使用8个案例来详细说明synchronized的加锁用法:
1.标准访问,请问先打印邮件还是短信?
2.邮件⽅法暂停4秒钟,请问先打印邮件还是短信?
3.新增⼀个普通⽅法hello(),请问先打印邮件还是hello?
4.两部⼿机,请问先打印邮件还是短信?
5.两个静态同步⽅法,同⼀部⼿机,请问先打印邮件还是短信?
6.两个静态同步⽅法,2部⼿机,请问先打印邮件还是短信?
7.1个普通同步⽅法,1个静态同步⽅法,1部⼿机,请问先打印邮件还是短信?
8.1个普通同步⽅法,1个静态同步⽅法,2部⼿机,请问先打印邮件还有短信?
1.2.1.标准访问,请问先打印邮件还是短信?
答案:邮件
class Phone {public synchronized void sendEmail() {System.out.println("==========sendEmail");}public synchronized void sendMessage() {System.out.println("======sendMessage");}
}public class LockDemo {public static void main(String[] args) {Phone phone = new Phone();new Thread(() -> {phone.sendEmail();}, "t1").start();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}new Thread(() -> {phone.sendMessage();}, "t2").start();//==========sendEmail//======sendMessage}
}
1.2.2.邮件⽅法暂停4秒钟,请问先打印邮件还是短信?
答案:邮件
//2. 邮件方法暂停4秒钟,请问先打印邮件还是短信? 邮件
class Phone {public synchronized void sendEmail() {try {TimeUnit.SECONDS.sleep(4);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("==========sendEmail");}public synchronized void sendMessage() {System.out.println("======sendMessage");}}public class LockDemo {public static void main(String[] args) {Phone phone = new Phone();new Thread(() -> {phone.sendEmail();}, "t1").start();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}new Thread(() -> {phone.sendMessage();}, "t2").start();//==========sendEmail//======sendMessage}
}
分析
普通同步方法(实例方法),锁是当前实例对象 ,进入同步代码前要获得当前实例的锁
⼀个对象⾥⾯如果有多个synchronized⽅法,某⼀个时刻内,只要⼀个线程去调⽤其中的⼀个synchronized⽅法了,其他的线程都只能等待。换句话说,某⼀个时刻内,只能有唯⼀⼀个线程去访问这些 synchronized⽅法,锁的是当前对象this(new 的这个phone),被锁定后,其他的线程都不能进⼊到当前对象的其他的synchronized⽅法。

1.2.3.新增⼀个普通⽅法hello(),请问先打印邮件还是hello?
答案:hello
加个普通⽅法后发现和同步锁⽆关

//3. 新增一个普通方法hello(),请问先打印邮件还是hello?
class Phone {public synchronized void sendEmail() {try {TimeUnit.SECONDS.sleep(4);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("==========sendEmail");}public synchronized void sendMessage() {System.out.println("======sendMessage");}public void hello() {System.out.println("sayHello");}
}public class LockDemo {public static void main(String[] args) {Phone phone = new Phone();new Thread(() -> {phone.sendEmail();}, "t1").start();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}new Thread(() -> {phone.sendMessage();}, "t2").start();new Thread(() -> {phone.hello();}, "t3").start();//sayHello//==========sendEmail//======sendMessage}
}
1.2.4.两部⼿机,请问先打印邮件还是短信?
答案:邮件
分析:换成两个对象后,不是同⼀把锁了,情况⽴刻变化
//4. 两部手机,请问先打印邮件还是短信?
class Phone {public synchronized void sendEmail() {try {TimeUnit.SECONDS.sleep(4);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("==========sendEmail");}public synchronized void sendMessage() {System.out.println("======sendMessage");}public void hello() {System.out.println("sayHello");}
}public class LockDemo {public static void main(String[] args) {Phone phone = new Phone();Phone phone2 = new Phone();new Thread(() -> {phone.sendEmail();}, "t1").start();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}new Thread(() -> {phone2.sendMessage();}, "t2").start();//======sendMessage//==========sendEmail}
}
1.2.5.两个静态同步⽅法,同⼀部⼿机,请问先打印邮件还是短信?
答案:邮件
分析:见 1.2.6
//5. 两个静态同步方法,同一部手机,请问先打印邮件还是短信?
class Phone {public static synchronized void sendEmail() {try {TimeUnit.SECONDS.sleep(4);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("==========sendEmail");}public static synchronized void sendMessage() {System.out.println("======sendMessage");}public void hello() {System.out.println("sayHello");}
}public class LockDemo {public static void main(String[] args) {Phone phone = new Phone();new Thread(() -> {phone.sendEmail();}, "t1").start();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}new Thread(() -> {phone.sendMessage();}, "t2").start();//==========sendEmail//======sendMessage}
}
1.2.6.两个静态同步⽅法,2部⼿机,请问先打印邮件还是短信?
答案: 邮件
分析: 静态同步方法,锁是当前类的class对象 ,进入同步代码前要获得当前类对象的锁
全局锁

//6. 两个静态同步方法,2部手机,请问先打印邮件还是短信?
class Phone {public static synchronized void sendEmail() {try {TimeUnit.SECONDS.sleep(4);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("==========sendEmail");}public static synchronized void sendMessage() {System.out.println("======sendMessage");}public void hello() {System.out.println("sayHello");}
}public class LockDemo {public static void main(String[] args) {Phone phone = new Phone();Phone phone2 = new Phone();new Thread(() -> {phone.sendEmail();}, "t1").start();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}new Thread(() -> {phone2.sendMessage();}, "t2").start();//==========sendEmail//======sendMessage}
}
1.2.7.1个普通同步⽅法,1个静态同步⽅法,1部⼿机,请问先打印邮件还是短信?
答案: 短信
分析:

//7. 1个普通同步方法,1个静态同步方法,1部手机,请问先打印邮件还是短信?
class Phone {public synchronized void sendEmail() {try {TimeUnit.SECONDS.sleep(4);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("==========sendEmail");}public static synchronized void sendMessage() {System.out.println("======sendMessage");}public void hello() {System.out.println("sayHello");}
}public class LockDemo {public static void main(String[] args) {Phone phone = new Phone();new Thread(() -> {phone.sendEmail();}, "t1").start();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}new Thread(() -> {phone.sendMessage();}, "t2").start();//======sendMessage//==========sendEmail}
}
1.2.8.1个普通同步⽅法,1个静态同步⽅法,2部⼿机,请问先打印邮件还有短信?
答案: 短信
分析:

1.2.8 总结
(1)当⼀个线程试图访问同步代码块时,它⾸先必须得到锁,退出或抛出异常时必须释放锁。 也就是说如果⼀个实例对象的普通同步⽅法获取锁后,该实例对象的其他普通同步⽅法必须等待获取锁的⽅法释放锁后才能获取锁,可是别的实例对象的普通同步⽅法因为跟该实例对象的普通同步⽅法⽤的是不同的锁,所以⽆需等待该实例对象已获取锁的普通同步⽅法释放锁就可以获取他们⾃⼰的锁。
(2)所有的静态同步⽅法⽤的也是同⼀把锁–类对象本身, 这两把锁(this/class)是两个不同的对象,所以静态同步⽅法与⾮静态同步⽅法之间是 不会有静态条件的。 但是⼀旦⼀个静态同步⽅法获取锁后,其他的静态同步⽅法都必须等待该⽅法释放锁后才能获取锁,⽽不管是同⼀个实例对象的静态同步⽅法之间,还是不同的实例对象的静态同步⽅法之间,只要它们同⼀个类的实例对象
二⼈⼯窗⼝排队购票(回顾)
题目:三个售票员 卖出 30张票
多个线程共抢一个资源
/*** 题目:三个售票员 卖出 30张票**/
class Ticket{//资源类//票private int number = 30;public synchronized void saleTicket(){if (number > 0) {System.out.println(Thread.currentThread().getName()+"\t卖出第:"+(number--)+"\t还剩下:"+number);}}}public class SaleTicketDemo {public static void main(String[] args) {Ticket ticket = new Ticket();new Thread(()->{ for (int i = 1; i <= 30 ; i++) ticket.saleTicket(); }, "A").start();new Thread(()->{ for (int i = 1; i <= 30 ; i++) ticket.saleTicket(); }, "B").start();new Thread(()->{ for (int i = 1; i <= 30 ; i++) ticket.saleTicket(); }, "C").start();}
}

我们用synchronized同步代码块的方式来解决。随着juc并发编程。我们有更加轻量级的锁方式来解决问题。
三 公平锁⾮公平锁 (⽕⻋站⼈⼯窗⼝排队购票)
lcok锁
Lock lock = new ReentrantLock();



概念:
公平锁,就是多个线程按照申请锁的顺序来获取锁,类似排队,先到先得。
⾮公平锁,则是多个线程抢夺锁,会导致优先级反转或饥饿现象。
区别:
- 公平锁在获取锁时先查看此锁维护的等待队列,为空或者当前线程是等待队列的队⾸,则直接占有锁,否则插⼊到等待队列,FIFO原则。
- ⾮公平锁⽐较粗鲁,上来直接先尝试占有锁,失败则采⽤公平锁⽅式。⾮公平锁的优点是吞吐量⽐公平锁更⼤。
synchronized和 juc.ReentrantLock默认都是⾮公平锁。 ReentrantLock在构造的时候传⼊ true 则是公平锁。
四 可重⼊锁/递归锁

可重⼊锁⼜叫递归锁,指的同⼀个线程在外层⽅法获得锁时,进⼊内层⽅法会⾃动获取锁。也就是说,线程可以进⼊任何⼀个它已经拥有锁的代码块。
⽐如method01⽅法⾥⾯有method02⽅法,两个⽅法都有同⼀把锁,得到了method01的锁。就⾃动得到了method02的锁,就像有了家⻔的锁,厕所、书房、厨房就为你敞开了⼀样。可重⼊锁可以避免死锁的问题。

/*** 可重入锁/递归锁*/class PhonePlus implements Runnable{//Synchronized Testpublic synchronized void sendEmail(){System.out.println(Thread.currentThread().getName()+"\t"+"sendEmail");sendSMS();}public synchronized void sendSMS(){System.out.println(Thread.currentThread().getName()+"\t"+"sendSMS");}//ReenTrantLock TestLock lock = new ReentrantLock();public void method1(){lock.lock();try {System.out.println(Thread.currentThread().getName()+"\t"+"method1");method2();} finally {lock.unlock();}}public void method2() {lock.lock();try {System.out.println(Thread.currentThread().getName()+"\t"+"method2");} finally {lock.unlock();}}@Overridepublic void run() {method1();}
}public class ReentrantLockDemo {public static void main(String[] args) {PhonePlus phonePlus = new PhonePlus();new Thread(()->{phonePlus.sendEmail();}, "t1").start();new Thread(()->{phonePlus.sendEmail();}, "t2").start();Thread t3 = new Thread(phonePlus);Thread t4 = new Thread(phonePlus);t3.start();t4.start();}
}
锁的配对
锁之间要配对,加了⼏把锁,最后就得解开⼏把锁,下⾯的代码编译和运⾏都没有任何问题。但锁的数量不匹配会导致死循环。
lock.lock();
lock.lock();
try{someAction();
}finally{lock.unlock();
}
五 ⾃旋锁
所谓⾃旋锁,就是尝试获取锁的线程不会⽴即阻塞,⽽是采⽤循环的⽅式去尝试获取。⾃⼰在那⼉⼀直循环获取,就像“⾃旋”⼀样。这样的好处是减少线程切换的上下⽂开销,缺点是会消耗CPU。CAS底层的 getAndAddInt就是⾃旋锁思想。
//跟CAS类似,⼀直循环⽐较。
while (!atomicReference.compareAndSet(null, thread)) { }

/*** 题目:实现一个自旋锁* 自旋锁好处:循环比较获取直到成功为止,没有类似wait的阻塞。* <p>* 通过CAS操作完成自旋锁,A线程先进来调用myLock方法自己持有锁5秒钟,* B随后进来后发现当前有线程持有锁,不是null,所以只能通过自选等待,直到A释放锁后B随后抢到。*/
public class SpinLockDemo {//原子引用(线程)AtomicReference<Thread> atomicReference = new AtomicReference<>(); //Thread ==> null//获取锁public void myLock() {Thread currentThread = Thread.currentThread();System.out.println(Thread.currentThread().getName() + "\t com in...");while (!atomicReference.compareAndSet(null, currentThread)) {}}//释放锁public void myUnLock() {Thread currentThread = Thread.currentThread();atomicReference.compareAndSet(currentThread, null);System.out.println(Thread.currentThread().getName() + "\t unlock....");}public static void main(String[] args) {SpinLockDemo spinLockDemo = new SpinLockDemo();new Thread(() -> {spinLockDemo.myLock();try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}spinLockDemo.myUnLock();}, "AA").start();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}new Thread(() -> {spinLockDemo.myLock();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}spinLockDemo.myUnLock();}, "BB").start();}
}
结果

过程分析

六 读写锁/独占/共享
读锁是共享的,写锁是独占的。 juc.ReentrantLock和 synchronized都是独占锁,独占锁就是⼀个锁只能被⼀个线程所持有。有的时候,需要读写分离,那么就要引⼊读写锁,即 juc.ReentrantReadWriteLock。
独占锁:指该锁⼀次只能被⼀个线程所持有。对
ReentrantLock和Synchronized⽽⾔都是独占锁
共享锁:指该锁可被多个线程所持有
对ReenntrantReadWriteLock其读锁是共享锁,其写锁是独占锁。
读锁的共享锁可保证并发读是⾮常⾼效的,读写、写读、写写的过程是互斥的。
⽐如缓存,就需要读写锁来控制。缓存就是⼀个键值对,以下Demo模拟了缓存的读写操作,读的 get ⽅法使⽤了 ReentrantReadWriteLock.ReadLock(),写的 put⽅法使⽤了ReentrantReadWriteLock.WriteLock()。这样避免了写被打断,实现了多个线程同时读。
相关文章:
并发编程---java锁
java锁一 多线程锁synchronized案例分析1.1synchronized介绍1.2 synchronized案例分析1.2.1.标准访问,请问先打印邮件还是短信?1.2.2.邮件⽅法暂停4秒钟,请问先打印邮件还是短信?分析1.2.3.新增⼀个普通⽅法hello(&…...
品牌营销 | 学习如何最大限度地发挥品牌营销的作用
您是否想过如何最大限度地发挥品牌营销的潜力?这是一项艰巨的挑战,通过了解品牌营销的基本组成部分,您可以成功地推广您的品牌。 (图源:Pixabay) 品牌营销的基本组成部分 你需要做什么来发展稳固的品牌&am…...
Linux驱动的同步阻塞和同步非阻塞
在字符设备驱动中,若要求应用与驱动同步,则在驱动程序中可以根据情况实现为阻塞或非阻塞一、同步阻塞这种操作会阻塞应用程序直到设备完成read/write操作或者返回一个错误码。在应用程序阻塞这段时间,程序所代表的进程并不消耗CPU的时间&…...
LearnOpenGL-光照-5.投光物
本人刚学OpenGL不久且自学,文中定有代码、术语等错误,欢迎指正 我写的项目地址:https://github.com/liujianjie/LearnOpenGLProject 文章目录投光物平行光点光源聚光不平滑的例子平滑例子投光物 前面几节使用的光照都来自于空间中的一个点 即…...
【C语言】每日刷题 —— 牛客语法篇(1)
前言 大家好,今天带来一篇新的专栏c_牛客,不出意外的话每天更新十道题,难度也是从易到难,自己复习的同时也希望能帮助到大家,题目答案会根据我所学到的知识提供最优解。 🏡个人主页:悲伤的猪大…...
【深度学习】Subword Tokenization算法
在自然语言处理中,面临的首要问题是如何让模型认识我们的文本信息,词,是自然语言处理中基本单位,神经网络模型的训练和预测都需要借助词表来对句子进行表示。 1.构建词表的传统方法 在字词模型问世之前,做自然语言处理…...
五分钟了解支付、交易、清算、银行等专业名词的含义?
五分钟了解支付、交易、清算、银行等专业名词的含义?1. 支付类名词01 支付应用02 支付场景03 交易类型04 支付类型(按通道类型)05 支付类型(按业务双方类型)06 支付方式07 支付产品08 收银台类型09 支付通道10 通道类型…...
4个工具,让 ChatGPT 如虎添翼!
LightGBM中文文档 机器学习统计学,476页 机器学习圣经PRML中文版...
初识PO、VO、DAO、BO、DTO、POJO时
PO、VO、DAO、BO、DTO、POJO 区别分层领域模型规约DO(Data Object)DTO(Data Transfer Object)BO(Business Object)AO(ApplicationObject)VO(View Object)Query领域模型命名规约:一、PO :(persistant object ),持久对象二、VO :(value object) ࿰…...
[2.2.4]进程管理——FCFS、SJF、HRRN调度算法
文章目录第二章 进程管理FCFS、SJF、HRRN调度算法(一)先来先服务(FCFS, First Come First Serve)(二)短作业优先(SJF, Shortest Job First)对FCFS和SJF两种算法的思考(三…...
【代码随想录Day55】动态规划
583 两个字符串的删除操作 https://leetcode.cn/problems/delete-operation-for-two-strings/72 编辑距离https://leetcode.cn/problems/edit-distance/...
Java开发 - 消息队列前瞻
前言 学完了Redis,那你一定不能错过消息队列,要说他俩之间的关联?关联是有的,但也不见得很大,只是他们都是大数据领域常用的一种工具,一种用来提高程序运行效率的工具。常见于高并发,大数据&am…...
MySQL连接IDEA详细教程
使用IDEA的时候,需要连接Database,连接时遇到了一些小问题,下面记录一下操作流程以及遇到的问题的解决方法。 目录 MySQL连接IDEA详细教程 MySQL连接IDEA详细教程 打开idea,点击右侧的 Database 或者 选择 View --> Tool Wind…...
线程(操作系统408)
基本概念 我们说引入进程的目的是更好的使用多道程序并发执行,提高资源的利用率和系统吞吐量;而引入线程的目的则是减小程序在并发执行的时候所付出的时间开销,提高操作系统的并发性能。 线程可以理解成"轻量级进程",…...
功耗降低99%,Panamorph超清VR光学架构解析
近期,投影仪变形镜头厂商Panamorph获得新型VR显示技术专利(US11493773B2),该专利方案采用了紧凑的结构,结合了Pancake透镜和光波导显示模组,宣称比传统VR方案的功耗、发热减少99%以上,可显著提高…...
【数据结构】带你深入理解栈
一. 栈的基本概念💫栈是一种特殊的线性表。其只允许在固定的一端进行插入和删除元素的操作,进行数据的插入和删除的一端称作栈顶,另外一端称作栈底。栈不支持随机访问,栈的数据元素遵循后进先出的原则,即LIFOÿ…...
认识CSS之如何提高写前端代码的效率
🌟所属专栏:前端只因变凤凰之路🐔作者简介:rchjr——五带信管菜只因一枚😮前言:该系列将持续更新前端的相关学习笔记,欢迎和我一样的小白订阅,一起学习共同进步~👉文章简…...
Vue中watch和computed
首先这里进行声明,这个讲的是vue2的内容,在vue3发生了什么变动与此无关 这里是官网: https://v2.cn.vuejs.org/v2/guide/installation.html computed > 计算属性 watch > 侦听器(也叫监视器) 其区别如下&…...
华为鲲鹏+银河麒麟v10 安装 docker-ce
设备:硬件:仅有ARM处理器,无GPU和NPU,操作系统麒麟银河V10,Kunpeng-920 #######参考原链接######### 华为鲲鹏银河麒麟v10 安装 docker-ce 踩坑 - akiyaの博客 在 arm64(aarch64) 架构服务器上基于国产化操作系统安…...
Lambda,Stream,响应式编程从入门到放弃
Lambda表达式 Java8新引入的语法糖 Lambda表达式*(关于lambda表达式是否属于语法糖存在很多争议,有人说他并不是语法糖,这里我们不纠结于字面表述)*。Lambda表达式是一种用于取代匿名类,把函数行为表述为函数式编程风…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
边缘计算医疗风险自查APP开发方案
核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...
[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...
用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found", "n…...
