途虎一面
-
令牌桶算法
流量控制算法
什么是令牌桶算法?工作原理是什么?使用它有哪些优点和注意事项?_什么是令牌桶算法?工作原理是什么?使用它有哪些优点和注意事项?-CSDN博客
扩展:
四种常见的限流算法
-
静态方法和非静态方法变量,对象在jvm内存分布情况
变量:
- 局部变量
- 成员变量
- 静态变量
- 实例变量
-
开发中常见的设计模式有哪些?
-
工厂模式
-
代理模式
-
观察者模式
-
单例模式
重复实例化对象,只创建唯一个实例对象。在多线程并发情况下 单例失效的解决措施
(1)饿汉式(私有化构造方法)
(2)双重检查锁定(两次判断对象是否为空,第二次采用synchronized进行同步代码)
追问:为什么需要两次检查呢?
当然是为了解决多线程并发带来的多次实例对象的情况。举个例子:
线程 A 调用
getInstance(),发现instance为null,于是进入同步块。线程 B 也几乎同时调用
getInstance(),也发现instance为null,然后等待线程 A 释放锁。线程 A 在同步块内创建了
instance并释放锁。线程 B 获得锁后,如果没有第二次检查,它会继续在同步块内创建另一个
instance,从而违反单例模式的初衷。▼java复制代码public class Singleton { private static volatile Singleton instance; private Singleton() { // 初始化代码 } public static Singleton getInstance() { if (instance == null) { // 第一次检查 synchronized (Singleton.class) { instance = new Singleton(); // 创建实例 } } return instance; } }-
策略模式
-
装饰模式
如何理解这6种常见设计模式?-阿里云开发者社区 (aliyun.com)
详细讲讲什么是观察者模式?观察者模式_观察者模式 循环依赖-CSDN博客
观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。
(抽象)被观察者内部维护了一个集合,用来记录存储有哪些观察者!同时有通用的订阅、删除、通知、获取状态的方法,具体的被观察者会继承(抽象)被观察者。创建抽象的观察者,内部应用抽象的被观察者,还有一个抽象的更新状态方法。
场景:应用于一对多的依赖关系的场景,例如:关注微博大v,他发微博,他的粉丝都能发现(消费)的动态!
优点:被观察者和观察者是抽象耦合的(即:易于扩展、灵活的组件)
缺点:可能会导致被观察者和观察者
循环依赖。(当被观察者之间存在关联时,容易出现循环依赖) -
-
volatile你有用过么?他有什么作用?使用场景有哪些?
volatile 关键字是 Java 提供的一种
轻量级的同步机制,可以保证变量的内存可见性和禁止指令重排序。volatile 不会造成上下文切换的开销,但是他并不能像 synchronized 那样保证所有场景下线程安全。使用场景:单例模式中的双重检查(在编译器和处理器会进行指令重排的情况)和多线程状态标记量
适用volatile的两个特点:(1)对变量的写操作不依赖于当前值(比如:**i++**操作,他是需要依赖i的原本值,才进行叠加的!因此不适合在多线程并发的的情况下 使用关键字volatile)(2)被修饰volatile修饰的变量不同与其他变量共同维护一种关系(大小关系)
▼java复制代码public class Range { private volatile int start; private volatile int end; public void setRange(int start, int end) { this.start = start; this.end = end; } public boolean isWithinRange(int value) { return value >= start && value <= end; } }在这个例子中:
start和end都被声明为volatile,确保了它们的可见性。- 然而,
start和end共同维护一个不变式:start <= end。
如果一个线程调用
setRange方法来更新start和end,另一个线程可能会在start更新后、end更新前读取它们,导致isWithinRange方法返回不一致的结果(例如start已增加,但end还未更新,可能导致逻辑错误)。 -
Mybatis 是如何应对 SQL 注入呢?
- 通过占位符 # 进行参数绑定
- 动态 SQL 生成标签(比如:用 foreach 标签解决 in 后面多个参数绑定,如果用字符串拼接,就容易发生SQL注入)
-
ConcureentHashMap 和 HashTable的区别是什么?
-
HashTable是一个线程安全的类,它使用
synchronized来锁住整张Hash表来实现线程安全,即每次锁住整张表让线程独占,相当于所有线程进行读写时都去竞争一把锁,导致效率非常低下。 -
ConcurrentHashMap可以做到读取数据不加锁,并且其内部的结构可以让其在进行写操作的时候能够将锁的粒度保持地尽量地小,允许多个修改操作并发进行,其关键在于使用了锁分段技术。
追问:ConcurrentHashMap的缺点是什么呢?
读取的数据不能保证是获取的最近更新的内容。
追问:ConcurrentHashMap 1.7 和 1.8 的区别是什么
1.7版本中 ConcurrentHashMap 采用的分段锁(Segement)的概念,每个Segement(内部维护了小HashMap)里面有多个HashEntry,通过两次 Hash算出存放具体的 HashEntry 的位置,同时用Synchronized将要更新的Segement进行锁定。默认初始化ConcureentHashMap 是有16个 Segement,即支持并发 16 个线程。
1.8版本中 ConcureentHashMap 是进一步缩小锁的粒度,即每个 HashEntry (Node) 就有一把锁。
PS: ConcureentHashMap在新增节点会采用
cas方法,如果下标已有数据,那么我们会采用Synchronized行锁定。思考:为什么为空时使用CAS,不为空时使用 synchronized 呢? 对于复杂的更新操作,需要线程耗费时间较长,不适合采用 cas方法,使得线程自旋时间长,占用 cpu 资源,降低 cpu的运行效率!
-
