因为 Java 语言既具有编译型语言的特征,也具有解释型语言的特征。由 Java 编写的程序需要 先经过编译步骤,生成.class 文件,这个文件必须由 Java 解释器来解释执行。
JIT 完成一次编译后会将字源码对应的机器码保存起来
在程序执行前将其编译为机器码
前端从后端接收JWT之后存储在本地存储中 local strong session stgorge 之后请求的时候 将JWT放入HTTP Header中的Authorization位
简单 高效 跨平台 支持多线程
类 单继承 c++ 支持多继承 不提供指针访问内存 自动垃圾回收
<< :左移运算符,向左移若干位,高位丢弃,低位补零。x << 1,相当于 x 乘以 2(不溢出的情况下)。
>> :带符号右移,向右移若干位,高位补符号位,低位丢弃。正数高位补 0,负数高位补 1。x >> 1,相当于 x 除以 2。
>>> :无符号右移,忽略符号位,空位都以 0 补齐。
由于 double,float 在二进制中的表现比较特殊,因此不能来进行移位操作。
取余 之后再...
6 种数字类型:
4 种整数型:byte、short、int、long 1 2 4 8
2 种浮点型:float、double 4 8
1 种字符类型:char 1 1 种布尔型:boolean。1b
泛型 对象在堆中 基本 栈的局部变量表 占用高内存小
Java 基本数据类型的包装类型的大部分都用到了缓存机制来提升性能。 Byte,Short,Integer,Long 这 4 种包装类默认创建了数值 [-128,127] 的相应类型的缓存数据, Character 创建了数值在 [0,127] 范围的缓存数据, Boolean 直接返回 True or False。Integer
如果超出对应范围仍然会去创建新的对象,缓存的范围区间的大小只是在性能和资源之间的权衡。 两种浮点数类型的包装类 Float,Double 并没有实现缓存机制。
装箱: 将基本类型用它们对应的引用类型包装起来; 拆箱: 将包装类型转换为基本数据类型;
装箱其实就是调用了 包装类的 valueOf() 方法,拆箱其实就是调用了 xxxValue() 方法。
Integer i = 10 等价于 Integer i = Integer.valueOf(10)
int n = i 等价于 int n = i.intValue()
计算机在表示一个数字时,宽度是有限的,无限循环的小数存储在计算机时,只能被截断,所以就会导致小数精度发生损失的情况。
可以直接使用 BigDecimal 来定义浮点数的值,然后再进行浮点数的运算操作即可。
可以被访问控制修饰符所修饰 局部变量不能被访问控制修饰符以及static修饰 但是都可以被final修饰 成员变量是属于类的 局部变量 是属于实例的 成员变量是对象的一部分,它随着对象的创建而存在, 而局部变量随着方法的调用而生成,随着方法的调用结束而消亡。 从变量是否有默认值来看,成员变量如果没有被赋初始值,则会自动以类型的默认值而赋值(一种情况例外:被 final 修饰的成员变量也必须显式地赋值),而局部变量则不会自动赋值。
先不考虑变量类型,如果没有默认值会怎样?变量存储的是内存地址对应的任意随机值,程序读取该值运行会出现意外
静态变量也就是被 static 关键字修饰的变量 静态变量是通过类名来访问的,例如StaticVariableExample.staticVar(如果被 private关键字修饰就无法这样访问了)。 通常情况下,静态变量会被 final 关键字修饰成为常量。
静态方法是属于类的, 非静态成员属于实例对象 非静态成员 不存在的时候,静态方法已经存在了
调用静态方法可以无需创建对象 静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),不允许访问实例成员(即实例成员变量和实例方法),而实例方法不存在这个限制。
重载就是同样方法的参数个数和类型不同, 可以进行不通过的操作 重写就是当子类重写父类的方法
Java 的可变参数编译后实际会被转换成一个数组
public static void printVariable(String... args) {
for (String s : args) {
System.out.println(s);
}
}
遇到方法重载的情况怎么办呢? 答案是会优先匹配固定参数的方法,因为固定参数的方法匹配度更高。
一个对象引用可以指向 0 个或 1 个对象(一根绳子可以不系气球,也可以系一个气球); 一个对象可以有 n 个引用指向它(可以用 n 条绳子系住一个气球)。
对象的相等一般比较的是内存中存放的内容是否相等。 引用相等一般比较的是他们指向的内存地址是否相等。
会有默认的不带参数的构造方法。
名字和类名字相同 没有返回值 生成对象的时候自动执行
构造方法不能被 override(重写),但是可以 overload(重载),所以你可以看到一个类中有多个构造函数的情况。
封装 将属性和方法包装起来
继承 它允许一个类(称为子类或派生类)继承另一个类(称为父类或基类)的属性和方法。通过继承,子类可以重用父类的代码,并且可以在不修改父类的情况下添加新的功能或修改已有的行为。
多态 //TODO
都不能被实例化。 都可以包含抽象方法。 一个类只能继承一个类,但是可以实现多个接口。
接口主要用于对类的行为进行约束,你实现了某个接口就具有了对应的行为。 抽象类主要用于代码复用,强调的是所属关系。 一个类只能继承一个类,但是可以实现多个接口。
都可以只有默认的实现方法 default
接口中的成员变量只能是 public static final 类型的,不能被修改且必须有初始值,而抽象类的成员变量默认 default,可在子类中被重新定义,也可被重新赋值。
浅拷贝 会拷贝此对象但是不会拷贝其内部的引用对象 深拷贝 深拷贝会完全复制整个对象, 包括这个对象所包含的内部对象。
实现深拷贝 重写clone方法
equal方法存在于 Object类中,用于判断对象相等, 默认的实现是== 一般我们会重写这个方法
hashcode的作用是对利用到hash 的数据结构, 加速查找元素
hshcode 判断相等后, 不一定相等, 因为存在hash冲突. 但是hashcode可以判断不等 在使用hash 的容器中, 使用hashcode可以提高效率
StringBuilder 与 StringBuffer 都继承自 AbstractStringBuilder 类
在 AbstractStringBuilder 中也是使用字符数组保存字符串,不过没有使用 final 和 private 关键字修饰
AbstractStringBuilder 是 StringBuilder 与 StringBuffer 的公共父类,定义了一些字符串的基本操作,如 expandCapacity、append、insert、indexOf 等公共方法
String 中的对象是不可变的,也就可以理解为常量,线程安全。 StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。 StringBuffer 对方法加了锁,所以是线程安全的。
String 操作少量的数据 StringBuilder 单线程操作字符串缓冲区下操作大量数据 StringBuffer 多线程操作字符串缓冲区下操作大量数据
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
private final char value[];
//...
}
保存字符串的数组被 final 修饰且为私有的, 并且String 类没有提供/暴露修改这个字符串的方法。
在某些编码方式下会生内存
底层 StringBuilder
调用 append()
方法实现
String继承自object, 因而他们都有 object 类.
String 中的 equals 方法是被重写过的,比较的是 String 字符串的值是否相等。
JVM 为了提升性能和减少内存消耗针对字符串(String 类)专门开辟的一块区域,主要目的是为了避免字符串的重复创建。
String.intern() 是一个 native(本地)方法,其作用是将指定的字符串对象的引用保存在字符串常量池中,可以简单分为两种情况:
Exception : 程序本身可以处理的异常,可以通过 catch 来进行捕获。Exception 又可以分为 Checked Exception (受检查异常,必须处理) 和 Unchecked Exception (不受检查异常,可以不处理)。 Error: Error 属于程序无法处理的错误. 例如 Java 虚拟机运行错误(Virtual MachineError)、虚拟机内存不够错误(OutOfMemoryError)、类定义错误(NoClassDefFoundError)等 。这些异常发生时,Java 虚拟机(JVM)一般会选择线程终止
Checked Exception 即 受检查异常 ,Java 代码在编译过程中,如果受检查异常没有被 catch或者throws 关键字处理的话,就没办法通过编译。
除了RuntimeException及其子类以外,其他的Exception类及其子类都属于受检查异常 。常见的受检查异常有:IO 相关的异常、ClassNotFoundException、SQLException...。
Unchecked Exception 即 不受检查异常 ,Java 代码在编译过程中 ,我们即使不处理不受检查异常也可以正常通过编译。
RuntimeException 及其子类都统称为非受检查异常,常见的有(建议记下来,日常开发中会经常用到):NullPointerException(空指针错误)IllegalArgumentException(参数错误比如方法入参类型错误)NumberFormatException(字符串转换为数字格式错误,IllegalArgumentException的子类)ArrayIndexOutOfBoundsException(数组越界错误)ClassCastException(类型转换错误)ArithmeticException(算术错误)SecurityException (安全错误比如权限不够)UnsupportedOperationException(不支持的操作错误比如重复创建同一用户)
会执行
不一定 比如在finally之前 程序所在的线程死亡,虚拟机关闭,cpu关闭
try (Scanner scanner = new Scanner(new File("test.txt"))) {
while (scanner.hasNext()) {
System.out.println(scanner.nextLine());
}
} catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
}
是一种接口提供方式, 调用方提供好接口, 服务端去实现
将数据结构转化为二进制字节流 用于传输 存储等 应用层
transient声明的关键字不会被实例化 ,比如密码 private transient String password; // 使用 transient 修饰
Hessian、Kryo、Protobuf、ProtoStuff, 这些都是基于二进制的序列化协议。 JSON 和 XML 这种属于文本类序列化方式。可读性比较好,性能较差
不支持跨语言调用 性能差 存在安全问题:
的 40 多个类都是从如下 4 个抽象类基类中派生出来的。 InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。 OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。
不管是磁盘还是网络传输,最小的存储单元都是字节 但是 在程序中操作的通常是字符形式的数据,因此需要提供对字符进行操作的方法。
引用数据类型
类
接口
数组
枚举
private 仅类内部 defalut 包内
子类继承父类的成员时,可以访问父类中具有default访问权限的成员,但前提是子类和父类必须在同一个包内。如果子类和父类不在同一个包内,子类是无法访问父类中使用默认访问权限修饰的成员的
protected 包内 和 子类
允许子类(无论是否在同一包内)访问被修饰的成员。而default访问修饰符则只能被同一包内的类访问。
public 所有类都可访问 越来越放松
静态代码块->构造代码块->构造方法
子类重写父类的方法的时候,权限不可以比父类的更加严格 子类的对象无法直接访问父类的方法,因而提供了super关键字
使用super调用父类指定构造方法 super(x,x)
如果父类的成员不希望被子类重写,可以用final关键字
static 修饰的 只分配一次内存 通过类名访问,无需创建对象
类名方法调用 不需要创建对象 只可访问静态成员变量
两个完全不同的概念 继承类或者实现接口 重写方法 类中的方法,参数 类型,个数,顺序,返回值 不同, 称为重载
存在于类中 名字与类名相同 没有返回值 创建对象时自动调用 不可以被重写,可以被重载
继承 多态 封装
拥有同父类的属性和方法 一个对象有多个不同的状态,主要表现在 继承 重写 上 主要表现为,将对象的属性和方法封装在一起
浅拷贝继承Cloneable 直接用默认的.clone() 方法 深拷贝继承Cloneale 之后重写clone方法,拷贝内部对象,注意内部对象也需要继承Cloneable方法
getClass wait notify notifyall hashCode equal toString Clone
对于基本类型,== 判断两个值是否相等,基本类型没有 equals 方法 对于引用类型,== 判断两个变量是否引用同一个对象,而 equals() 判断值是否相等 我们可以重写 equal 方法达到我们想要的效果
抽象类不可以被实例化 只能继承 抽象类中含有抽象方法 抽象类被 abstract 修饰
是指在运行时操作 类、接口、属性和方法
反射提高了程序的可拓展性 但是带来了额外的开销 并且不安全
变量 不可被修改 方法 不可贝重写 类 不可被继承
已存在的会引用,而不是创建新的对象 .intern(),本地方法,用于将指定的存储到字符串常量池中
Throwable Exception Error Exception CheckedException UncheckException Error
Exception 程序可以处理的异常 Error 程序无法处理的异常 JVM错误 内存不足
在java代码中接受异常检查,如果代码没有被try throw 修饰,则会报错 除了 RuntimeException 其他都是Checked
提高了代码的复用性 编译器可以对参数进行检测 可以增强代码的可读性稳定性
允许在定义类、接口和方法时使用类型参数
Spring中 简化配置 注解 动态特性
用于修饰类方法变量 通过反射机制 简化代码加速开发
都是从以下类派生出来的 InputStream Reader OutPutStream Writer
字符流耗时间 字节流有时候会存在编码问题
实参 形参(函数括号内的)
java中仅有值 java中引用数据类型传递的是值,这个值是地址
推荐使用kryo
Object.class Class.forName"cn.javaguid.Main" .getClass 类加载器传入路径
静态代理 动态代理
是java中的一个类, 主要提供本地方法, 用于一些高性能的数据结构, 但是使用不当会造成内存泄漏
Collection Set List Queue Map
Set HashSet SortedSet HashSet LinkedHashSet SortedSet TreeSet
List ArrayList Vector ArraryList LinkedList Vector Stack
Queue ProriQueue Dequeu
Map HashMap HashTable SortedMap HashMap linkedHashMap SortedMap TreeMap
List 有序可重复 Set 不可重复 Queue 有序 Map 键值对
List ArrayList Object[] Vector Object[] LinkedList 1.6 循环链表 1.7 取消了循环
Set HashSet 无序唯一 TreeSet 有序唯一
Queue ProriQUeue Object[] 实现小顶堆 DelayQueue
Map HashMap 数组+链表 -> 数组+链表+红黑树 表长>8 数组>64
LinkedHashMap 继承HashMap 加入了双向链表,可以保证键值对的插入顺序
HashTable 数组+链表 线程安全
TreeMap 红黑树(一种排序二叉树)
需要排序的时候 TreeMap 不需要排序 HashMap 保证线程安全 CocurrentHashMap
简化操作 规范操作
动态扩容 泛型 只能存储对象 可以存储任何类型 创建时无需指定大小 需要指定大小
Vector 线程安全 Stack 线程安全 都是有synchornized修饰
头 尾 指定位置 n 1 n 1 1 n
一般不使用LinkedList
链表不是连续的存储空间,不能实现随机访问
A compareTo B compare A B
出队顺序和优先级有关 二叉堆 O(logN) 插入 删除 非线程安全 默认小顶堆
如果队列满了,一直等到队列可以放入新的元素的时候放入
extend AbstractList implemlent list Ramdomaccess cloneable Serializable 可以null值 null值无意义
都不是线程安全 Arraylist LinkedList 内存占用 是否支持随机访问 数据结构 数组 双向链表
1.7 Segment的组合16个 可以理解为最多支持16个并发 1.8 Node数组 链表+红黑树
进程是程序的一次执行过程 包含多个线程 线程是比进程更小的执行单位
线程共享 堆和本地方法区 线程独立的有 程序计数器 虚拟机栈 本地方法栈
在Windows linux中采用1对1的线程模型
记录执行到哪里了,方便中断之后恢复
为虚拟机提供服务
为native方法提供服务
new Thread().start()
实现方式有 继承 Thread 实现 Runnable 实现 Callable 使用线程池
6 new 初始状态 还没有被start调用 runnable 运行状态 被调用了start blocked 阻塞状态 需要等待锁释放 waiting 等待状态 需要等待其他线程做出一些指定的动作 time-wating 超时等待状态 在指定的事件后自行返回而不是像waiting一直等待 terminated 终止状态
线程切换需要进行上下文切换 让出cpu的使用权
sleep 没有释放锁, 而 wait 释放了锁 为何wait 不定义咋Thread中 释放锁操作的对象是Object 而非线程 为何sleep不定义在Object中 让当前进程等待,不涉及到对象
run不会当作多线程执行 start会
并发 在同一时间段执行 并行 在同一时刻运行
同步需要等待返回结果 异步不需要
现在计算机大多都是多线程的,充分利用计算机资源 减少了线程上下文切换带来的开销 当今互联网对并发要求很高
死锁 线程不安全 内存泄漏
对于同一份数据,不管多少线程同时访问,都可以保证这一份数据的一致性和正确性 混乱 错误 丢失
cpu密集型 多线程开销大,不一定 IO密集型 一般会提高效率
两个或多个进程因争夺资源而相互等待
宏观 互斥条件 循环等待 第一个 第二个 请求与保持条件 不剥夺条件
互斥条件 一个资源某一时刻只有一个线程可以占用 请求与保持条件 因请求资源阻塞时,不释放资源 不剥夺条件 线程获得的资源不可被剥夺 循环等待条件 形成一种头尾项链的循环等待资源
jconsloe JDK bin目录下
破坏请求保持条件 一次性获取所有资源 破坏不剥夺条件 申请不到则主动释放 循环等待条件 按照某一顺序申请资源,某一顺序释放资源
java内存模型
用来告诉编译器这个变量可能会在程序的控制之外发生改变,因此编译器不能对其进行优化。这样可以确保每次访问该变量时都会从内存中重新读取,而不是使用缓存值。
如何保证变量的可见性 每次使用都要到主存中读取 不可以保证原子性
volatile 关键字
bei 假设每次都出问题,所以每次操作之前都加锁
le 假设每次都没问题,先直接操作,提交的时候再做验证
bei 写比教多的场景 竞争激烈 le 写少的场景 竞争少
方法 代码块
volatile 是轻量的 synchronized 是重量级的 volatile 解决变量在多个线程之间的可见性, synchronized 解决多个线程之间访问资源的问题 volatile 修饰变量 synchronized 修饰方法和代码块
可重入锁 可以获得自己内部的锁 避免死锁
先申请的先获得锁 随机获取锁
都是可重入锁
synchronized 非公平锁 reentantlock 可以是公平锁也可以是非公所suo reen等待可中断
Java 中synchronized
和ReentrantLock
等独占锁就是悲观锁
public void performSynchronisedTask() {
synchronized (this) {
// 需要同步的操作
}
}
private Lock lock = new ReentrantLock();
lock.lock();
try {
// 需要同步的操作
} finally {
lock.unlock();
}
乐观锁java中没有提供,一般需要手动实现
一个锁可以被多个线程获取 一个锁只可以被一个线程获得
不可以 如果发现写锁被占用, 直接获取失败 但是持有写锁可以获取读锁
性能好 乐观锁
我们创建的 变量 是可以被任何一个 线程 访问修改的 但是每个线程都有一块仅自己访问的空间 TheadLocal
所有的线程创建的实例对象都放在主内存中 每个线程都有自己私有的本地内存, 存储了该线程以读/写共享变量的副本
有任务需要处理的时候,直接向线程池中获取线程来处理,处理完之后并不会被直接销毁,而是等待下一个任务
降低资源消耗 重复利用线程而不需要 销毁和创建 提高响应速度 提高线程的可管理性 避免过多的或者过少创建线程
ThreadPoolExecutor 构造函数来创建 Executors 不推荐
使用第一个 显式的写明过期时间等等参数,避免资源耗尽
使用execute()时,未捕获异常导致线程终止,线程池创建新线程替代;使用submit()时,异常被封装在Future中,线程继续复用。
使用一个优先阻塞队列
主要用在一些需要执行耗时任务的场景,避免程序一直原地等待耗时任务执行完成
1取消任务; 2判断任务是否被取消; 3判断任务是否已经执行完成; 4获取任务执行结果。
编译器优化 并行指令重排 现代处理器,如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序
两个线程如果通信的话,需要经历 线程1 把本地内存中修改的共享变量副本的值同步到主内存中去. 线程2到主内存中读取对应的共享变量的值
定义了共享内存中 多线程 读写变量的规范 从而保证指令的正确性 jmm 把内存区域分成两块 一个是主内存 一个是线程的私有内存 线程只是操作私有内存 私有内存和主内存可以同步
compare and swap 一种乐观锁的思想 在无锁的情况下实现线程安全
while 体现了自旋
while(true){
int oldData=mainMemory
//operation
if(compareAndSwap){
//成功
break;
失败不退出
}
}
保证线程间的可见性
当一个线程对这个变量进行操作的时候, 都胡从主内存中获取新的值
防止指令重排序
防止编译器优化 使多线程按照正确的流程访问变量
不是 所以如果该处理逻辑中 有对该单列状态的修改(体现为该单例的成员属性),则必须考虑线程同步问题 是单例吗 是
抽取公共模块复用,降低耦合,减少代码的修改 为公共日志保存, 事务处理等
spring实现的事务本质就是 AOP 完成, 对方法前后进行拦截,在执行方法之前开启事务,在执行完目标方法之后根据执行情况提交或者回滚事务
一共三个 捕获了异常但是没有抛出 抛出的异常类型不对 需要配置 @Transactional 方法上不是public修饰的,也会导致事务失效
BeanDefinition 类 获取bean的定义信息 这里面就封装了bean的所有信息 比如 类的全路径 是否是延迟加载 是否是单例等等这些信息 创建bean 调用构造函数实例化bean bean的依赖注入,比如一些set方法注入 @Autowire在这一步完成 是处理Aware接口,如果某一个bean实现了Aware接口就会重写方法执行 是bean的后置处理器BeanPostProcessor 初始化方法,比如实现了接口InitializingBean或者自定义了方法init-method标签或@PostContruct
第六步是执行了bean的后置处理器BeanPostProcessor,主要是对bean进行增强,有可能在这里产生代理对象
最后一步是销毁bean
循环依赖 循环引用指的是 两个或两个以上的 bean 互相依赖对方 形成了闭环 在spring中 允许存在 spring使用三级缓存 解决了大部分循环引用问题
由于bean的生命周期中构造函数是第一个执行的因此 spring框架不能解决 构造函数依赖注入的问题 可以使用 @Lazy 懒加载
单例池 初始化完成的bean对象 早期的bean对象 生命周期还没有走完 工厂对象 缓存的工厂 用来创建对象
@SpringBootApplication 对三个注解进行了封装
@SpringBootConfiguration 和 Configuration 相同 声明为配置类 @EnableAutoConfiguration 核心 @ComponentScan 包扫描
@EnableAutoConfiguration
该注解通过@Import
注解导入对应的配置选择器 读取了配置的类的全类名
在这些配置类所定义的Bean会判断是否有对应的class文件,如果有则加载该类
实例化 bean @Controller @Component @Service @Repository
@Atuowired Spring @Resource java 类型 名称 @Qualifier 用于指定具体的依赖对象的名称 @Scope 标注bean的范围(单例多例)
@Configuration @ComponentScan @bean 方法的返回值储存到Spring容器 @Import 导入的类会放到Spring容器中 @Aspect @Before @After @Around @Pointcut AOP
@RequestMapping @RequestBody @RequestParam @PathViriable @ResponseBody @RequestHeader @PostMapping、@GetMapping @RestController
@SpringBootApplication 包括 @SpringBootConfiguration Configration @EnableAutoConfiguration 自动配置 @ComponentScan 包扫描
读取xml配置文件 创建工厂 创建会话 使用执行器操作数据库 并且进行输入输出映射
支持
在用到数据的时候查询 用不到的时候不查询 可以在Mapper的xml中配置延迟加载 默认是关闭的
使用代理对象完成的 使用拦截器
一级缓存: 底层是 HashMap 本地缓存 其存储作用域为 Session Session销毁后会清空数据 默认是开启的 二级缓存是基于namespace和mapper的作用域起作用的 默认关闭
某一个作用域进行了增改删操作 所有select缓存都会被清除
远程调用 网关 注册中心 负载均衡 降级熔断
服务注册和发现和监控
eureka 被消费者 主动发送信息给注册中心 消费者 从注册中心拉取信息
nacos 和 eureka 的区别
Ribben 从注册中心获取节点信息 之后按照负载均衡配置来处理
随机 轮询 权重 最少连接 配置区域轮询 比如同一个机房为一个区域
实现IRule接口 编写配置类
服务降级 针对于某个接口 服务熔断 针对于整个微服务
服务降级 一般开发中与Feign接口整合, 编写降级逻辑
服务熔断 如果检测到一定时间内失败次数很高, 就会触发熔断机制 一段时间之后尝试请求微服务 如果失败会继续熔断 如果成功就关闭熔断
skywalking 可以监控微服务 并给出提醒 可以看到整个微服务的状态 可以看到详细的接口相应情况 包括接口每个阶段执行的情况 包括数据库的耗时情况
nginx 漏桶算法
以固定的速率输出请求 过多的请求等待或丢弃
网关 springcloud 令牌桶
申请到令牌的服务才处理 过多的等待或丢弃
RabbitMQ publicher exchange queue consumerX
使用确认机制 检测丢失 丢失后 可以使用 使用回调方法 写入日志 保存到数据库重发 来解决
消息持久化 默认为内存存储 开启持久化可以缓存消息 交换机和队列中的数据
消费者有确认机制 消费者出现异常的时候会 利用本地重试 如果一直失败 会将信息发送到异常交换机 由人工处理
设置唯一id 幂等 方案: 分布式锁 数据库锁
增加消费者 消费者启用多线程技术 扩大队列容积 使用惰性队列
集群
幂等 restful 风格中 put update 都不是幂等的
新增数据 可以使用唯一索引
tooken + redis 请求的时候将要tooken 存储到redis中 处理的时候去redis看一下有没有token 有就处理, 处理的同时时候删除token
使用分布式锁
xxl-job
随机 轮询 一致性hash LFU LRD 故障转移 分片广播
设置故障转移和重试机制
采用分片广播
序列化 转为json 之后存入
分布式锁为分布式事务提供服务
单机情况下使用语言内置的锁可以实现 分布式情况下无法这样做 可以使用一个互斥量 或者使用Redis内置的Redlock 使用互斥量一般是单点情况下 redlock使用了多个节点搭建 避免单点故障 使用互斥量可以使用redis或者是MySQL数据库 实现 获得锁的时候插入一个数据 释放锁的时候删除这个数据 唯一索引可以保证只被插入一次 使用redlock 会尝试从 N 个独立的节点获取锁 并且从大多数节点上获得锁成功 就认为获得了锁
原子性 一致性 隔离性 持久性 aut cons ins de 事务是最小单元 数据库事务前后 数据的状态保持一致 并发事务之间不受影响 事务提交后对数据库的修改是永久的
CAP BASE 是分布式系统架构的一些概念 CAP 指的是 一致性 可用性 分区容错性 分布式系统一般无法满足三者 而我们要认为网络是不可靠的 因而我们再分布式系统设计的时候一般选取 两种原则 CP AP CP 保证了强一致性 但是会损失部分可用性 AP 保证了系统的高可用 允许中间状态存在
BASE 是对 CAP 的一种妥协 BASE指的是 基本可用 软状态 和 最终一致性 通过参考BASE理论可以搭建微服务的架构
会对redis的持久化产生影响 阻塞主线程 或 过多的消耗资源 回盘策略如果设置的always 主线程执行完后 会调用fsync() 函数 等到读写操作完成之后 函数才会返回 因而会阻塞 过大的key会造成AOF重写的机制过快 损失性能
UUID 雪花算法生成分布式ID UUID 过长 造成 MAC地址泄漏 空间消耗大 没有业务意义 没有规则 雪花算法生成的ID 有可能会产生重复 但可以定制 并且相对来说短一些 可以实现有序递增
128b
可以但是不建议 因为太长了 影响性能
根据用户的ID 使用限流中间件 //TODO
超时重试机制 可以采用 固定时间重试 或者是梯度区间重试的方法 防止一次请求被多次执行 可以使用幂等设计接口
系统再等待IO的时候不会阻塞 可以去处理其他请求
主动关闭部分功能 保证总体可用 比如限制流 延长页面相应时间等
增加缓存 搭建集群 包括读写分离的主从复制集群 还有分片集群 对数据进行分库分表
可以采用查看进程的方式 也可以使用查看网络的方式 使用查看进程的方式 命令是 ps -ef| grep 端口号 使用查看网络的方式 命令是 netstatu |grep 端口号
继承是 is a 的关系 子类是父类的特殊实现形式 聚合是 has a 的关系 一个对象包含另一个对象
通过Class类,我们可以获取类的结构信息,如类的方法、字段、构造函数等 并且可以动态地创建对象、调用方法、访问字段等
类中有属性 ... 需要定义一些 默认的实现
深层次解耦 更有利于拓展 继承多个
外层循环遍历行 内层循环遍历列 的性能会更高一些
注意一些比较实际的东西 比如 基础 数据库 还有一些旧技术但是有用的技术的原理 操作系统和网络问的不多
MVC是一种设计模式 Model(模型)、View(视图)、Controller(控制器) Controller 是Model和View这两层的桥梁
历史悠久 应用广泛 包括智能手机 软件 嵌入式 特性 跨平台 多线程 面向对象的特征 对比 简单 相较于c++ 不支持指针操作内存 自动垃圾回收 不支持运算符重载 生态十分完善 包括数据库 集群 和一系列中间件都对java进行了适配
servlet 是 javaweb的 核心内容 是java 实现的动态web技术 servlet 是java规范之一 我们实现servlet 接口可以借助servelt 服务器运行项目
Servlet 初始化后调用 init () 方法。
创建一个servlet 实例
Servlet 调用 service() 方法来处理客户端的请求。
service 会调用 doGet doPost 方法 我们需要重写这些方法
Servlet 销毁前调用 destroy() 方法。 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
每个请求都会创建一个线程 执行 根据不同的路径 执行不同的servlet 方法
tomcat 一般作为javaweb项目的web容器 实际上 tomact 是一个servlet 容器 用来托管和处理servlet
使用 @ExceptionalHandler 注解 在类中定义一个方法
单个Controller
使用 @ControllerAdvice 注解 定义一个类
全局
可以在里面针对不同的异常类 写对应的处理方法
内外连接
是用来处理夺表操作的
见mysql
sql执行顺序
如何对SQL语句优化
分页查询
问了一些SQL的书写,比如聚合函数、group by啥的
基本的JDBC操作
Java内存分布 垃圾回收 CMS G1 溢出问题
怎么判断空指针
Static关键字的用法
如果使用算法的话 对10取余得到最后一个数字 为新数字的第一个数字 之后将源数字除以10 重复操作 可以得到新数字的第二个数字 如此递归 得到最终的结果
如果用库函数的话 将数字转为 String 之后用 StringBuffer 中的 reverse 函数 之后再转为整数
现在年轻 加班有加班费的话 倒是挺喜欢加班的 一方面可以多赚点钱 另一方面可以增加工作能力 对敲代码挺感兴趣的
uml包图和类图
流程图 用例图
可以用一些ui设计参考软件 比如 figma
功能 性能 可靠性 安全性 兼容性 易用性 还要看用户的反映
做事比较认真 有责任心 之前初中高中 也有担任班委 办事老师挺满意的 做事比较干净
那段时间比较贪玩 而且那个课比较难 没怎么学 之后暑假认认真真的学了一遍 暑假过后开学的时候补考过了
范式
(声明式、编程式)
启动类 @EnableTransactionManagement 启动事务的时候 添加 @Transactional 注解
是一家国有控股企业 使用 计算机技术 赋能传统产业
多学习 提升自己 争取拿更高的工资 争取在这个行业更加深入一些
刚开始参加了ACM社团 后来发现自己不太适合写算法 之后就退了 之后课余时间 就鼓捣一些自己喜欢的东西 比如docke git linux 等 还有一些硬件的 aruiniu 单片机等 装系统 刷机什么的 还有部署使用各种各样的开源项目
两个面试官,一个hr,一个技术,过程比较轻松
1.自我介绍 2.考研了吗?考了什么学校?考了多少分?二战吗? 3.家在外省,为什么选择济南? 4.之前有投过简历吗?有没有收到offer? 在招聘软件上投过很多 回复的很少 有一个让我等着 5.针对项目问了特别多问题(优势?学校老师要求的还是自己做的? 学校的大作业 我做的比较认真 后来学了新技术又优化了一下 大概是做什么的,如何实现) 7.(简历上写了熟悉linux系统)问了几条linux命令,比如如何复制文件,如何给用户授权,最大的权限是什么?
拥有者 所属组 其他用户 chmod chown:修改所属组和所有者
chown runoob:runoobgroup file1.txt
8.数据库!!! (1)问了几个语句 如何给查询结果排序(升序,降序DESC) 如何分片(比如查询第10-15条记录) SELECT * FROM your_table LIMIT 9, 6; (2)主要学了哪些数据库? mysql redis (3)熟悉数据库索引吗?索引的优缺点?有哪几类索引? B树索引、哈希索引、全文索引等
全文索引 一般用于模糊查询
(4)哪些数据适合索引?(比如性别适不适合) 通常情况下,索引应该应用于那些经常被用作查询条件的列,以提高查询性能。性别这一列通常只有两个不同的取值(比如"男"和"女"),因此对于性别这样的低基数列来说,并不适合创建索引。
作为查询条件的列
区分度高的 长度短
经常用于where的字段
经常用于排序分组的字段
(5)知道范式吗?第一范式第二范式?
解耦 消除冗余
第一范式 字段的值是源自性的,不可再分
第二范式 数据库中的每个记录都是 唯一可以标识的 而且所有非主键字段 都必须完全依赖主键
第三范式 所有非主属性之间不可存在依赖
(6)什么是mySQL事务?
事务是一组 逻辑上的一块执行的 行为 要么同时,,,,
mysql事务对应一组操作 要么同时,,,,
可以开启事务 之后输入代码 最后提交事务
成功的话 事务就会正常执行 有误的话可以进行事务的回滚
mysql不会自动回滚 需要我们自己解决
使用一些框架 出现异常的时候可以帮助我们回滚
9.主要用的语言是什么? 10.你的职业规划是什么? 11.对于女生来说,考公务员是一个比较好的选择,你考虑过公务员吗?为什么不考 不喜欢那种东西 没啥兴趣 没啥意思
商品表(Products table):
商品ID(Product ID)
商品名称(Product Name)
商品描述(Product Description)
商品价格(Product Price)
商品库存(Product Stock)
商品分类ID(Category ID)
上架时间(Listed Time)
下架时间(Unlisted Time)
销量(Sales Volume)
状态(Status)
创建时间(Created Time)
更新时间(Updated Time)
商品分类表(Categories table):
分类ID(Category ID)
分类名称(Category Name)
父级分类ID(Parent Category ID)
购物车如何实现的
未登录的用户存放到本地缓存中 比如lcoalStrong
已经登录的存放在redis中
需要后端提供哪些接口?
对Redis操作的一些接口
可以使用Redis 中的 hash 结构存放 id 和 数量两个字段
提供查询和更新的接口
订单
创建一个订单类
确定支付的时候 点击支付就会创建订单
从Redis中拷贝购物车信息 之后添加到订单中 并使用订单类提供的方法计算价格
之后将订单给 RabbitMQ 使用异步处理 不会阻塞主线程
这一块是比较复杂的 建议画一个流程图
使用定时调度 超时的订单就自动释放