模板演示网站/谷歌chrome安卓版
锁策略(CAS,死锁)和多线程对集合类的使用
锁策略
1.乐观锁VS悲观锁
2.轻量级锁VS重量级锁
3.自旋锁VS挂起等待锁
4.互斥锁VS读写锁
5.可重入锁vs不可重入锁
死锁的第一种情况
死锁的第二种情况
死锁的第三种情况
CAS
1.实现原子类
2.实现自旋锁
偏向锁:非必要,不加锁
锁消除
锁粗化
Callable 的用法
JUC(ava.util.concurrent)
原子类
信号量 Semaphore
CountDownLatch
多线程对集合类的使用
多线程环境使用 顺序表
多线程环境使用队列
多线程环境使用哈希表
其他方面的改进:
更充分的利用了CAS机制--无锁编程
优化了扩容策略
锁策略
上面我说过,锁是为了解决线程冲突的问题。但是我也说过加锁操作会影响程序的效率。(因为阻塞),为了应对这个我们应该合理去进行加锁操作,那么就应该有策略的操作。
1.乐观锁VS悲观锁
乐观锁: 预测接下来冲突概率不大(做的工作少)--->效率会快一些
悲观锁:预测接下了的冲突概率不大(做的多)--->x效率会慢一些
其实这两个就是预测接下来的锁冲突(阻塞等待)的概率是大,还是不大,根据这个冲突的概率,决定接下来怎么做。
Synchronized 初始使用乐观锁策略. 当发现锁竞争比较频繁的时候, 就会自动切换成悲观锁策略.
2.轻量级锁VS重量级锁
轻量级锁:加锁解锁的过程更快更高效。(一个乐观锁很可能是一个轻量级锁)
重量级锁:加锁解锁,过程更慢,更低效。(一个悲观锁很可能是一个重量级锁)
3.自旋锁VS挂起等待锁
自旋锁:是轻量级锁的一种典型实现(纯用户态的不需要经过内核态(时间相对更短))
加锁失败后,不停等待的去问是否可以加锁了
挂起等待锁:是重量级锁的一种典型实现(通过内核机制来实现挂起等待(时间更长了))
加锁失败后,先去做其他事情,等这个锁给我信号后我就回来加锁。
Synchronized 既是悲观锁,也是乐观锁,既是轻量级锁,也是重量级锁;轻量级锁部分基于自旋锁实现,重量级锁部分基于挂起等待锁实现。
而Synchronized 会根据当前锁竞争的激烈程度,自适应;
- 如果冲突不激烈,以轻量级锁或者乐观锁的状态运行
- 如果激烈,以重量级锁或悲观锁的状态运行。
4.互斥锁VS读写锁
互斥锁:
synchronized是一个互斥锁,就单纯的加锁。通常只有两种操作:
- 进入代码块,加锁
- 出代码块,解锁
读写锁:
有一种锁,把读操作和写操作分开加锁(线程安全):
- 给读加锁
- 给写加锁
- 解锁
约定:
- 读锁和读锁之间,不会锁竞争,不会产生冲突(不会影响程序之间的效率)
- 写锁和写锁之间,有锁竞争(减慢速度,保证准确性)
- 读锁和写锁之间,有锁竞争(减慢速度,保证准确性)
Java中专门提供了读锁一个类,写锁一个类。
5.可重入锁vs不可重入锁
- 如果一个锁,在一个线程中,连续对锁,锁了两次,不产生死锁,叫可重入锁。
- 如果一个锁,在一个线程中,连续对锁,锁了两次,产生死锁,叫不可重入锁。
死锁的第一种情况
如何产生死锁,我们对一个代码加两次锁,此时内部的锁要等待外部的锁释放才能加锁,而此时外部的锁释放,需要等待内部锁加锁成功。然后逻辑上矛盾了,于是产生了死锁。
死锁的第二种情况
两个线程两把锁,即使单个线程是可重入锁,也会死锁。
线程1的外部锁加锁,需要等待线程2内部锁释放,同理线程2外部锁加锁,需要等待线程1内部锁释放,此时逻辑矛盾,产生死锁。
死锁的第三种情况
哲学家,就餐问题(N个线程,M把锁)
一个桌子上有五只筷子。也有五个人,桌上有一碗面,每个人只能用一双筷子吃一口。诺是五个同时拿起一只筷子,场上就构不成一双筷子的条件,也就是谁都吃不了面。此时就死锁了。
怎么办,很简单,五个人约定一个规则,谁先吃,谁后吃,此时就可以避开死锁的情况。
死锁的四个必要条件
- 互斥使用:一个线程拿到一把锁后,另一个线程不能使用(根本问题锁的基本特点)
- 不可抢占:一个线程拿到锁,只能自己主动释放,不能是被其他线程强行占有
- 请求和保持:一个线程拿到一个锁,不去做事,反而想拿到第二把锁。
- 循环等待:逻辑冲突。谁都拿不到。
实践中如何避免死锁?
对锁进行编号,如果需要获取多把锁,就约定加锁顺序,务必先对编号小的加锁,在对编号大的加锁。
公平锁VS非公平锁
约定:
遵循先来后到,就是公平锁,不遵守先来后到的(等概率竞争是不公平的),非公平锁。
synchronized是非公平的,要实现公平就需要在synchronized的基础上,加个队列来记录这些加锁线程的顺序。
总结一下synchronized的特点:
- 既是乐观锁,也是悲观锁
- 既是轻量级锁,也是重量级锁
- 轻量级锁基于自旋锁实现,重量级锁基于挂起等待实现
- 不是读写锁
- 是可重入锁
- 是非公平锁
CAS
CAS: 全称Compare and swap,字面意思:“比较并交换”,一个 CAS 涉及到以下操作:
我们假设内存中的原数据V,旧的预期值A,需要修改的新值B。
1. 比较 A 与 V 是否相等。(比较)
2. 如果比较相等,将 B 写入 V。(交换)
3. 返回操作是否成功。
真实的 CAS (即cpu的一条指令)是一个原子的硬件指令完成的(具有原子性),相当于我们不加锁,就能保证线程安全。
当多个线程同时对某个资源进行CAS操作,只能有一个线程操作成功,但是并不会阻塞其他线程,其他线程只会收到操作失败的信号。
CAS 可以视为是一种乐观锁. (或者可以理解成 CAS 是乐观锁的一种实现方式)
讲到锁操作的时候,我们说过因为一个读一个写的两个线程,他们不会自己去检查变量是否发生过改变。但是CAS却可以进行自检,并返回是否成功。
基于CAS实现的操作:
1.实现原子类
标准库里提供AtomInteger类保证程序的原子性
- AtomicBoolean
- AtomicInteger
- AtomicIntegerArray
- AtomicLong
- AtomicReference
- AtomicStampedReference
2.实现自旋锁
通过CAS的自检性,反复检查当前的锁状态,看是否解开了;
但是CAS不是没有问题,最典型的问题A->B->A问题,其实就是我们要内存改变的值与内存的值一样,是得不断在A--B--A中不断横跳。在具体一点就是,两个线程(t1,t2)对数据进行减法,(t3)还有一个对数据进行加法,而加的数据与减的数据一样。
那么就会有一个问题。两个线程中其中一个线程(t1)提前做了减操作,接下来是(t3)加操作,此时内存的值没变,t2线程发现值是原来的值,又做了一次减操作。(这显然不是我们所期望的)
如何解决呢?
加入一个衡量内存的值是否变化的量,俗称版本号,版本号只能增加无法减少,每一次修改版本+1,这样我只需对比版本号本身就可以避免aba问题。
synchronized的锁策略:锁升级
偏向锁:非必要,不加锁
先让线程针对锁,有个标记,如果整个代码执行过程中没有遇到别的线程和我竞争这个所,我就加锁了。但是如果有人来竞争,就升级为真的锁。这样既保证了效率,也保证了线程安全。
锁消除
基础逻辑是,非必要不加锁。编译器+JVM 判断锁是否可消除,如果可以,就直接消除。检测当前代码是否多线程执行,判断是否有必要加锁,如果没有必要,但是又加上了锁,就会在编译过程中自动取消掉。
比如StringBuffer,在源码内加入了synchronized关键字。诺是单线程就必要加锁了,也就可以取消掉。
锁粗化
锁的粒度,synchronized代码块,包含代码的多少(代码越多,粒度越粗,越少,粒度越细),多数情况希望锁的粒度更小。(串行代码少,意味着并发代码就多。)
如果有一个场景需要频繁的加锁解锁,此时就会将整个场景锁起来,变成一个更粗的锁
Callable 的用法
Callable 是一个 interface . 相当于把线程封装了一个 "返回值". 方便程序猿借助多线程的方式计算结果,非常类似于Runnable,只不过返回值不是void,而是泛型
创建线程计算 1 + 2 + 3 + ... + 1000(非callable)
//创建一个类 Result , 包含一个 sum 表示最终结果, lock 表示线程同步使用的锁对象
static class Result {public int sum = 0;public Object lock = new Object();
}
public static void main(String[] args) throws InterruptedException {Result result = new Result();Thread t = new Thread() {@Overridepublic void run() {
//main 方法中先创建 Result 实例, 然后创建一个线程 t. 在线程内部计算 1 + 2 + 3 + ... + 1000int sum = 0;for (int i = 1; i <= 1000; i++) {sum += i;}synchronized (result.lock) {result.sum = sum;
//主线程同时使用 wait 等待线程 t 计算结束result.lock.notify();}}};t.start();synchronized (result.lock) {//while (result.sum == 0) {result.lock.wait();}
//当线程 t 计算完毕后, 通过 notify 唤醒主线程, 主线程再打印结果.System.out.println(result.sum);}
}
创建线程计算 1 + 2 + 3 + ... + 1000(callable)
Callable<Integer> callable = new Callable<Integer>() {@Overridepublic Integer call() throws Exception {int sum = 0;for (int i = 1; i <= 1000; i++) {sum += i;}return sum;}
};
FutureTask<Integer> futureTask = new FutureTask<>(callable);
Thread t = new Thread(futureTask);
t.start();
int result = futureTask.get();
System.out.println(result);
- 创建一个匿名内部类, 实现 Callable 接口. Callable 带有泛型参数. 泛型参数表示返回值的类型.
- 重写 Callable 的 call 方法, 完成累加的过程. 直接通过返回值返回计算结果.
- 把 callable 实例使用 FutureTask 包装一下.
- 创建线程, 线程的构造方法传入 FutureTask . 此时新线程就会执行 FutureTask 内部的 Callable 的
- call 方法, 完成计算. 计算结果就放到了 FutureTask 对象中.
- 在主线程中调用 futureTask.get() 能够阻塞等待新线程计算完毕. 并获取到 FutureTask 中的结 果.
Callable中泛型是什么,就返回什么。
Callable 和 Runnable的区别
- Callable 和 Runnable 相对, 都是描述一个 "任务",Callable 描述的是带有返回值的任务,Runnable 描述的是不带返回值的任务。
- Callable 通常需要搭配 FutureTask 来使用.,FutureTask 用来保存 Callable 的返回结果. 因为Callable 往往是在另一个线程中执行的, 啥时候执行完并不确定。
- FutureTask 就可以负责这个等待结果出来的工作。
FutureTask 的理解,其实可以理解为,炖汤,通常炖汤我们将食物放入砂锅中,只需要等待时间过去2-3小时,砂锅就能为我们呈现一锅鲜美的汤。
JUC(ava.util.concurrent)
ReentrantLock:可重入互斥锁. 和 synchronized 定位类似, 都是用来实现互斥效果, 保证线程安全
用法:
- lock(): 加锁, 如果获取不到锁就死等.
- trylock(超时时间): 加锁, 如果获取不到锁, 等待一定的时间之后就放弃加锁.(加锁失败,不会阻塞,直接返回false,更灵活)
- unlock(): 解锁
ReentrantLock 和 Synchronized 的区别:
- synchronized 是一个关键字, 是 JVM 内部实现的(大概率是基于 C++ 实现). ReentrantLock 是标准 库的一个类, 在 JVM 外实现的(基于 Java 实现).
- synchronized 使用时不需要手动释放锁. ReentrantLock 使用时需要手动释放. 使用起来更灵活, 但是也容易遗漏 unlock.
- synchronized 在申请锁失败时, 会死等. ReentrantLock 可以通过 trylock 的方式等待一段时间就 放弃.
- synchronized 是非公平锁, ReentrantLock 默认是非公平锁,但是提供了公平和非公平两种工作模式. 可以通过构造方法传入一个 true 开启公平锁模式.
-
更强大的唤醒机制. synchronized 是通过 Object 的 wait / notify 实现等待-唤醒. 每次唤醒的是一 个随机等待的线程. ReentrantLock 搭配 Condition 类实现等待-唤醒, 可以更精确控制唤醒某个指定的线程.
如何选择使用哪个锁?
- 锁竞争不激烈的时候, 使用 synchronized, 效率更高, 自动释放更方便。
- 锁竞争激烈的时候, 使用 ReentrantLock, 搭配 trylock 更灵活控制加锁的行为, 而不是死等。
- 如果需要使用公平锁, 使用 ReentrantLock。
原子类
原子类内部用的是 CAS 实现,所以性能要比加锁实现 i++ 高很多。原子类有以下几个
- AtomicBoolean
- AtomicInteger
- AtomicIntegerArray
- AtomicLong
- AtomicReference
- AtomicStampedReference
信号量 Semaphore
本质是一个计数器,描述了当前“可用资源”的个数
- P操作,申请资源。计数器-1;
- V操作,释放资源。计数器+1;
如果计数器为0,就阻塞等待,等待出现资源时,及继续申请等待。
- 创建 Semaphore 示例, 初始化为 4, 表示有 4 个可用资源。
- acquire 方法表示申请资源(P操作), release 方法表示释放资源(V操作)
- 创建 20 个线程, 每个线程都尝试申请资源, sleep 1秒之后, 释放资源. 观察程序的执行效果。
Semaphore semaphore = new Semaphore(4);
Runnable runnable = new Runnable() {@Overridepublic void run() {try {System.out.println("申请资源");semaphore.acquire();System.out.println("我获取到资源了");Thread.sleep(1000);System.out.println("我释放资源了");semaphore.release();} catch (InterruptedException e) {e.printStackTrace();}}
};
for (int i = 0; i < 20; i++) {Thread t = new Thread(runnable);t.start();
}
CountDownLatch
同时等待 N 个任务执行结束.
- 构造 CountDownLatch 实例, 初始化 10 表示有 10 个任务需要完成。
- 每个任务执行完毕, 都调用 latch.countDown() . 在 CountDownLatch 内部的计数器同时自减。
- 主线程中使用 latch.await(); (暗中计算有几个countDown被调用了)阻塞等待所有任务执行完毕. 相当于计数器为 0 了。
public class Demo {public static void main(String[] args) throws Exception {CountDownLatch latch = new CountDownLatch(10);Runnable r = new Runable() {@Overridepublic void run() {try {Thread.sleep(Math.random() * 10000);latch.countDown();} catch (Exception e) {e.printStackTrace();}}};for (int i = 0; i < 10; i++) {new Thread(r).start();}// 必须等到 10 人全部回来latch.await();System.out.println("比赛结束");}
}
多线程对集合类的使用
常用的集合类:ArrayList,LinkedList,HashMap,PriorityQueue。。。线程是不安全的。
如果要使用怎么办?
1.可以手动对集合的修改操作加锁。(synchronized 或者 ReentrantLock)
2.使用java标准库提供的一些线程安全的版本的集合类。
多线程环境使用 顺序表
ArrayList可用,Vertor代替,但是vertor该有的方法都用synchronized,是很老的集合,实际场景并不适用。
1.Collections.synchronizedList(new ArrayList);
- synchronizedList 是标准库提供的一个基于 synchronized 进行线程同步的 List.
- synchronizedList 的关键操作上都带有 synchronized
2.使用 CopyOnWriteArrayList
CopyOnWrite容器即写时复制的容器。
- 当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy, 复制出一个新的容器,然后新的容器里添加元素,
- 添加完元素之后,再将原容器的引用指向新的容器。
这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会
添加任何元素。
所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。
优点:
- 在读多写少的场景下, 性能很高, 不需要加锁竞争.
缺点:
- 占用内存较多.
- 新写的数据不能被第一时间读取到.
多线程环境使用队列
- ArrayBlockingQueue 基于数组实现的阻塞队列
- LinkedBlockingQueue 基于链表实现的阻塞队列
- PriorityBlockingQueue 基于堆实现的带优先级的阻塞队列
- TransferQueue 最多只包含一个元素的阻塞队列
多线程使用队列:BlockingQueue
多线程环境使用哈希表
在多线程环境下使用哈希表可以使用:
- Hashtable
是线程安全的,给关键方法加上synchronized,颗粒度比较粗。它对整个哈市表加锁,任何的增删查操作,都会触发加锁,也就意味着会有锁竞争。其实没有必要,哈希表是有桶的,修改值是要通过key计算hash值,然后将新元素放到链表上。
两个线程对不同量进行修改,不会产生冲突,但是由于方法上加了锁也就意味着,两个线程同时使用一个方法会阻塞。(所以不建议)
- ConcurrentHashMap
线程是安全的,ConcurrentHashMap不是只有一把锁了,每个桶也就是链表的头结点作为一把,锁,这样针对不同的链表进行操作是不会产生的所冲突。大部分的加锁操作就没有锁冲突。
其他方面的改进:
更充分的利用了CAS机制--无锁编程
有些操作,比如获取或更新某个元素个数,就可以直接使用CAS完成,不必加锁
优化了扩容策略
对于hashTable来说,如果元素太多们就会涉及扩容,诺元素很多很多,上亿个,那么将原表大部分的元素搬到新的位置上,这个操作非常不流畅。所以呢ConcurrentHashMap,在此基础上,诺put触发扩容机制,就会一次性创建更大的内存空间,然后搬运一部分,此时就相当于存在两个hash表,此时对表操作,插入是对新表插入,删除是对旧表(看元素在那个表上)删除,查找是新旧表都查。(每一次操作。都会从旧表搬运一部分到新表)
Hashtable和HashMap、ConcurrentHashMap 之间的区别
- HashMap: 线程不安全. key 允许为 null
- Hashtable: 线程安全. 使用 synchronized 锁 Hashtable 对象, 效率较低. key 不允许为 null.
- ConcurrentHashMap: 线程安全. 使用 synchronized 锁每个链表头结点, 锁冲突概率低, 充分利用CAS 机制. 优化了扩容方式. key 不允许为 null
Java多线程是如何实现数据共享的?
- JVM 把内存分成了这几个区域:
- 方法区, 堆区, 栈区, 程序计数器.
- 其中堆区这个内存区域是多个线程之间共享的.
- 只要把某个数据放到堆内存中, 就可以让多个线程都能访问到。
Java创建线程池的接口是什么?参数 LinkedBlockingQueue 的作用是什么?
创建线程池主要有两种方式:
- 通过 Executors 工厂类创建. 创建方式比较简单, 但是定制能力有限.
- 通过 ThreadPoolExecutor 创建. 创建方式比较复杂, 但是定制能力强.
LinkedBlockingQueue 表示线程池的任务队列。 用户通过 submit / execute 向这个任务队列中添
加任务, 再由线程池中的工作线程来执行任务。
相关文章:

Java多线程(四)锁策略(CAS,死锁)和多线程对集合类的使用
锁策略(CAS,死锁)和多线程对集合类的使用 锁策略 1.乐观锁VS悲观锁 2.轻量级锁VS重量级锁 3.自旋锁VS挂起等待锁 4.互斥锁VS读写锁 5.可重入锁vs不可重入锁 死锁的第一种情况 死锁的第二种情况 死锁的第三种情况 CAS 1.实现原子类 …...

基于spring boot+ vue+ mysql开发的UWB室内外定位系统源码
现代制造业厂区面积大、人员数量多、物资设备不断增加,随着工业信息化技术的发展,大型制造企业中对人员、车辆、物资的管理要求越来越细致。 高精度定位管理系统使用UWB室内定位技术,通过在厂区安装定位基站,为人员或设备佩戴定位…...

第2章_瑞萨MCU零基础入门系列教程之面向过程与面向对象
本教程基于韦东山百问网出的 DShanMCU-RA6M5开发板 进行编写,需要的同学可以在这里获取: https://item.taobao.com/item.htm?id728461040949 配套资料获取:https://renesas-docs.100ask.net 瑞萨MCU零基础入门系列教程汇总: ht…...

数字图像处理:亮度对比度-几何变换-噪声处理
文章目录 数字图像增强亮度与对比度转换几何变换图像裁剪尺寸变换图像旋转 噪声处理添加噪声处理噪声 数字图像增强 亮度与对比度转换 图像变换可分为以下两种: 点算子:基于像素变换,在这一类图像变换中,仅仅根据输入像素值计算…...

maven报错:[ERROR] 不再支持源选项 7。请使用 8 或更高版本。
解决方案 pom.xml文件中增加maven编译的java.version jdk版本设置,以及maven.compiler.source 资源编译jdk版本设置和maven.compiler.target 资源构建jdk版本设置 JDK:6~8 一般都是1.6,1.7,1.8的写法。 <properties><…...

MySQL基础3-约束
MySQL基础3-约束 一. 约束概述1.1 概念1.2 目的1.3 分类 二. 约束演示三. 外键约束3.1 概念3.2 语法三. 删除/更新行为 一. 约束概述 1.1 概念 约束是作用于表中字段上的规则,用于限制存储在表中的数据 1.2 目的 保证数据库中数据的正确、有效性和完整…...

OJ练习第166题——课程表(拓扑排序问题)
课程表 力扣链接:207. 课程表 题目描述 你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。 在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] [ai, bi] ,表…...

单臂路由实现VLAN间路由
单臂路由实现VLAN间路由 单臂路由 概述拓扑图PC配置LSW2 接入层交换机LSW3 接入层交换机LSW1 汇聚层交换机R1 路由器ping 测试 单臂路由 概述 单臂路由的原理是通过一台路由器,使 VLAN 间互通数据通过路由器进行三层转发。 如果在路由器上为每个 VLAN 分配一个单独…...

【VSCode】文件模板创建及使用.md
背景 最近使用VSCode学习Vue项目比较频繁,每次创建Vue文件都要手动写重复代码,特别麻烦,就上网查找自动生成代码的说明,结果发现VSCode有代码模板,怪怪,感觉发现新大陆了(low!)。 配置 打开配置 方式一&a…...

【漏洞复现】EnjoySCM存在文件上传漏洞
漏洞描述 EnjoySCM是一款适应于零售企业的供应链管理软件,主要为零售企业的供应商提供服务。EnjoySCM的目的是通过信息技术,实现供应商和零售企业的快速、高效、准确的信息沟通、管理信息交流。。 该系统存在任意文件上传漏洞,攻击者通过漏洞可以获取服务器的敏感信息。 …...

MaPLe: Multi-modal Prompt Learning
本文也是LLM系统的文章,主要是面向多模态的大语言模型,针对《MaPLe: Multi-modal Prompt Learning》的翻译。 MaPLe:多模态提示学习 摘要1 引言2 相关工作3 方法4 实验5 结论 摘要 CLIP等预先训练的视觉语言(V-L)模型…...

软件测试/测试开发丨Jenkins Pipeline 学习笔记
点此获取更多相关资料 本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接:https://ceshiren.com/t/topic/26711 1. Jenkins节点 1.1 常用的节点 内建节点SSH节点Java Web节点 1.1.1 SSH节点配置 远程工作目录 节点中必须有该目录,用于下载和运行j…...

java多线程——线程池
线程池 线程池创建线程池关闭线程池使用获取多个结果 线程池 一个线程池中存在许多准备运行的空闲线程,把Runnable对象交给线程池,会有一个线程调用其run()方法,当调用完后线程不会死亡,而是在池中继续为下一次请求服务 利用线程…...

Linux文件操作
目录 复制文件、目录 cp 移动 重命名文件或目录 mv 创建删除文件 touch rm(remove) 创建删除目录 mkdir(make directory) rmdir(remove directory) 复制文件、目录 cp cp(copy) 同一个目录下复制,所以重命名了一下;把它复制到linuxcast.net/目录下可以…...

Tomcat多实例 + Tomcat负载均衡、动静分离(Nginx联动)
多实例联动 一、Tomcat 多实例1.1 什么是Tomcat多实例?1.2 配置思路1.3 配置实现1.3.1 安装jdk1.3.2 安装tomcat1.3.3 配置 tomcat 环境变量1.3.4 修改端口号1.3.5 修改各 tomcat 实例中的 startup.sh 和 shutdown.sh 文件,添加 tomcat 环境变量1.3.6 启…...

bootstrap和application的区别
SpringBoot项目的配置文件支持两种四个: bootstrap和application。 YML文件两个:bootstrap.yml,application.yml 属性文件两个:bootstrap.properties,application.properties 配置文件优先级 SpringBoot支持同时使用…...

【狂神】SpringMVC笔记(一)之详细版
1.Restful 风格 概念: 实现方式: 使用PathVariable 在url相同的情况下,会根据请求方式的不同来执行不同的方法。 使用RestFull风格的好处:简洁、高效、安全 2、接受请求参数及数据回显 2.1、请求参数 方式一:这里…...

vue 对axios进行封装
token配置、中英文配置、对所有接口统一设置防抖、对所有post接口统一设置节流 废话少说直接上代码 request.js import axios from axios // 使用element-ui Message做消息提醒 import { ElMessage } from element-plus//这是为了防止刁民反复切换页面,切换页面…...

第十二章 YOLO的部署实战篇(下篇-cuda)
cuda教程目录 第一章 指针篇 第二章 CUDA原理篇 第三章 CUDA编译器环境配置篇 第四章 kernel函数基础篇 第五章 kernel索引(index)篇 第六章 kenel矩阵计算实战篇 第七章 kenel实战强化篇 第八章 CUDA内存应用与性能优化篇 第九章 CUDA原子(atomic)实战篇 第十章 CUDA流(strea…...

原生JavaScript+PHP多图上传实现
摘要 很多场景下需要选择多张图片上传,或者是批量上传以提高效率,多图上传的需求自然就比较多了,本文使用最简单的XMLHttpRequest异步上传图片。 界面 上传示例 代码 index.html <!DOCTYPE html> <html><head><titl…...

企业架构LNMP学习笔记30
1、upstream 中server的关键字:语法: upstream中的分发之后的几个关键字: 1)backup 备 其他的没有backup标识的都不可用了,才分发到backup; 2)down 此条配置,不会被分发到。 syst…...

数学建模算法汇总(全网最全,含matlab案例代码)
数学建模常用的算法分类 全国大学生数学建模竞赛中,常见的算法模型有以下30种: 最小二乘法数值分析方法图论算法线性规划整数规划动态规划贪心算法分支定界法蒙特卡洛方法随机游走算法遗传算法粒子群算法神经网络算法人工智能算法模糊数学时间序列分析马…...

openpnp - 底部相机高级矫正后,底部相机看不清吸嘴的解决方法
文章目录 openpnp - 底部相机高级矫正后,底部相机看不清吸嘴的解决方法概述解决思路备注补充 - 新问题 - N1吸嘴到底部相机十字中心的位置差了很多END openpnp - 底部相机高级矫正后,底部相机看不清吸嘴的解决方法 概述 自从用openpnp后, 无论版本(dev/test), 都发现一个大概…...

怎么提高自己当众讲话的能力?
当众讲话是一项重要的沟通技能,它可以帮助你在各种场合中表达自己的观点、影响他人,并建立自信。虽然对很多人来说,当众讲话可能是一项挑战,但通过一些实践和技巧,你可以提高自己的当众讲话能力。下面是一些方法&#…...

孙哥Spring源码第20集
第20集 refresh()-invokeBeanFactoryPostProcessor 四-处理Configuration下的Bean生成代理对象 【视频来源于:B站up主孙帅suns Spring源码视频】【微信号:suns45】 1、二行InvokeBeanFactoryPostProcessors的作用 registryProcessors:处理的…...

【计算机网络】HTTP(上)
文章目录 1.HTTP概念2. URLurlencode 和 urldecode转义规则 3. HTTP的宏观理解HTTP的请求HTTP的响应 4. 见一见HTTP请求和响应请求报头 1. 模拟一个简单的响应response响应报头 2. 从路径中获取内容ReadFile函数的实现 3.不同资源进行区分反序列化的实现ReadOneLine函数的实现P…...

Maven学习记录
一、Maven是什么 简单来说Maven是一个标准化的java管理和构建工具,它提供了一系列规范,包括项目结构,构建流程(编译,测试,打包,发布……),依赖管理等。 标准化就是定下…...

H5游戏开发H5休闲小游戏定制H5软件定制
H5游戏是一种运行在网页浏览器中的HTML5技术开发的游戏。H5休闲小游戏通常具有简单的玩法,易于上手,适合快速的娱乐。以下是开发H5休闲小游戏的一般步骤: 1. 制定游戏开发概念: 确定H5游戏开发的主题和玩法。休闲小游戏通常应该…...

Spring基础及IoC容器的理解
Spring概念: 通常所说的Spring指的是Spring Framewprk(Spring框架),它是一个开源的框架。用一句话概括就是:Spring是包含了众多工具方法的IoC容器。 什么是容器? 容器是用来容纳某种物品的装置,在之前的学习中&…...

护网行动为什么给的钱那么多
因为护网行动是国家应对网络安全问题所做的重要布局之一。 随着大数据、物联网、云计算的快速发展,愈演愈烈的网络攻击已经成为国家安全的新挑战。国家关键信息基础设施可能时刻受到来自网络攻击的威胁。网络安全的态势之严峻,迫切需要我们在网络安全领…...