Administrator
发布于 2023-04-16 / 8 阅读
0
0

随笔-6

nginx主要作用

  • 静态代理
  • 负载均衡,请求。常用策略有轮询、权重、随机、ip_hash、least_conn等
  • 限流 基础漏桶算法
  • 缓存 浏览器缓存和代理层缓存
  • 黑白名单 不限流白名单和黑名单

禁用e.printStackTrace()

短时间内大量请求访问此接口 -> 代码本身有问题,很多情况下抛异常 -> e.printStackTrace() 来打印异常到控制台 -> 产生错误堆栈字符串到字符串池内存空间 -> 此内存空间一下子被占满了 -> 开始在此内存空间产出字符串的线程还没完全生产完整,就没空间了 -> 大量线程产出字符串产出到一半,等在这儿(等有内存了继续搞啊)-> 相互等待,等内存,锁死了,整个应用挂掉了。

记住,不要使用 e.printStackTrace()!而且会产生大量字符串的方法,使用时都要注意,因为字符串池所属的非堆内存空间就那么点,小心占满了。

分布式session实现方案

  • 使用jwt替代session,从数据库或缓存获取其它信息
  • tomcat+redis 利用TomcatRedisSessionManager,使tomcat 都将 session 数据存储到 redis
  • spring session + redis  session交给spring托管,从redis获取数据

乐观锁和悲观锁

乐观锁:乐观锁在操作数据时非常乐观,认为别人不会同时修改数据。因此乐观锁不会上锁,只是在执行更新的时候判断一下在此期间别人是否修改了数据:如果别人修改了数据则放弃操作,否则执行操作。

悲观锁:悲观锁在操作数据时比较悲观,认为别人会同时修改数据。因此操作数据时直接把数据锁住,直到操作完成后才会释放锁;上锁期间其他人不能修改数据。如synchronized、lock锁等

乐观锁主要有版本号和CAS两种实现方式。

CAS操作包括了3个操作数:

  • 需要读写的内存位置(V)

  • 进行比较的预期值(A)

  • 拟写入的新值(B)

CAS操作逻辑如下:如果内存位置V的值等于预期的A值,则将该位置更新为新值B,否则不进行任何操作。许多CAS的操作是自旋的:如果操作不成功,会一直重试,直到操作成功为止。CAS是由CPU支持的原子操作,其原子性是在硬件层面进行保证的。

CAS可能有ABA问题,一般需要引入版本号。java.util.concurrent.atomic包提供的原子类就是基于CAS实现的。

版本号机制的话会在更新时会携带版本号与当前数据版本做对比。

当竞争不激烈 (出现并发冲突的概率小)时,乐观锁更有优势,因为悲观锁会锁住代码块或数据,其他线程无法同时访问,影响并发,而且加锁和释放锁都需要消耗额外的资源。

当竞争激烈(出现并发冲突的概率大)时,悲观锁更有优势,因为乐观锁在执行更新时频繁失败,需要不断重试,浪费CPU资源。

ConcurrentHashMap理解

  • 在1.8中ConcurrentHashMap的get操作全程不需要加锁,这也是它比其他并发集合比如hashtable、用Collections.synchronizedMap()包装的hashmap安全效率高的原因之一。

  • get操作全程不需要加锁是因为Node的成员val是用volatile修饰的,和数组用volatile修饰没有关系。

  • 数组用volatile修饰主要是保证在数组扩容的时候保证可见性。


评论