# Typora **Repository Path**: lrf2021/Typora ## Basic Information - **Project Name**: Typora - **Description**: md笔记 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2021-03-28 - **Last Updated**: 2025-02-14 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Java学习笔记 # 一、数据结构与算法 ## 数据结构: 基础数据结构 * 链表 * 栈 * 队列、约瑟夫环 * 数组 * 树、二叉树、二叉查找树、二叉平衡树 * 图 高级数据结构 * 红黑树 * B树/B+树 * 跳表 * 堆(优先队列) ## 算法 * 双指针/滑动窗口 * DFS、BFS * 回溯 * 动态规划 * 贪心 * 分治 * 拓扑排序 # 一、Java基础: ### 1.集合 * Map * HashMap:数组+链表+红黑树,初始容量16,负载因子0.75f,阈值12,容量默认为大于参数的第一个2的次方。计算hash(hashcode与本身右移16位相与)。链表长度大于8且数组长度大于64转成红黑树,小于6转回链表,扩容是下一个2的次方,数据迁移(hash与原数组长度相与,高位0则不变,高位1则迁移到原位置加原数组长度的位置),可以存null键null值 * TreeMap:有序,使用红黑树,传入的key必须实现了Comparator接口,比较使用的是key本身的compare方法 * LinkedHashMap:在HashMap的基础上对每一个node结点增加了before、after指针,可以按照插入顺序遍历 * List * ArrayList:数组,默认容量10(创建时为0,第一次add时扩为10),扩容(grow)1.5倍,遍历时删除需要用迭代器或者从后开始遍历,删除元素使用Object(如果是整型则要确保是Integer而不是int),删除下标使用int * LinkedList:链表,通过下标查找元素时会判断是前半部分还是后半部分 * Set * HashSet:底层是HashMap,只有key,value为null * TreeSet:底层是TreeMap,只有key,value为null * Queue:LinkedList ### 2.IO * IO * NIO * channel:双向的 * buffer * selector ### 4.网络编程 Socket WebSocket ### 5.反射 * 获取class的三种方式: ``` //1.通过类名.class获取 Class c1 = Person.class; //2.通过Class.forName()传入全类名获取 Class c2 = Class.forName("com.demo.Person"); //3.通过对象的getClass()方法获取 Person person = new Person(); Class c3 = person.getClass(); ``` ### 6.异常 * Exception:程序本身可以捕获并且可以处理的异常,其 * RuntimeException是Exception的子类,RuntimeException类极其子类表示JVM在运行期间可能出现的错误。编译器不会检查此类异常,并且不要求处理异常,**常见运行时异常**:`空指针异常`,`数组越界`,`类型转换异常`,**常见非运行时异常:**`IOException`,`SqlException` * Error:指示运行时环境发生的错误。**常见Error:**`OutOfMemoryError内存溢出`,`StackOverflowError栈溢出` ### 7.Java 8 新特性 * stream * lambda: ()->{} * 接口新增default方法 # 二、并发 ## 1.volatile * 原理:数据在主内存中,每次读取数据从主内存中读取,修改数据先从主内存中读取数据到工作内存中,修改后再写回到主内存 * 可见性:并发情况下当数据修改后会强制线程立刻从主内存中读取新数据 * 禁止指令重排:单线程下指令重排可以优化,但是多线程会有安全问题,使用volatile可以禁止指令重排 ## 2.synchronized * 对象数据: * 对象头: * mark word:存储锁标志、hashcode、对象分代年龄等 * klass point:指向这个对象的类元数据,确定是哪一个类 * 实例数据:存放类的属性信息,包括父类的信息 * 对齐填充:使对象地址是8的整数倍 * monitor对象: * entryList:所有竞争锁的线程都会进入这个集合 * waitSet:处于wait状态的线程 * owner:指向持有锁的线程 * count:加锁次数,可重入 * 使用方式和特性:可重入(防止死锁)、非公平 * 锁升级: * 无锁:锁状态为01,保存有hashcode,第一次调用hashcode()方法会计算并将这个字段填充,后续hashcode会直接取这个字段而不是重新计算 * 偏向锁:锁状态为01,使用线程id和epoch值覆盖,需要计算hashcode会撤销偏向锁并升级为轻量级锁 * 轻量级锁:锁状态为00,指向栈帧中锁记录,会将mark word拷贝到锁记录中 * 重锁:锁状态为10,指向monitor对象,会将mark word拷贝到monitor对象字段中 ## 3.Lock * 可重入锁ReentrantLock:可重入、公平/非公平,底层是有个sync继承了AQS,lock是调用的sync的tryAcquire方法 * 可重入读写锁ReentrantReadWriteLock:state分为2部分,高16位是读状态,低16位是写状态,读写互斥, * Condition:定义在AQS内部的ConditionObject实现了接口,调用await时会释放锁(所以需要先加锁),进入阻塞状态,当其他线程调用signal方法后会唤醒,重新尝试加锁。 * 锁分类:重入锁、读写锁、公平/非公平锁,乐观/悲观锁,共享/独占锁,死锁和活锁 ## 4.AQS * state:维护一个volatile int变量,表示锁数量,每次加锁加1,释放锁减1 * 同步队列:所有没竞争到锁的线程都会构造成node结点加入到队列中,然后会尝试加锁两次,都失败后使用LockSupport进行阻塞 ## 5.并发工具类: * CountDownLatch:内部sync继承了AQS,通过共享锁的形式加锁,每次countdonw的时候使state减1,await()判断state是否为0 * CyclicBarrier:底层通过ReentrantLock和Condition来实现,如果线程是最后一个调用await的,就调用signalAll唤醒所有线程,否则进入阻塞 * Semaphore:内部sync继承了AQS,使用共享锁,传入一个int表示最大线程数,每次有线程加锁则state加1,直到达到最大线程数,再加锁就会进入阻塞,有锁释放则唤醒所有线程竞争锁。 ## 6.线程 ### 线程状态: **操作系统线程状态** * 新建new * 就绪ready * 运行runing * 阻塞 * 死亡 **Java线程状态** * NEW:新建状态,表示一个Thread刚刚被创建出来,还没有启动 * RUNNABLE:可运行状态。一个新创建好的线程,调用其start()方法后,就会由NEW状态迁移到RUNNABLE状态。 * BLOCKED:阻塞状态,表示线程正在等待一个监视器锁(monitor lock),而监视器锁在Java代码中的体现就是synchronized关键字。**也就是说:只有线程在等待进入synchronized修饰的代码块或方法时,线程才处于BLOCKED状态。** * WAITING:等待状态,表示线程在等待某些条件的到达。在调用以下方法后,线程会进入WAITING状态: 1. Object中定义的无超时的wait()方法,等待一个同步监视器的唤醒; 2. Thread中定义的无超时的join()方法,等待其他线程执行完毕; 3. LockSupport.park()方法。 * TIMEWAITING:超时等待状态,与WAITING状态类似,并在其基础上,增加了超时的限制。在调用以下方法后,线程会进入TIMED_WAITING状态: 1. Thread.sleep()方法,线程定时休眠; 2. Object中定义的带超时的wait()方法; 3. Thread中定义的带超时的join()方法; 4. LockSupport.parkNanos()方法; 5. LockSupport.parkUntil()方法。 * TERMTED:终止状态,包括线程正常执行完毕和异常终止。 ### 常用方法 * yield:使当前线程放弃cpu的使用权 * sleep:使当前线程阻塞,不释放锁 * interrupt:中断阻塞中的线程 * join:当线程B调用了线程A的join方法,只有等待线程A执行完,线程B才会执行后面的代码。 ## 7.线程池 ### 参数 * coreSize核心线程数 * maxSize最大线程数 * time空闲时间 * 空闲时间单位 * 阻塞队列 * 线程工厂 * 拒绝策略: * AbortPolicy:直接抛出异常 * CallerRunPolicy:由调用者执行(比如main线程) * DiscardPolicy:直接丢弃 * DiscardOldestPolicy:丢弃等待时间最久的,并执行当前任务 ## 8.ThreadLocal * ThreadLocal原理:有一个内部类ThreadLocalMap,其键值对存储的是ThreadLocl对象和需要线程独有的值,Thread有一个属性是ThreadLocal类型,每一个线程都有自己的map,key是一个ThreadLocal对象和其存储的值,当声明了多个ThreadLocal对象存储值,当前线程的map也会存储多个ThreadLocal对象和其存储的值。 * 内存泄漏问题:ThreadLOcalMap的Entry是继承了弱引用,当进行垃圾回收时会回收Entry ## 9.并发容器: * ConcurrentHashMap:有一个sizeCtl的变量(默认0,-1表示正在扩容,-(n+1)表示有n个线程在扩容),当遍历到forwarding结点时会协助扩容,遍历链表时会给头结点加锁,不允许null键null值, * CopyOnWriteArrayList:底层是Object数组,添加时使用ReentrantLock加锁,复制一份长度+1的新数组,在新数组最后一个位置上添加新元素,将新数组覆盖旧数组 * CopyOnWriteArraySet:底层是CopyOnWriteArrayList,添加时是调用CopyOnWriteArrayList的addIfAbsent方法,如果存在则返回false,否则插入。 * BlockingQueue: * ArrayBlockingQueue:底层Object数组,添加时进行加锁,直接放在最后一个索引,如果满了则返回false * LinkedBlockingQueue:使用了AtomicInteger来保存任务数量,offer时先加锁,再判断任务数量是否小于容量,将节点加入到链表尾部 * PriorityBlockingQueue:底层使用的是优先队列 * DelayQueue:存储的数据必须实现Delay接口 * SynchronousQueue:不存储元素,只有当一个元素poll()时另一个元素才能调用offer() ## 10.原子类 * AtomicInteger:底层是一个volatile int变量,在增加值时调用了unsafe的cas方法进行更新,通过自旋不断判断是否相等,相等才更新 * AtomicLong:同AtomicInteger,底层是一个volatile long变量 * LongAdder:并发环境下的计数器 ## 11.Fork/Join框架 将一个任务拆分成多个任务,再把任务的结果合并 # 三、Java虚拟机 ### 1. Java内存区域 **线程独有区域** * 栈:局部变量、操作数、动态链接、方法返回地址 * 本地方法栈 * 程序计数器 **共享区域** * 堆 * 方法区(常量池) * 直接内存 ### 2.垃圾收集算法 分代收集理论 标记清除 标记复制 标记整理 ### 3.垃圾收集器 Serial收集器 ParNew收集器 Parallel Scavenge收集器 Serial Old收集器 Parallel Old收集器 CMS收集器 G1收集器 ZGC收集器 ### 4.内存分配策略 1. 对象优先在Eden区分配 2. 大对象直接分配到老年代 3. 长期存活的对象进入老年代(默认经过15次minor gc后仍然存活的对象) 4. 当同年对象达到Survivor区的一半时,将直接进入老年代,而不用等到15岁 5. 当minor gc不足以将存活对象转移到survivor区后,会启用分配担保机制转移到老年代 ### 5.类加载机制 **类加载过程** 1. 加载:加载Class文件 2. 验证:确保class文件中的字节流符合约束条件 3. 准备:为类中定义的变量分配内存,并初始零值 4. 解析:将常量池中的符号引用替换为直接引用 5. 初始化:为类变量赋值 **类初始化的时机** * 当遇到new一个对象,读取或设置一个静态字段时,或者调用一个静态方法时 * 使用反射包对类进行调用时 * 当初始化一个类时,需要先初始化其父类 * 虚拟机启动时会先初始化主类(main类) **类加载器** * 启动类加载器 * 扩展类加载器 * 应用程序类加载器 * 自定义类加载器 **双亲委派模型** * 当一个类加载器收到了类加载的请求,会把这个请求委派给父类加载器去加载 * 只有当父类加载器反馈不能加载时才会尝试自己去加载 * 模型可以保证在不同类加载器环境下,系统定义的类(Object)是同一个类 **破坏双亲委派模型** * 重写类加载器的loadClass方法 ### 5.Java内存模型 volatile 原子性 有序性(指令重排) 可见性 # 四、Mysql数据库 ### 数据库理论 **模式** * 模式 * 内模式 * 外模式 **范式** * 第一范式1NF:所有属性不可再分, * 第二范式2NF:满足第一范式,同时所有非主属性完全函数依赖于任何一个候选码 * 第三范式3NF:满足第二范式,同时所有非主属性不传递依赖于候选码 * 巴斯范式BFNF:满足第三范式,同时主属性之间不存在传递依赖和部分函数依赖 ### 存储引擎 * InnoDB * MyISAM * Memory ### 索引 * 聚簇索引 * 唯一索引 * 全文索引 ### 锁 **锁的类型** 行锁 * 共享锁(S锁):允许事务读一行数据,共享锁与共享锁兼容 * 排他锁(X锁):允许事务删除或更新一行数据,排他锁与所有锁都不兼容 * 表锁: * 行锁: * 页锁: * 意向锁: * 记录锁:锁住行记录 * 间隙锁:锁住与相邻键之间的间隙 * 临建锁(next-key):将修改的键及与相邻键之间的间隙都锁住 * 自增锁:表级锁, 当使用自增id时,进行插入会添加自增锁,以保证自增id唯一。InnoDB提供了一种轻量级互斥量的自增长机制,提供了一个参数innodb_autoinc_lock_mode设置自增模式,默认值是1 * 0,通过表锁的方式 * 1,对于简单插入使用互斥量进行累加,对于批量插入使用自增表锁 * 2,对于所有插入都使用互斥量进行自增 ### MVCC ### 事务 * 隔离级别 * 读未提交:产生脏读、不可重复读、幻读问题 * 读已提交:解决脏读问题 * 可重复读:解决不可重复读问题 * 序列化:解决幻读问题 * ACID特性 * A(**Atomicity**)原子性:一个事务中的所有操作要么全部完成,要不全部失败 * C(**Consistency**)一致性: * I(Isolation)隔离性:数据库允许多个事务之间并发执行, * D(**Durability**)持久性:事务处理结束后,对数据库的修改是永久的 ### 优化 分表、分库、sql语句优化、explain # 五、Java Web ## 1.spring ### IOC原理 **bean的生命周期** IOC容器初始化过程 ### AOP原理 **AOP实现** * JDK代理 * cglib代理 ## 2.spring mvc **MVC源码流程** **消息处理流程** ## 3.mybatis JDBC、Mybatis和Hibernate 动态SQL #和$ 缓存机制 ## 4.SpringBoot ### 常用注解: * @SpringBootApplication * @Conditional * @EnableAutoConfiguration # 六、中间件 ### redis 四大问题 * 缓存击穿 * 缓存穿透 * 缓存雪崩 * 一致性问题 数据类型 持久化 过期策略和内存淘汰策略 Redis单线程 ### MQ # 七、操作系统 ### Linux常用命令 ### IO多路复用 ### 进程线程协程 ### 进程间的通信 ### IO模型 ### 内存 ### 缺页中断 # 八、计算机网络 ## 浏览器输入一个网址过程 ## 应用层 dns http https cookie和seesion ## 传输层 tcp udp 三次握手、四次挥手 子网掩码 ## 安全相关 XSS CSRF SQL注入 # 九、设计模式 **设计原则**: * 单一职责原则:一个类应该只有一个发生变化的原因,通俗:**一个类只负责一项职责,如果有多项应该拆分为两个类** * 开闭原则:应该对扩展开放,对修改关闭 * 里氏替换原则:所有引用基类的地方,必须能够透明地使用其子类的对象。通俗:**子类可以扩展功能,但不能改变父类原有功能** * 迪米特法则:只与你的直接朋友交谈,不跟“陌生人”说话。通俗:**如果两个类无需直接通信,则应该由第三方转发调用,降低耦合** * 接口隔离原则:要为各个类建立它们需要的专用接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。 * 依赖倒置原则:要面向接口编程,比如传参应该传入一个接口,而不是具体的类 **设计模式** * 单例模式 * 策略模式 * 观察者模式 * 建造模式 * 工厂模式 * ......