├── 05 设计模式 ├── notes │ ├── 解释器模式.md │ ├── 设计模式原则.md │ ├── 抽象工厂模式.md │ ├── 简单工厂模式.md │ └── 工厂模式.md └── pics │ ├── Observable.png │ ├── Observer_Result.png │ ├── Proxy_Pattern.png │ ├── JDK_Proxy_Result.png │ ├── Spring_ObserverPattern.png │ ├── Observer&EventListhener.png │ └── observer_pattern_uml_diagram.jpg ├── 06 计算机网络 ├── notes │ ├── CDN.md │ ├── 物理层.md │ ├── 负载均衡.md │ ├── Ping.md │ ├── 流量控制和拥塞控制.md │ ├── URI.md │ ├── IP地址.md │ ├── ARP、RARP.md │ ├── 计算机网络体系结构.md │ ├── HTTPS.md │ ├── GET和POST.md │ └── 各层协议.md └── pics │ ├── 三次握手.png │ ├── 响应报文.png │ ├── 四次挥手.png │ ├── 请求报文.png │ ├── 各层的作用.png │ ├── 对应网络协议.png │ ├── HTTPS C S.png │ ├── TSL SSL.png │ ├── HTTP-HTTPS.png │ ├── 7层模型 四层模型 五层协议.png │ ├── HTTP REQUEST.png │ └── HTTP RESPONSE.png ├── 09 数据结构与算法 ├── 02 链表 │ └── 常用方法.md ├── 07 动态规划 │ ├── 相关方法.md │ ├── BFS和DFS.md │ └── LeetCode总结.md ├── 06 大数据 │ ├── 大数据算法.png │ ├── TOP K问题.md │ └── 预备知识点.md ├── 11 数组 │ └── notes │ │ └── Leetcode总结.md ├── 01 排序 │ └── pics │ │ ├── HeapSort.gif │ │ ├── HillSort.jpg │ │ ├── BubbleSort.gif │ │ ├── BucketSort.gif │ │ ├── CountSort.gif │ │ ├── MergeSort.gif │ │ ├── QuickSort.gif │ │ ├── RadixSort.gif │ │ ├── InsertionSort.gif │ │ ├── SelectionSort.gif │ │ ├── algorithm_analysis.png │ │ ├── bubbleSort_example.png │ │ ├── mergeSort_example.png │ │ └── selection_sort_example.png ├── 10 数据结构 │ ├── pics │ │ ├── Stack.png │ │ ├── queue.jpg │ │ ├── TwoWayLinkedList.png │ │ ├── Single-Linked List.png │ │ ├── SingleCirularLinkedList.png │ │ └── TwoWayCirularLinkedList.png │ └── notes │ │ ├── 栈.md │ │ ├── 数组.md │ │ ├── 堆和栈的区别.md │ │ ├── 队列.md │ │ └── 链表.md ├── 03 二叉树 │ └── notes │ │ ├── B树 B+树详解.md │ │ └── 题目总结.md ├── 04 字符串 │ └── 常用思路和API.md ├── 08 DFS BFS │ └── Leetcode总结.md └── 09 二分查找 │ └── Leetcode总结.md ├── 17 中间件 └── 01 消息队列 │ └── notes │ ├── Kafaka.md │ ├── 消息队列选型.md │ ├── 怎么保证MQ的高可用性.md │ ├── 怎么保证MQ消息不丢失.md │ └── 消息持久化.md ├── 04 框架 ├── 01 Spring │ ├── notes │ │ ├── Spring事件和监听器.md │ │ ├── Spring handlers.md │ │ ├── Spring优点.md │ │ └── Spring后置处理器.md │ └── pics │ │ ├── bean的初始化.png │ │ ├── run result.png │ │ ├── Spring constructure.png │ │ ├── Spring 高级 低级容器 UML.jpg │ │ └── SpringBean lifeCycle.png ├── 02 Spring MVC │ ├── pics │ │ └── DispatchServlet.png │ └── notes │ │ └── SpringMVC.md ├── 05 Netty │ └── notes │ │ └── 简介.md └── 03 MyBatis │ └── notes │ └── mybatis概述.md ├── 02 JVM ├── pics │ ├── 堆内存.gif │ ├── parNew.png │ ├── serial.png │ ├── 内存交互操作.png │ ├── 函数调用过程.png │ ├── 双亲加载机制.png │ ├── 句柄访问对象.png │ ├── 垃圾收集器.jpg │ ├── 复制算法.jpg │ ├── 对象创建过程.png │ ├── 指针访问对象.png │ ├── 标记清除.jpg │ ├── 虚拟机栈帧.png │ ├── 内存堆按年代分.png │ ├── 双亲委派实现.jpeg │ ├── jdk1.8前内存结构.png │ ├── jdk1.8后内存结构.png │ ├── serial-old.png │ ├── stack-Frame.png │ ├── parallel-old.png │ ├── root-tracing.png │ └── 线程、主内存、工作内存.webp └── notes │ ├── 逃逸分析.md │ ├── 栈上分配和TLAB.md │ ├── JVM参数.md │ ├── 内存泄漏和内存溢出.md │ ├── JVM内存对象.md │ └── 锁优化.md ├── 07 操作系统 ├── pics │ ├── 共享存储.png │ ├── 消息传递.png │ ├── 磁盘结构.jpg │ ├── 管道通信.png │ ├── 进程的状态.png │ ├── 进程通信.png │ ├── Linux架构.png │ ├── 多级反馈队列.png │ └── Linux细分结构jpg.jpg └── notes │ ├── 并行、并发.md │ ├── 同步、异步.md │ ├── 孤儿进程和僵尸进程.md │ ├── 硬链接、软链接.md │ ├── 页面置换算法.md │ ├── 设备管理.md │ ├── 线程间通信和进程间通信.md │ ├── 段式管理和页式管理.md │ └── 内存管理.md ├── 03 多线程和高并发 ├── pics │ ├── 线程状态.png │ ├── 线程池类图.png │ ├── Syc code.png │ ├── Syc method.png │ ├── threadLocalMap.png │ ├── ThreadLocal结构概览.jpg │ └── threadFactory state.jpg └── notes │ ├── Unsafe.md │ ├── 公平锁和非公平锁.md │ ├── 可重入锁.md │ ├── CPU密集型和IO密集型.md │ ├── 自旋锁.md │ ├── 读写锁.md │ └── 线程状态.md ├── 15 工具 └── 01 Git │ └── pics │ ├── .git.png │ ├── fork.png │ ├── branch.png │ ├── git add.png │ ├── git log.png │ ├── conflict .png │ ├── git clone.png │ ├── git commit.png │ ├── git push.png │ ├── remote add.png │ └── user.name email.png ├── 08 数据库 ├── 02 Redis │ ├── pics │ │ ├── AOF.png │ │ ├── RDB.png │ │ ├── 缓存穿透.png │ │ ├── AOF流程.png │ │ ├── RDB流程.png │ │ ├── Redis主从.jpg │ │ ├── Redis哨兵.jpg │ │ ├── Redis集群.jpg │ │ ├── 持久化恢复数据.png │ │ ├── 缓存雪崩解决.jpg │ │ ├── Redis单副本.jpg │ │ ├── Redis哨兵2.jpg │ │ ├── Redis完整同步.jpg │ │ ├── redis高并发.jpg │ │ ├── redis高性能.jpg │ │ ├── Redis部分重同步.jpg │ │ ├── psync process.jpg │ │ └── Redis master slave.jpg │ └── notes │ │ ├── redis 和 memcached.md │ │ ├── 分布式锁.md │ │ ├── 缓存雪崩和缓存穿透.md │ │ ├── 数据一致性.md │ │ └── 过期策略和淘汰策略.md └── 01 MySQL │ ├── pics │ ├── 乐观锁实现.jpg │ ├── master-slave.png │ ├── Secondary Index.png │ └── clustered index.png │ └── notes │ ├── 慢查询优化.md │ ├── 数据库备份.md │ ├── MySQL实践.md │ ├── 聚集索引和非聚集索引.md │ ├── 回表查询.md │ ├── 优化.md │ ├── SQL语句.md │ ├── 分库分表.md │ ├── 视图.md │ ├── Drop,Delete,Truncate.md │ ├── inner join、left join和right join.md │ ├── MySQL事务.md │ ├── Explain.md │ ├── 三大范式.md │ ├── 主从复制与读写分离.md │ └── MVCC多版本并发控制.md ├── 10 项目 └── 03 电商基础秒杀 │ ├── notes │ ├── 脑图.png │ ├── 防止超卖.md │ ├── Redis问题.md │ ├── 面试问题.md │ ├── 秒杀框架.md │ ├── 项目介绍.md │ ├── 第七章 安全优化.md │ ├── 第五章知识点.md │ ├── 负载均衡.md │ └── 第三章知识点.md │ └── pics │ ├── 秒杀系统设计.png │ ├── AmqpTemplate.png │ ├── Direct Mode.png │ ├── Fanout mode.png │ ├── Topic mode.png │ └── RabbitMQ structure.png ├── 01 JavaSe ├── 01 集合框架 │ ├── pics │ │ ├── 拉链法原理.png │ │ ├── 集合框架.png │ │ ├── LinkedList.png │ │ ├── 集合继承关系图.webp │ │ ├── TreeMap_base.png │ │ ├── hashmap-put.png │ │ ├── ArrayList底层实现.png │ │ ├── LinkedList类图关系.png │ │ ├── LinkedList_remove.png │ │ ├── Concurrenthashmap-ds.png │ │ ├── CopyOnWriteArrayList.png │ │ ├── LinkedList_add(E e).png │ │ ├── TreeMap_rotateLeft.png │ │ ├── TreeMap_rotateRight.png │ │ ├── Arrylist与Collection关系.jpg │ │ └── ConcurrentHashMap JDK1.8.png │ └── notes │ │ ├── TreeSet and TreeMap.md │ │ └── Vector.md ├── 03 基础概念 │ ├── pics │ │ ├── 重写 重载.png │ │ ├── static.jpg │ │ ├── jvm,jre,jdk.png │ │ ├── Error&Exception.png │ │ └── abstract&Interface.jpg │ └── notes │ │ ├── 什么是重载和重写.md │ │ ├── Java和C++区别.md │ │ ├── JVM,JRE,JDK.md │ │ ├── Java 各版本的新特性.md │ │ ├── super.md │ │ ├── final关键字.md │ │ ├── 字符串常量池.md │ │ ├── 继承.md │ │ ├── 封装.md │ │ ├── Object.md │ │ ├── 多态.md │ │ ├── 反射.md │ │ ├── 对象的序列化和反序列化.md │ │ ├── 装箱和拆箱.md │ │ ├── equals.md │ │ └── 值传递和引用传递.md └── 02 IO │ └── notes │ ├── 文件读写.md │ └── IO模型.md ├── 18 Java8 └── pics │ ├── Stream Operation.jpg │ ├── Terminal Result.jpg │ ├── what stream can do.jpg │ ├── Stream Operation List.jpg │ └── Stream intermediate Operation output.jpg ├── 16 Tomcat └── pics │ ├── Tomcat Struction.png │ └── tomcat boot process.png ├── 12 HR常问 ├── 非科班.md └── HR常问.md └── 11 分布式与微服务 └── 02 分布式 └── notes ├── 分布式事务.md ├── 分布式锁.md ├── BASE.md └── CAP定理.md /05 设计模式/notes/解释器模式.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /06 计算机网络/notes/CDN.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /06 计算机网络/notes/物理层.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /06 计算机网络/notes/负载均衡.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /09 数据结构与算法/02 链表/常用方法.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /09 数据结构与算法/07 动态规划/相关方法.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /17 中间件/01 消息队列/notes/Kafaka.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /04 框架/01 Spring/notes/Spring事件和监听器.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /04 框架/01 Spring/notes/Spring handlers.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /02 JVM/pics/堆内存.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/02 JVM/pics/堆内存.gif -------------------------------------------------------------------------------- /02 JVM/pics/parNew.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/02 JVM/pics/parNew.png -------------------------------------------------------------------------------- /02 JVM/pics/serial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/02 JVM/pics/serial.png -------------------------------------------------------------------------------- /02 JVM/pics/内存交互操作.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/02 JVM/pics/内存交互操作.png -------------------------------------------------------------------------------- /02 JVM/pics/函数调用过程.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/02 JVM/pics/函数调用过程.png -------------------------------------------------------------------------------- /02 JVM/pics/双亲加载机制.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/02 JVM/pics/双亲加载机制.png -------------------------------------------------------------------------------- /02 JVM/pics/句柄访问对象.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/02 JVM/pics/句柄访问对象.png -------------------------------------------------------------------------------- /02 JVM/pics/垃圾收集器.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/02 JVM/pics/垃圾收集器.jpg -------------------------------------------------------------------------------- /02 JVM/pics/复制算法.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/02 JVM/pics/复制算法.jpg -------------------------------------------------------------------------------- /02 JVM/pics/对象创建过程.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/02 JVM/pics/对象创建过程.png -------------------------------------------------------------------------------- /02 JVM/pics/指针访问对象.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/02 JVM/pics/指针访问对象.png -------------------------------------------------------------------------------- /02 JVM/pics/标记清除.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/02 JVM/pics/标记清除.jpg -------------------------------------------------------------------------------- /02 JVM/pics/虚拟机栈帧.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/02 JVM/pics/虚拟机栈帧.png -------------------------------------------------------------------------------- /06 计算机网络/pics/三次握手.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/06 计算机网络/pics/三次握手.png -------------------------------------------------------------------------------- /06 计算机网络/pics/响应报文.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/06 计算机网络/pics/响应报文.png -------------------------------------------------------------------------------- /06 计算机网络/pics/四次挥手.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/06 计算机网络/pics/四次挥手.png -------------------------------------------------------------------------------- /06 计算机网络/pics/请求报文.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/06 计算机网络/pics/请求报文.png -------------------------------------------------------------------------------- /07 操作系统/pics/共享存储.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/07 操作系统/pics/共享存储.png -------------------------------------------------------------------------------- /07 操作系统/pics/消息传递.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/07 操作系统/pics/消息传递.png -------------------------------------------------------------------------------- /07 操作系统/pics/磁盘结构.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/07 操作系统/pics/磁盘结构.jpg -------------------------------------------------------------------------------- /07 操作系统/pics/管道通信.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/07 操作系统/pics/管道通信.png -------------------------------------------------------------------------------- /07 操作系统/pics/进程的状态.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/07 操作系统/pics/进程的状态.png -------------------------------------------------------------------------------- /07 操作系统/pics/进程通信.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/07 操作系统/pics/进程通信.png -------------------------------------------------------------------------------- /02 JVM/pics/内存堆按年代分.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/02 JVM/pics/内存堆按年代分.png -------------------------------------------------------------------------------- /02 JVM/pics/双亲委派实现.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/02 JVM/pics/双亲委派实现.jpeg -------------------------------------------------------------------------------- /03 多线程和高并发/pics/线程状态.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/03 多线程和高并发/pics/线程状态.png -------------------------------------------------------------------------------- /06 计算机网络/pics/各层的作用.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/06 计算机网络/pics/各层的作用.png -------------------------------------------------------------------------------- /06 计算机网络/pics/对应网络协议.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/06 计算机网络/pics/对应网络协议.png -------------------------------------------------------------------------------- /07 操作系统/pics/Linux架构.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/07 操作系统/pics/Linux架构.png -------------------------------------------------------------------------------- /07 操作系统/pics/多级反馈队列.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/07 操作系统/pics/多级反馈队列.png -------------------------------------------------------------------------------- /02 JVM/pics/jdk1.8前内存结构.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/02 JVM/pics/jdk1.8前内存结构.png -------------------------------------------------------------------------------- /02 JVM/pics/jdk1.8后内存结构.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/02 JVM/pics/jdk1.8后内存结构.png -------------------------------------------------------------------------------- /02 JVM/pics/serial-old.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/02 JVM/pics/serial-old.png -------------------------------------------------------------------------------- /02 JVM/pics/stack-Frame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/02 JVM/pics/stack-Frame.png -------------------------------------------------------------------------------- /03 多线程和高并发/pics/线程池类图.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/03 多线程和高并发/pics/线程池类图.png -------------------------------------------------------------------------------- /05 设计模式/pics/Observable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/05 设计模式/pics/Observable.png -------------------------------------------------------------------------------- /06 计算机网络/pics/HTTPS C S.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/06 计算机网络/pics/HTTPS C S.png -------------------------------------------------------------------------------- /06 计算机网络/pics/TSL SSL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/06 计算机网络/pics/TSL SSL.png -------------------------------------------------------------------------------- /09 数据结构与算法/06 大数据/大数据算法.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/09 数据结构与算法/06 大数据/大数据算法.png -------------------------------------------------------------------------------- /15 工具/01 Git/pics/.git.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/15 工具/01 Git/pics/.git.png -------------------------------------------------------------------------------- /15 工具/01 Git/pics/fork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/15 工具/01 Git/pics/fork.png -------------------------------------------------------------------------------- /02 JVM/pics/parallel-old.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/02 JVM/pics/parallel-old.png -------------------------------------------------------------------------------- /02 JVM/pics/root-tracing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/02 JVM/pics/root-tracing.png -------------------------------------------------------------------------------- /02 JVM/pics/线程、主内存、工作内存.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/02 JVM/pics/线程、主内存、工作内存.webp -------------------------------------------------------------------------------- /03 多线程和高并发/pics/Syc code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/03 多线程和高并发/pics/Syc code.png -------------------------------------------------------------------------------- /06 计算机网络/pics/HTTP-HTTPS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/06 计算机网络/pics/HTTP-HTTPS.png -------------------------------------------------------------------------------- /07 操作系统/pics/Linux细分结构jpg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/07 操作系统/pics/Linux细分结构jpg.jpg -------------------------------------------------------------------------------- /08 数据库/02 Redis/pics/AOF.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/08 数据库/02 Redis/pics/AOF.png -------------------------------------------------------------------------------- /08 数据库/02 Redis/pics/RDB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/08 数据库/02 Redis/pics/RDB.png -------------------------------------------------------------------------------- /08 数据库/02 Redis/pics/缓存穿透.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/08 数据库/02 Redis/pics/缓存穿透.png -------------------------------------------------------------------------------- /10 项目/03 电商基础秒杀/notes/脑图.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/10 项目/03 电商基础秒杀/notes/脑图.png -------------------------------------------------------------------------------- /15 工具/01 Git/pics/branch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/15 工具/01 Git/pics/branch.png -------------------------------------------------------------------------------- /15 工具/01 Git/pics/git add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/15 工具/01 Git/pics/git add.png -------------------------------------------------------------------------------- /15 工具/01 Git/pics/git log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/15 工具/01 Git/pics/git log.png -------------------------------------------------------------------------------- /01 JavaSe/01 集合框架/pics/拉链法原理.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/01 JavaSe/01 集合框架/pics/拉链法原理.png -------------------------------------------------------------------------------- /01 JavaSe/01 集合框架/pics/集合框架.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/01 JavaSe/01 集合框架/pics/集合框架.png -------------------------------------------------------------------------------- /01 JavaSe/03 基础概念/pics/重写 重载.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/01 JavaSe/03 基础概念/pics/重写 重载.png -------------------------------------------------------------------------------- /03 多线程和高并发/pics/Syc method.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/03 多线程和高并发/pics/Syc method.png -------------------------------------------------------------------------------- /05 设计模式/pics/Observer_Result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/05 设计模式/pics/Observer_Result.png -------------------------------------------------------------------------------- /05 设计模式/pics/Proxy_Pattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/05 设计模式/pics/Proxy_Pattern.png -------------------------------------------------------------------------------- /06 计算机网络/pics/7层模型 四层模型 五层协议.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/06 计算机网络/pics/7层模型 四层模型 五层协议.png -------------------------------------------------------------------------------- /06 计算机网络/pics/HTTP REQUEST.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/06 计算机网络/pics/HTTP REQUEST.png -------------------------------------------------------------------------------- /06 计算机网络/pics/HTTP RESPONSE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/06 计算机网络/pics/HTTP RESPONSE.png -------------------------------------------------------------------------------- /08 数据库/01 MySQL/pics/乐观锁实现.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/08 数据库/01 MySQL/pics/乐观锁实现.jpg -------------------------------------------------------------------------------- /08 数据库/02 Redis/pics/AOF流程.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/08 数据库/02 Redis/pics/AOF流程.png -------------------------------------------------------------------------------- /08 数据库/02 Redis/pics/RDB流程.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/08 数据库/02 Redis/pics/RDB流程.png -------------------------------------------------------------------------------- /08 数据库/02 Redis/pics/Redis主从.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/08 数据库/02 Redis/pics/Redis主从.jpg -------------------------------------------------------------------------------- /08 数据库/02 Redis/pics/Redis哨兵.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/08 数据库/02 Redis/pics/Redis哨兵.jpg -------------------------------------------------------------------------------- /08 数据库/02 Redis/pics/Redis集群.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/08 数据库/02 Redis/pics/Redis集群.jpg -------------------------------------------------------------------------------- /08 数据库/02 Redis/pics/持久化恢复数据.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/08 数据库/02 Redis/pics/持久化恢复数据.png -------------------------------------------------------------------------------- /08 数据库/02 Redis/pics/缓存雪崩解决.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/08 数据库/02 Redis/pics/缓存雪崩解决.jpg -------------------------------------------------------------------------------- /09 数据结构与算法/11 数组/notes/Leetcode总结.md: -------------------------------------------------------------------------------- 1 | # 寻找数组前K个最大的数 2 | 3 | https://blog.csdn.net/zhou15755387780/article/details/81318105 -------------------------------------------------------------------------------- /10 项目/03 电商基础秒杀/pics/秒杀系统设计.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/10 项目/03 电商基础秒杀/pics/秒杀系统设计.png -------------------------------------------------------------------------------- /15 工具/01 Git/pics/conflict .png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/15 工具/01 Git/pics/conflict .png -------------------------------------------------------------------------------- /15 工具/01 Git/pics/git clone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/15 工具/01 Git/pics/git clone.png -------------------------------------------------------------------------------- /15 工具/01 Git/pics/git commit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/15 工具/01 Git/pics/git commit.png -------------------------------------------------------------------------------- /15 工具/01 Git/pics/git push.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/15 工具/01 Git/pics/git push.png -------------------------------------------------------------------------------- /15 工具/01 Git/pics/remote add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/15 工具/01 Git/pics/remote add.png -------------------------------------------------------------------------------- /01 JavaSe/03 基础概念/pics/static.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/01 JavaSe/03 基础概念/pics/static.jpg -------------------------------------------------------------------------------- /03 多线程和高并发/pics/threadLocalMap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/03 多线程和高并发/pics/threadLocalMap.png -------------------------------------------------------------------------------- /04 框架/01 Spring/pics/bean的初始化.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/04 框架/01 Spring/pics/bean的初始化.png -------------------------------------------------------------------------------- /05 设计模式/pics/JDK_Proxy_Result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/05 设计模式/pics/JDK_Proxy_Result.png -------------------------------------------------------------------------------- /07 操作系统/notes/并行、并发.md: -------------------------------------------------------------------------------- 1 | ## 1.并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生; 2 | 3 | ## 2.并行是在不同实体上的多个事件,并发是在同一实体上的多个事件; 4 | 5 | -------------------------------------------------------------------------------- /08 数据库/02 Redis/pics/Redis单副本.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/08 数据库/02 Redis/pics/Redis单副本.jpg -------------------------------------------------------------------------------- /08 数据库/02 Redis/pics/Redis哨兵2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/08 数据库/02 Redis/pics/Redis哨兵2.jpg -------------------------------------------------------------------------------- /08 数据库/02 Redis/pics/Redis完整同步.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/08 数据库/02 Redis/pics/Redis完整同步.jpg -------------------------------------------------------------------------------- /08 数据库/02 Redis/pics/redis高并发.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/08 数据库/02 Redis/pics/redis高并发.jpg -------------------------------------------------------------------------------- /08 数据库/02 Redis/pics/redis高性能.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/08 数据库/02 Redis/pics/redis高性能.jpg -------------------------------------------------------------------------------- /09 数据结构与算法/01 排序/pics/HeapSort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/09 数据结构与算法/01 排序/pics/HeapSort.gif -------------------------------------------------------------------------------- /09 数据结构与算法/01 排序/pics/HillSort.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/09 数据结构与算法/01 排序/pics/HillSort.jpg -------------------------------------------------------------------------------- /09 数据结构与算法/10 数据结构/pics/Stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/09 数据结构与算法/10 数据结构/pics/Stack.png -------------------------------------------------------------------------------- /09 数据结构与算法/10 数据结构/pics/queue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/09 数据结构与算法/10 数据结构/pics/queue.jpg -------------------------------------------------------------------------------- /18 Java8/pics/Stream Operation.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/18 Java8/pics/Stream Operation.jpg -------------------------------------------------------------------------------- /18 Java8/pics/Terminal Result.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/18 Java8/pics/Terminal Result.jpg -------------------------------------------------------------------------------- /01 JavaSe/01 集合框架/pics/LinkedList.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/01 JavaSe/01 集合框架/pics/LinkedList.png -------------------------------------------------------------------------------- /01 JavaSe/01 集合框架/pics/集合继承关系图.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/01 JavaSe/01 集合框架/pics/集合继承关系图.webp -------------------------------------------------------------------------------- /03 多线程和高并发/pics/ThreadLocal结构概览.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/03 多线程和高并发/pics/ThreadLocal结构概览.jpg -------------------------------------------------------------------------------- /04 框架/01 Spring/pics/run result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/04 框架/01 Spring/pics/run result.png -------------------------------------------------------------------------------- /08 数据库/01 MySQL/pics/master-slave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/08 数据库/01 MySQL/pics/master-slave.png -------------------------------------------------------------------------------- /08 数据库/02 Redis/pics/Redis部分重同步.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/08 数据库/02 Redis/pics/Redis部分重同步.jpg -------------------------------------------------------------------------------- /09 数据结构与算法/01 排序/pics/BubbleSort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/09 数据结构与算法/01 排序/pics/BubbleSort.gif -------------------------------------------------------------------------------- /09 数据结构与算法/01 排序/pics/BucketSort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/09 数据结构与算法/01 排序/pics/BucketSort.gif -------------------------------------------------------------------------------- /09 数据结构与算法/01 排序/pics/CountSort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/09 数据结构与算法/01 排序/pics/CountSort.gif -------------------------------------------------------------------------------- /09 数据结构与算法/01 排序/pics/MergeSort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/09 数据结构与算法/01 排序/pics/MergeSort.gif -------------------------------------------------------------------------------- /09 数据结构与算法/01 排序/pics/QuickSort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/09 数据结构与算法/01 排序/pics/QuickSort.gif -------------------------------------------------------------------------------- /09 数据结构与算法/01 排序/pics/RadixSort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/09 数据结构与算法/01 排序/pics/RadixSort.gif -------------------------------------------------------------------------------- /10 项目/03 电商基础秒杀/pics/AmqpTemplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/10 项目/03 电商基础秒杀/pics/AmqpTemplate.png -------------------------------------------------------------------------------- /10 项目/03 电商基础秒杀/pics/Direct Mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/10 项目/03 电商基础秒杀/pics/Direct Mode.png -------------------------------------------------------------------------------- /10 项目/03 电商基础秒杀/pics/Fanout mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/10 项目/03 电商基础秒杀/pics/Fanout mode.png -------------------------------------------------------------------------------- /10 项目/03 电商基础秒杀/pics/Topic mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/10 项目/03 电商基础秒杀/pics/Topic mode.png -------------------------------------------------------------------------------- /15 工具/01 Git/pics/user.name email.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/15 工具/01 Git/pics/user.name email.png -------------------------------------------------------------------------------- /16 Tomcat/pics/Tomcat Struction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/16 Tomcat/pics/Tomcat Struction.png -------------------------------------------------------------------------------- /18 Java8/pics/what stream can do.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/18 Java8/pics/what stream can do.jpg -------------------------------------------------------------------------------- /01 JavaSe/01 集合框架/pics/TreeMap_base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/01 JavaSe/01 集合框架/pics/TreeMap_base.png -------------------------------------------------------------------------------- /01 JavaSe/01 集合框架/pics/hashmap-put.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/01 JavaSe/01 集合框架/pics/hashmap-put.png -------------------------------------------------------------------------------- /01 JavaSe/03 基础概念/pics/jvm,jre,jdk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/01 JavaSe/03 基础概念/pics/jvm,jre,jdk.png -------------------------------------------------------------------------------- /03 多线程和高并发/pics/threadFactory state.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/03 多线程和高并发/pics/threadFactory state.jpg -------------------------------------------------------------------------------- /05 设计模式/pics/Spring_ObserverPattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/05 设计模式/pics/Spring_ObserverPattern.png -------------------------------------------------------------------------------- /08 数据库/02 Redis/pics/psync process.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/08 数据库/02 Redis/pics/psync process.jpg -------------------------------------------------------------------------------- /09 数据结构与算法/01 排序/pics/InsertionSort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/09 数据结构与算法/01 排序/pics/InsertionSort.gif -------------------------------------------------------------------------------- /09 数据结构与算法/01 排序/pics/SelectionSort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/09 数据结构与算法/01 排序/pics/SelectionSort.gif -------------------------------------------------------------------------------- /16 Tomcat/pics/tomcat boot process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/16 Tomcat/pics/tomcat boot process.png -------------------------------------------------------------------------------- /18 Java8/pics/Stream Operation List.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/18 Java8/pics/Stream Operation List.jpg -------------------------------------------------------------------------------- /01 JavaSe/01 集合框架/pics/ArrayList底层实现.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/01 JavaSe/01 集合框架/pics/ArrayList底层实现.png -------------------------------------------------------------------------------- /01 JavaSe/01 集合框架/pics/LinkedList类图关系.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/01 JavaSe/01 集合框架/pics/LinkedList类图关系.png -------------------------------------------------------------------------------- /01 JavaSe/03 基础概念/pics/Error&Exception.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/01 JavaSe/03 基础概念/pics/Error&Exception.png -------------------------------------------------------------------------------- /05 设计模式/pics/Observer&EventListhener.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/05 设计模式/pics/Observer&EventListhener.png -------------------------------------------------------------------------------- /08 数据库/01 MySQL/pics/Secondary Index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/08 数据库/01 MySQL/pics/Secondary Index.png -------------------------------------------------------------------------------- /08 数据库/01 MySQL/pics/clustered index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/08 数据库/01 MySQL/pics/clustered index.png -------------------------------------------------------------------------------- /01 JavaSe/01 集合框架/pics/LinkedList_remove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/01 JavaSe/01 集合框架/pics/LinkedList_remove.png -------------------------------------------------------------------------------- /04 框架/01 Spring/pics/Spring constructure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/04 框架/01 Spring/pics/Spring constructure.png -------------------------------------------------------------------------------- /04 框架/01 Spring/pics/Spring 高级 低级容器 UML.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/04 框架/01 Spring/pics/Spring 高级 低级容器 UML.jpg -------------------------------------------------------------------------------- /04 框架/02 Spring MVC/pics/DispatchServlet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/04 框架/02 Spring MVC/pics/DispatchServlet.png -------------------------------------------------------------------------------- /08 数据库/02 Redis/pics/Redis master slave.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/08 数据库/02 Redis/pics/Redis master slave.jpg -------------------------------------------------------------------------------- /09 数据结构与算法/01 排序/pics/algorithm_analysis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/09 数据结构与算法/01 排序/pics/algorithm_analysis.png -------------------------------------------------------------------------------- /09 数据结构与算法/01 排序/pics/bubbleSort_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/09 数据结构与算法/01 排序/pics/bubbleSort_example.png -------------------------------------------------------------------------------- /09 数据结构与算法/01 排序/pics/mergeSort_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/09 数据结构与算法/01 排序/pics/mergeSort_example.png -------------------------------------------------------------------------------- /09 数据结构与算法/10 数据结构/pics/TwoWayLinkedList.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/09 数据结构与算法/10 数据结构/pics/TwoWayLinkedList.png -------------------------------------------------------------------------------- /10 项目/03 电商基础秒杀/pics/RabbitMQ structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/10 项目/03 电商基础秒杀/pics/RabbitMQ structure.png -------------------------------------------------------------------------------- /01 JavaSe/01 集合框架/pics/Concurrenthashmap-ds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/01 JavaSe/01 集合框架/pics/Concurrenthashmap-ds.png -------------------------------------------------------------------------------- /01 JavaSe/01 集合框架/pics/CopyOnWriteArrayList.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/01 JavaSe/01 集合框架/pics/CopyOnWriteArrayList.png -------------------------------------------------------------------------------- /01 JavaSe/01 集合框架/pics/LinkedList_add(E e).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/01 JavaSe/01 集合框架/pics/LinkedList_add(E e).png -------------------------------------------------------------------------------- /01 JavaSe/01 集合框架/pics/TreeMap_rotateLeft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/01 JavaSe/01 集合框架/pics/TreeMap_rotateLeft.png -------------------------------------------------------------------------------- /01 JavaSe/01 集合框架/pics/TreeMap_rotateRight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/01 JavaSe/01 集合框架/pics/TreeMap_rotateRight.png -------------------------------------------------------------------------------- /01 JavaSe/03 基础概念/pics/abstract&Interface.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/01 JavaSe/03 基础概念/pics/abstract&Interface.jpg -------------------------------------------------------------------------------- /04 框架/01 Spring/pics/SpringBean lifeCycle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/04 框架/01 Spring/pics/SpringBean lifeCycle.png -------------------------------------------------------------------------------- /05 设计模式/pics/observer_pattern_uml_diagram.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/05 设计模式/pics/observer_pattern_uml_diagram.jpg -------------------------------------------------------------------------------- /09 数据结构与算法/10 数据结构/pics/Single-Linked List.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/09 数据结构与算法/10 数据结构/pics/Single-Linked List.png -------------------------------------------------------------------------------- /01 JavaSe/01 集合框架/pics/Arrylist与Collection关系.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/01 JavaSe/01 集合框架/pics/Arrylist与Collection关系.jpg -------------------------------------------------------------------------------- /09 数据结构与算法/01 排序/pics/selection_sort_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/09 数据结构与算法/01 排序/pics/selection_sort_example.png -------------------------------------------------------------------------------- /01 JavaSe/01 集合框架/pics/ConcurrentHashMap JDK1.8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/01 JavaSe/01 集合框架/pics/ConcurrentHashMap JDK1.8.png -------------------------------------------------------------------------------- /09 数据结构与算法/10 数据结构/pics/SingleCirularLinkedList.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/09 数据结构与算法/10 数据结构/pics/SingleCirularLinkedList.png -------------------------------------------------------------------------------- /09 数据结构与算法/10 数据结构/pics/TwoWayCirularLinkedList.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/09 数据结构与算法/10 数据结构/pics/TwoWayCirularLinkedList.png -------------------------------------------------------------------------------- /10 项目/03 电商基础秒杀/notes/防止超卖.md: -------------------------------------------------------------------------------- 1 | https://blog.csdn.net/tianyaleixiaowu/article/details/90036180 2 | 3 | https://blog.csdn.net/ghaohao/article/details/80360439 4 | 5 | -------------------------------------------------------------------------------- /18 Java8/pics/Stream intermediate Operation output.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuqifan1098/Java_Review/HEAD/18 Java8/pics/Stream intermediate Operation output.jpg -------------------------------------------------------------------------------- /03 多线程和高并发/notes/Unsafe.md: -------------------------------------------------------------------------------- 1 | https://www.jianshu.com/p/2e5b92d0962e 2 | 3 | https://www.cnblogs.com/gxyandwmm/p/9418915.html 4 | 5 | https://www.cnblogs.com/throwable/p/9139947.html 6 | 7 | -------------------------------------------------------------------------------- /04 框架/05 Netty/notes/简介.md: -------------------------------------------------------------------------------- 1 | netty通过Reactor模型基于多路复用器接收并处理用户请求,内部实现了两个线程池,**boss线程和work线程池**,其中**boss线程池的线程负责处理请求的accept事件**,当接收到accept事件的请求,把对应的socket封装到一个NioSocketChannel中,并交给work线程池,其中**work线程池负责请求的read和write事件** -------------------------------------------------------------------------------- /10 项目/03 电商基础秒杀/notes/Redis问题.md: -------------------------------------------------------------------------------- 1 | # 1. Redis失效怎么办 2 | 3 | 事前:尽量保证整个 **redis 集群的高可用性**,发现机器宕机尽快补上。选择**合适的内存淘汰策略**。 4 | 5 | 事中:**本地ehcache缓存 + hystrix限流&降级**,避免MySQL崩掉 6 | 7 | 事后:利用 redis **持久化机制**保存的数据尽快恢复缓存 8 | 9 | -------------------------------------------------------------------------------- /07 操作系统/notes/同步、异步.md: -------------------------------------------------------------------------------- 1 | **同步**:当一个同步调用发出后,调用者要一直等待返回结果。通知后,才能进行后续的执行。 2 | 3 | **异步**:当一个异步过程调用发出后,调用者不能立刻得到返回结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。 4 | 5 | **阻塞**:是指调用结果返回前,当前线程会被挂起,即阻塞。 6 | 7 | **非阻塞**:是指即使调用结果没返回,也不会阻塞当前线程。 -------------------------------------------------------------------------------- /03 多线程和高并发/notes/公平锁和非公平锁.md: -------------------------------------------------------------------------------- 1 | # 公平锁 2 | 3 | 4 | 5 | 公平锁,就是在并发环境中,每个线程在获取锁时会先查看此锁维护的等待队列,如果为空,或者当前线程是等待队列的第一个,就占有锁,否则就会加入到等待队列中,按照FIFO取自己。 6 | 7 | # 非公平锁 8 | 9 | 非公平锁比较粗鲁,上来就占有锁,如果尝试失败,就再采用非公平锁,可能会造成线程饥饿或反转优先级。 10 | 11 | 非公平锁的吞吐量比公平锁大 -------------------------------------------------------------------------------- /02 JVM/notes/逃逸分析.md: -------------------------------------------------------------------------------- 1 | 逃逸是指**在某个方法之内创建的对象,除了在方法体之内被引用之外,还在方法体之外被其它变量引用到;这样带来的后果是在该方法执行完毕之后,该方法中创建的对象将无法被GC回收,由于其被其它变量引用。**正常的方法调用中,方法体中创建的对象将在执行完毕之后,将回收其中创建的对象;故由于无法回收,即成为逃逸。 2 | 3 | 逃逸分析可以分析出某个对象是否永远只在某个方法、线程的范围内,并没有“逃逸”出这个范围,逃逸分析的一个结果就是对于某些未逃逸对象可以直接在栈上分配,由于该对象一定是局部的,所以栈上分配不会有问题 4 | 5 | -------------------------------------------------------------------------------- /01 JavaSe/03 基础概念/notes/什么是重载和重写.md: -------------------------------------------------------------------------------- 1 | # 什么是重载和重写 2 | 3 | - **重载**:重载发生在**同一个类**中,同名的方法如**有不同的参数列表**,则视为重载。 4 | 5 | - **重写**:重写发生在**子类与父类**之间,重写要求子类被重写方法和父类被重写方法**有相同的返回类型**。 6 | 7 | ![](https://raw.githubusercontent.com/wuqifan1098/picBed/master/%E9%87%8D%E5%86%99%20%E9%87%8D%E8%BD%BD.png) 8 | 9 | -------------------------------------------------------------------------------- /03 多线程和高并发/notes/可重入锁.md: -------------------------------------------------------------------------------- 1 | # 可重入锁(递归锁) 2 | 3 | 指的是同一线程外层函数获得锁后,内层递归函数仍然能获取该所的代码,在同一个线程在外层方法获取锁的时候,在进入内层方法会自动获取锁。 4 | 5 | 也就是说,**线程可以进入任何一个它已经拥有的锁所同步的代码块**。 6 | 7 | ```java 8 | public sync void method01(){ 9 | method02(); 10 | } 11 | 12 | public sync void method02(){ 13 | 14 | } 15 | ``` 16 | 17 | -------------------------------------------------------------------------------- /09 数据结构与算法/10 数据结构/notes/栈.md: -------------------------------------------------------------------------------- 1 | **栈** (stack)只允许在有序的线性数据集合的一端(称为栈顶 top)进行加入数据(push)和移除数据(pop)。因而按照 **后进先出(LIFO, Last In First Out)** 的原理运作。**在栈中,push 和 pop 的操作都发生在栈顶。** 栈常用一维数组或链表来实现,用数组实现的队列叫作 **顺序栈** ,用链表实现的队列叫作 **链式栈** 。 2 | 3 | ![](https://raw.githubusercontent.com/wuqifan1098/picBed/master/Stack.png) 4 | 5 | -------------------------------------------------------------------------------- /10 项目/03 电商基础秒杀/notes/面试问题.md: -------------------------------------------------------------------------------- 1 | # Redis和数据库一致性 2 | 3 | 秒杀商品的库存数量的一致性:系统初始化的时候,将商品数量保存到缓存中,每秒杀一次,则减redis中保存的库存数,并且秒杀请求加入消息队列,当消费消息队列中的秒杀请求时才减少数据库中的库存值,即发生秒杀时不是立即同步redis和数据库的数值,而是在处理完消息队列中的请求后才保持了redis和数据库的一致性 4 | 5 | 作者:offer+1+1 6 | 链接: 7 | 8 | # 为什么要是用消息队列以及消息队列的优缺点分析 9 | 10 | # rabbitmq 支持事务吗 -------------------------------------------------------------------------------- /10 项目/03 电商基础秒杀/notes/秒杀框架.md: -------------------------------------------------------------------------------- 1 | # 前端 2 | 3 | - Thymeleaf 4 | 5 | - Bootstrap 6 | 7 | - JQuery 8 | 9 | # 后端 10 | 11 | - SpringBoot 12 | 13 | - JSR303 14 | 15 | - MyBatis 16 | 17 | # 中间件 18 | 19 | - RabbitMQ 20 | 21 | - Redis 22 | 23 | - Druid 24 | 25 | # 实现内容 26 | 27 | 1. 分布式会话 28 | 1. 商品列表页 29 | 1. 商品详情页 30 | 1. 订单详情页 31 | 1. 系统压测 32 | 1. 缓存优化 33 | 1. 消息队列 34 | 1. 接口安全 35 | 36 | -------------------------------------------------------------------------------- /08 数据库/01 MySQL/notes/慢查询优化.md: -------------------------------------------------------------------------------- 1 | # 概述 2 | 3 |    将mysql服务器中影响数据库性能的相关SQL语句记录到日志文件,通过对这些特殊的SQL语句分析,改进以达到提高数据库性能的目的。 4 | 5 | ## 设置日志功能 6 | 7 | 关于慢查询日志,主要涉及到下面几个参数: 8 | 9 | - slow_query_log :是否开启慢查询日志功能(必填) 10 | - long_query_time :超过设定值,将被视作慢查询,并记录至慢查询日志文件中(必填) 11 | - log-slow-queries :慢查询日志文件(不可填),自动在 \data\ 创建一个 [hostname]-slow.log 文件 12 | 13 |   也就是说,只有满足以上三个条件,“慢查询功能”才可能正确开启或关闭。 14 | 15 | 16 | -------------------------------------------------------------------------------- /08 数据库/02 Redis/notes/redis 和 memcached.md: -------------------------------------------------------------------------------- 1 | # 区别 2 | 3 | 1. **redis支持更丰富的数据类型**(支持更复杂的应用场景):Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,zset,hash等数据结构的存储。**memcache支持简单的数据类型,String**。 4 | 1. Redis**支持数据的持久化**,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用,而Memecache**把数据全部存在内存之中**。 5 | 1. 集群模式:memcached**没有原生的集群模式**,需要依靠客户端来实现往集群中分片写入数据;但是 redis 目前是**原生支持 cluster 模式的**. 6 | 1. Memcached是**多线程,非阻塞IO复用的网络模型**;Redis使用**单线程的多路 IO 复用模型。** 7 | 8 | -------------------------------------------------------------------------------- /04 框架/01 Spring/notes/Spring优点.md: -------------------------------------------------------------------------------- 1 | 1. 降低了组件之间的耦合性 ,实现了软件各层之间的解耦 2 | 3 | 1. 可以使用容易提供的众多服务,如事务管理,消息服务等 4 | 5 | 1. 容器提供单例模式支持 6 | 7 | 1. 容器提供了AOP技术,利用它很容易实现如权限拦截,运行期监控等功能 8 | 9 | 1. 容器提供了众多的辅助类,能加快应用的开发 10 | 11 | 1. spring对于主流的应用框架提供了集成支持,如hibernate,JPA,Struts等 12 | 13 | 1. spring属于低侵入式设计,代码的污染极低 14 | 15 | 1. 独立于各种应用服务器 16 | 17 | 1. spring的DI机制降低了业务对象替换的复杂性 18 | 19 | 1. Spring的高度开放性,并不强制应用完全依赖于Spring,开发者可以自由选择spring的部分或全部 -------------------------------------------------------------------------------- /09 数据结构与算法/10 数据结构/notes/数组.md: -------------------------------------------------------------------------------- 1 | **数组(Array)** 是一种很常见的数据结构。它是由相同类型的元素(element)的集合所组成,并且被分配一块连续的内存来存储(与链表对比)。利用元素的索引(index)可以计算出该元素对应的存储地址。它的特点是**提供随机访问**并且容量有限。 2 | 3 | 假如数组的长度为 n。 4 | 访问:O(1)//访问特定位置的元素 5 | 插入:O(n )//最坏的情况发生在插入发生在数组的首部并需要移动所有元素时 6 | 删除:O(n)//最坏的情况发生在删除数组的开头发生并需要移动第一元素后面所有的元素时 7 | 8 | ### 数组vs链表 9 | 10 | 1. 数组使用的是连续内存空间对CPU的缓存机制友好,链表则相反。 11 | 2. 数组的大小固定,声明之后就要占用所需的连续内存空间。如果声明的数组过小的话,需要再申请一个更大的内存空间,然后将原数组拷贝进去。数组多的情况下,这将是非常耗时的。链表则天然支持动态扩容。 12 | 13 | -------------------------------------------------------------------------------- /10 项目/03 电商基础秒杀/notes/项目介绍.md: -------------------------------------------------------------------------------- 1 | 基于SpringBoot开发,访问数据库采用MyBatis,服务器验证框架JSR303 2 | 3 | 分布式部署实现了分布式Session 4 | 5 | 秒杀的业务逻辑:用户浏览商品列表,跳转商品详情,商品详情页点击秒杀按钮,如果秒杀成功,进入订单详情 6 | 7 | 实现业务逻辑后进行了一个压测,出现了什么问题,对他进行优化 8 | 9 | 对服务器进行缓存优化,出现了数据不一致,先写数据库还是先写缓存,Ngnix横向扩展 10 | 11 | 用消息队列做一个异步下单,业界常用的算法 12 | 13 | 安全方面的优化,保证系统不会宕机 14 | 15 | 学到了如何应对大并发:如何利用缓存,如何使用异步,如何编写优雅的代码 16 | 17 | 本项目是一个模拟高并发环境下基于 SpringBoot 的秒杀购物平台。为了减少对数据库的直接访问,通过 Redis 实现了缓存优化;并通过 RabbitMQ 消息中间件来接收大量的并发请求,实现异步和削峰,然后再慢慢地更新数据库。最后通过 Jmeter 压测工具,可以很好地对比优化前后的 QPS... 18 | 19 | -------------------------------------------------------------------------------- /02 JVM/notes/栈上分配和TLAB.md: -------------------------------------------------------------------------------- 1 | JVM提供了一种叫做栈上分配的概念,针对那些**作用域不会逃逸出方法的对象,在分配内存时不在将对象分配在堆内存中,而是将对象属性打散后分配在栈**(线程私有的,属于栈内存)上,这样,随着方法的调用结束,栈空间的回收就会随着将栈上分配的打散后的对象回收掉,不再给gc增加额外的无用负担,从而提升应用程序整体的性能 2 | 3 | ### 线程私有分配区TLAB 4 | 5 | 对象分配在堆上,而堆是一个全局共享的区域,**当多个线程同一时刻操作堆内存分配对象空间时,就需要通过锁机制或者指针碰撞的方式确保不会申请到同一块内存**,而这带来的效果就是对象分配效率变差(尽管JVM采用了CAS的形式处理分配失败的情况),但是对于存在竞争激烈的分配场合仍然会导致效率变差。因此,在Hotspot 1.6的实现中引入了TLAB技术。 6 | 7 | TLAB全称ThreadLocalAllocBuffer,是线程的一块私有内存,如果设置了虚拟机参数 -XX:UseTLAB,在线程初始化时,**同时也会申请一块指定大小的内存,只给当前线程使用,这样每个线程都单独拥有一个Buffer,**如果需要分配内存,就在自己的Buffer上分配,这样就不存在竞争的情况,可以大大提升分配效率。 -------------------------------------------------------------------------------- /07 操作系统/notes/孤儿进程和僵尸进程.md: -------------------------------------------------------------------------------- 1 | # 概念 2 | 3 | 孤儿进程:**一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。**孤儿进程将被**init进程(进程号为1)所收养**,并由init进程对它们完成状态收集工作。 4 | 5 | 僵尸进程:**一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息**,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵尸进程。 6 | 7 | # 危害 8 | 9 | 如果进程不调用wait / waitpid的话, 那么**保留的那段信息就不会释放,其进程号就会一直被占用**,但是系统所能使用的进程号是有限的,如果大量的产生僵尸进程,将因为**没有可用的进程号而导致系统不能产生新的进程**. 此即为僵尸进程的危害,应当避免。 10 | 11 | 孤儿进程是没有父进程的进程,孤儿进程这个重任就落到了init进程身上,init进程就好像是一个民政局,专门负责处理孤儿进程的善后工作。每当出现一个孤儿进程的时候,内核就把孤 儿进程的父进程设置为init,而init进程会循环地wait()它的已经退出的子进程。这样,当一个孤儿进程凄凉地结束了其生命周期的时候,init进程就会代表党和政府出面处理它的一切善后工作。因此孤儿进程并不会有什么危害。 -------------------------------------------------------------------------------- /09 数据结构与算法/03 二叉树/notes/B树 B+树详解.md: -------------------------------------------------------------------------------- 1 | # B树 2 | 3 | ## 1. B树的定义 4 | 5 | - B树(B-tree)是对2-3树数据结构的扩展,又称为多路平衡查找树,它的一个节点可以拥有多于2个子节点的二叉查找树。与自平衡二叉查找树不同, 6 | 7 | - B树是一种自平衡树数据结构,可以保持数据排序,它能够存储数据、对其进行排序并允许以O(log n)的时间复杂度运行进行查找、顺序读取、插入和删除的数据结构 8 | 9 | - B树针对读写大数据块的系统进行了优化。B树的算法减少定位记录时所经历的中间过程,从而加快存取速度。普遍运用在数据库和文件系统。 10 | 11 | 注:有人说B-树,其实就是B树,因为B树的原英文名称为B-tree 12 | 13 | ## 2. B树的性质 14 | 15 | 一棵m阶的B 树 (m叉树)的性质 16 | 17 | - 树中每个结点最多含有m个孩子(m>=2); 18 | 19 | - 若根结点不是叶子结点,则至少有2个孩子 20 | 21 | - 除根结点和叶子结点外,其它每个结点至少有[ceil(m / 2)]个孩子 22 | 23 | - 所有叶子结点都出现在同一层,叶子结点不包含任何关键字信息 24 | 25 | - 每个非终端结点中包含有n个关键字信息,并且以升序排列 26 | 27 | -------------------------------------------------------------------------------- /01 JavaSe/03 基础概念/notes/Java和C++区别.md: -------------------------------------------------------------------------------- 1 | # Java和C++的区别 2 | 3 | - Java 是纯粹的**面向对象语言**,所有的对象都继承自 java.lang.Object,C++ 为了兼容 C 即**支持面向对象也支持面向过程**。 4 | 5 | - Java 通过虚拟机从而实现跨平台特性,但是 C++ 依赖于特定的平台。 6 | 7 | - Java **没有指针**,它的引用可以理解为安全指针,而 C++ 具有和 C 一样的**指针**。 8 | 9 | - Java 支持**自动垃圾回收**,而 C++ 需要**手动回收**。(C++11 中引入智能指针,使用引用计数法垃圾回收) 10 | 11 | - Java **不支持多重继承**,只能通过实现多个接口来达到相同目的,而 C++ **支持多重继承**。 12 | 13 | - Java 不支持操作符重载,虽然可以对两个 String 对象支持加法运算,但是这是语言内置支持的操作,不属于操作符重载,而 C++ 可以。 14 | 15 | - Java 内置了线程的支持,而 C++ 需要依靠第三方库。 16 | 17 | - Java 的 goto 是保留字,但是不可用,C++ 可以使用 goto。 18 | 19 | - Java 不支持条件编译,C++ 通过 #ifdef #ifndef 等预处理命令从而实现条件编译。 -------------------------------------------------------------------------------- /06 计算机网络/notes/Ping.md: -------------------------------------------------------------------------------- 1 | # 1、什么是 Ping 2 | 3 | ping是一种计算机网络工具,用来测试数据包能否透过IP协议到达特定主机。ping的运作原理是向目标主机传出一个ICMP echo@要求数据包,并等待接收echo回应数据包。程序会按时间和成功响应的次数估算丢失数据包率(丢包率)和数据包往返时间(网络时延,Round-trip delay time)。———— 维基百科 4 | 5 | # 2、工作原理 6 | 7 | ## ICMP协议 8 | 9 | ICMP 的全称是 Intent Control Message Protocol, 中文过来就是 **互联网控制报文协议** 10 | 11 | 网络数据包在庞大的网络中会很多各种不同情况。如果一定需要举一个例子来比如的话,用相当于兵种的侦察兵。时刻给大部队探测前方的情况。以便后方的大部队能够根据不同情况做出不同的调整。所以 ICMP 经常用于网络环境的测试。 12 | 13 | Ping发送一个ICMP(Internet Control Messages Protocol)即因特网信报控制协议;回声请求消息给目的地并报告是否收到所希望的ICMP echo (ICMP回声应答) 14 | 15 | **利用网络上机器IP地址的唯一性,给目标IP地址发送一个数据包,再要求对方返回一个同样大小的数据包来确定两台网络机器是否连接相通,时延是多少。** -------------------------------------------------------------------------------- /02 JVM/notes/JVM参数.md: -------------------------------------------------------------------------------- 1 | # JVM 参数 2 | 3 | ## GC 优化配置 4 | 5 | | 配置 | 描述 | 6 | | --- | --- | 7 | | -Xms | 初始化堆内存大小 | 8 | | -Xmx | 堆内存最大值 | 9 | | -Xmn | 新生代大小 | 10 | | -XX:PermSize | 初始化永久代大小 | 11 | | -XX:MaxPermSize | 永久代最大容量 | 12 | 13 | ## GC 类型设置 14 | 15 | | 配置 | 描述 | 16 | | --- | --- | 17 | | -XX:+UseSerialGC | 串行垃圾回收器 | 18 | | -XX:+UseParallelGC | 并行垃圾回收器 | 19 | | -XX:+UseConcMarkSweepGC | 并发标记扫描垃圾回收器 | 20 | | -XX:ParallelCMSThreads= | 并发标记扫描垃圾回收器 = 为使用的线程数量 | 21 | | -XX:+UseG1GC | G1 垃圾回收器 | 22 | 23 | ```java 24 | java -Xmx12m -Xms3m -Xmn1m -XX:PermSize=20m -XX:MaxPermSize=20m -XX:+UseSerialGC -jar java-application.jar 25 | ``` -------------------------------------------------------------------------------- /09 数据结构与算法/10 数据结构/notes/堆和栈的区别.md: -------------------------------------------------------------------------------- 1 | ### 各司其职 2 | 3 | 最主要的区别就是栈内存用来存储局部变量和方法调用。 4 | 而堆内存用来存储Java中的对象。无论是成员变量,局部变量,还是类变量,它们指向的对象都存储在堆内存中。 5 | 6 | ### 独有还是共享 7 | 8 | 栈内存归属于单个线程,每个线程都会有一个栈内存,其存储的变量只能在其所属线程中可见,即栈内存可以理解成线程的私有内存。 9 | 而堆内存中的对象对所有线程可见。堆内存中的对象可以被所有线程访问。 10 | 11 | ### 异常错误 12 | 13 | 如果栈内存没有可用的空间存储方法调用和局部变量,JVM会抛出java.lang.StackOverFlowError。 14 | 而如果是堆内存没有可用的空间存储生成的对象,JVM会抛出java.lang.OutOfMemoryError。 15 | 16 | ### 空间大小 17 | 18 | 栈的内存要远远小于堆内存,如果你使用递归的话,那么你的栈很快就会充满。如果递归没有及时跳出,很可能发生StackOverFlowError问题。 19 | 你可以通过-Xss选项设置栈内存的大小。-Xms选项可以设置堆的开始时的大小,-Xmx选项可以设置堆的最大值。 20 | 21 | 这就是Java中堆和栈的区别。理解好这个问题的话,可以对你解决开发中的问题,分析堆内存和栈内存使用,甚至性能调优都有帮助。 -------------------------------------------------------------------------------- /01 JavaSe/03 基础概念/notes/JVM,JRE,JDK.md: -------------------------------------------------------------------------------- 1 | # JDK 2 | 3 | JDK(Java Development Kit) 是 Java 语言的**软件开发工具包**(SDK)。在JDK的安装目录下有一个jre目录,里面有两个文件夹bin和lib,在这里可以认为bin里的就是jvm,lib中则是jvm工作所需要的类库,而jvm和lib合起来就称为jre。 4 | 5 | # JRE 6 | 7 | JRE(Java Runtime Environment,Java运行环境),包含JVM标准实现及Java核心类库。JRE是**Java运行环境,并不是一个开发环境**,所以没有包含任何开发工具(如编译器和调试器)。 8 | 9 | # JVM 10 | 11 | JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。 12 | 13 | ![](http://pqefpszye.bkt.clouddn.com/201904231532_638.png) 14 | 15 | JDK是整个Java的核心,包括了Java运行环境JRE、Java工具和Java基础类库。JRE是运行JAVA程序所必须的环境的集合,包含JVM标准实现及Java核心类库。JVM是整个java实现跨平台的最核心的部分,能够运行以Java语言写的程序。 -------------------------------------------------------------------------------- /08 数据库/02 Redis/notes/分布式锁.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1. Redis分布式锁怎么选值?(CVTE) 4 | 5 | 6 | 7 | # 分布式锁 8 | 9 | 分布式锁一般有三种实现方式:1. 数据库乐观锁;2. 基于Redis的分布式锁;3. 基于ZooKeeper的分布式锁。 10 | 11 | # 可靠性 12 | 13 | 首先,为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件: 14 | 15 | 1. 互斥性。在任意时刻,只有一个客户端能持有锁。 16 | 2. 不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。 17 | 3. 具有容错性。只要大部分的Redis节点正常运行,客户端就可以加锁和解锁。 18 | 4. 解铃还须系铃人。加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。 19 | 20 | # 代码实现 21 | 22 | ## 组件依赖 23 | 24 | 首先我们要通过Maven引入`Jedis`开源组件,在`pom.xml`文件加入下面的代码: 25 | 26 | ```java 27 | 28 | redis.clients 29 | jedis 30 | 2.9.0 31 | 32 | ``` -------------------------------------------------------------------------------- /04 框架/01 Spring/notes/Spring后置处理器.md: -------------------------------------------------------------------------------- 1 | ## 什么是bean post processor? 2 | 3 | bean生命周期始于加载bean的定义。通过拿到的这个定义,Spring可以构造出(`construct`嘛)bean并注入组件(因为我们常用的就是在controller里 service里使用)。之后,所有的bean都可以进行**后置处理**。这意味着我们可以实现一些自定义逻辑并调用它。并在调用bean的初始化方法(xml配置所定义的init-method 属性)之前和/或之后进行调用(当然默认的上下文环境是Spring容器)。 4 | 5 | 你不能为给定的bean类型明确指定一个bean后置处理器。每个定义的后处理器可以应用于`application context`中的所有定义的bean。后置处理器bean必须实现**org.springframework.beans.factory.config.BeanPostProcessor**接口并定义`postProcessBeforeInitialization`和`postProcessAfterInitialization`方法。第一个在调用初始化方法(init-method所指定的方法)之前被调用,第二个在调用初始化方法之后被调用。这两个方法都有两个参数: 6 | 7 | - Object:表示已处理的bean的实例。 8 | - 字符串:包含已处理的bean的名称。 9 | 10 | http://www.iocoder.cn/Spring/Bean-post-processors/ -------------------------------------------------------------------------------- /05 设计模式/notes/设计模式原则.md: -------------------------------------------------------------------------------- 1 | # 七大原则 2 | 3 | ## 1 单一职责 4 | 5 | 对类来说的,即一个类应该只负责一项职责 。如类 A 负责两个不同职责:职责 1 ,职责 2 。 6 | 当职责1需求变更而改变A时 ,可能造成职责2执行错误, 所以需要将类A的粒度分解为A1, A2。 7 | 8 | ## 2 接口隔离 9 | 10 | 客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。 11 | 12 | ## 3 依赖倒转 13 | 14 | 高层模块不应该依赖低层模块,二者都应该依赖其抽象 15 | 16 | ## 4 里氏替换 17 | 18 | **1. 子类必须完全实现父类的方法** 19 | 20 | **2. 子类可以有自己的个性** 21 | 22 | **3. 覆盖或实现父类的方法时输入参数可以被放大** 23 | 24 | **4. 覆写或实现父类的方法时输出结果可以被缩小** 25 | 26 | ## 5 开闭原则 OCP 27 | 28 | 对于**扩展是开放的**,对于**修改是关闭。** 29 | 30 | ## 6 迪米特法则 31 | 32 | 33 | 34 | ## 7 合成复用 35 | 36 | # 总结 37 | 38 | (1)单一职责原则要求实现类要职责单一; 39 | 40 | (2)里氏替换原则要求**不要去破坏继承系统**; 41 | 42 | (3)依赖倒置原则要求**面向接口编程**; 43 | 44 | (4) 接口隔离原则要求在**设计接口的时候要精简单一**; 45 | 46 | (5) 迪米特法则要求要**降低耦合**; 47 | 48 | (6)开闭原则是总纲,要求**对扩展开发,对修改关闭**。 -------------------------------------------------------------------------------- /09 数据结构与算法/10 数据结构/notes/队列.md: -------------------------------------------------------------------------------- 1 | **队列** 是 **先进先出( FIFO,First In, First Out)** 的线性表。在具体应用中通常用链表或者数组来实现,用数组实现的队列叫作 **顺序队列** ,用链表实现的队列叫作 **链式队列** 。**队列只允许在后端(rear)进行插入操作也就是 入队 enqueue,在前端(front)进行删除操作也就是出队 dequeue** 2 | 3 | ![](https://raw.githubusercontent.com/wuqifan1098/picBed/master/queue.jpg) 4 | 5 | ### 常见应用场景 6 | 7 | - **阻塞队列:** 阻塞队列可以看成在队列基础上加了阻塞操作的队列。当队列为空的时候,出队操作阻塞,当队列满的时候,入队操作阻塞。使用阻塞队列我们可以很容易实现“生产者 - 消费者“模型。 8 | - **线程池中的请求/任务队列:** 线程池中没有空闲线程时,新的任务请求线程资源时,线程池该如何处理呢?答案是将这些请求放在队列中,当有空闲线程的时候,会循环中反复从队列中获取任务来执行。队列分为无界队列(基于链表)和有界队列(基于数组)。无界队列的特点就是可以一直入列,除非系统资源耗尽,比如 :`FixedThreadPool` 使用无界队列 `LinkedBlockingQueue`。但是有界队列就不一样了,当队列满的话后面再有任务/请求就会拒绝,在 Java 中的体现就是会抛出`java.util.concurrent.RejectedExecutionException` 异常。 9 | - linux内核进程队列(按优先级排队) 10 | - 实现生活中的派对,播放器上的播放列表; 11 | - 消息队列 12 | - 等等…… -------------------------------------------------------------------------------- /08 数据库/01 MySQL/notes/数据库备份.md: -------------------------------------------------------------------------------- 1 | mysqldump 命令将数据库中的数据备份成一个文本文件。表的结构和表中的数据将存储在生成的文本文件中。 2 | 3 |   mysqldump命令的工作原理很简单。它先查出需要备份的表的结构,再在文本文件中生成一个CREATE语句。然后,将表中的所有记录转换成一条INSERT语句。然后通过这些语句,就能够创建表并插入数据。 4 | 5 | **1.使用mysqldump实现逻辑备份** 6 | 7 | ``` 8 | `#语法:``# mysqldump -h 服务器 -u用户名 -p密码 数据库名 > 备份文件.sql` `#示例:``#单库备份``mysqldump -uroot -p123456 db1 > c:/db1.sql``mysqldump -uroot -p123456 db1 table1 table2 > c:/db1-table1-table2.sql` `#多库备份``mysqldump -uroot -p123456 ``--databases db1 db2 mysql db3 > c:/db1_db2_mysql_db3.sql` `#备份所有库``mysqldump -uroot -p123456 ``--all-databases > c:/all.sql` 9 | ``` 10 | 11 | **2.恢复逻辑备份** 12 | 13 | ``` 14 | #在mysql命令下,用source命令导入备份文件: 15 | mysql> USE 数据库名; 16 | mysql> source 备份文件.sql; 17 | 18 | 注意:只能在cmd界面下执行source命令,不能在mysql工具里面执行source命令,会报错,因为cmd是直接调用mysql.exe来执行命令的。 19 | ``` 20 | 21 | -------------------------------------------------------------------------------- /04 框架/03 MyBatis/notes/mybatis概述.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1.请介绍一下Mybatis的两级缓存(cvte) 4 | 5 | 6 | 7 | ## 2. 请说出Mybatis的${}和#{}的区别(cvte) 8 | 9 | 会将传入的内容当做**字符串,**而$会直接将**传入值**拼接在sql语句中. 10 | 11 | ## 3. 什么是SQL注入。(cvte) 12 | 13 | ​ 就是通过**把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。** 14 | 15 | ​ 具体来说,它是利用现有应用程序,将(恶意)的SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。 16 | 17 | https://blog.csdn.net/woainiqazwsx123/article/details/82707725 18 | 19 | # 一、Mybatis介绍 20 | 21 | MyBatis是一个支持**普通SQL查询**,**存储过程**和**高级映射**的优秀**持久层框架**。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装。MyBatis可以使用简单的**XML或注解**用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。 22 | 23 | ## MyBatis的缓存 24 | 25 | MyBatis的缓存分为一级缓存和二级缓存, 26 | 一级缓存放在session里面,默认就有,二级缓存放在它的命名空间里,默认是打开的, 27 | 使用二级缓存属性类需要实现Serializable序列化接口(可用来保存对象的状态),可在它的映射文件中配置 28 | 29 | -------------------------------------------------------------------------------- /01 JavaSe/03 基础概念/notes/Java 各版本的新特性.md: -------------------------------------------------------------------------------- 1 | ## [Java 各版本的新特性](https://cyc2018.github.io/CS-Notes/#/notes/Java 基础?id=java-各版本的新特性) 2 | 3 | **New highlights in Java SE 8** 4 | 5 | 1. Lambda Expressions 6 | 2. Pipelines and Streams 7 | 3. Date and Time API 8 | 4. Default Methods 9 | 5. Type Annotations 10 | 6. Nashhorn JavaScript Engine 11 | 7. Concurrent Accumulators 12 | 8. Parallel operations 13 | 9. PermGen Error Removed 14 | 15 | **New highlights in Java SE 7** 16 | 17 | 1. Strings in Switch Statement 18 | 2. Type Inference for Generic Instance Creation 19 | 3. Multiple Exception Handling 20 | 4. Support for Dynamic Languages 21 | 5. Try with Resources 22 | 6. Java nio Package 23 | 7. Binary Literals, Underscore in literals 24 | 8. Diamond Syntax 25 | 9. [Difference between Java 1.8 and Java 1.7?](http://www.selfgrowth.com/articles/difference-between-java-18-and-java-17) 26 | 10. [Java 8 特性](http://www.importnew.com/19345.html) -------------------------------------------------------------------------------- /06 计算机网络/notes/流量控制和拥塞控制.md: -------------------------------------------------------------------------------- 1 | # TCP 流量控制 2 | 3 | 流量控制是为了**控制发送方发送速率**,保证接收方来得及接收。 4 | 5 | 接收方发送的确认报文中的窗口字段可以用来控制发送方窗口大小,从而影响发送方的发送速率。例如将窗口字段设置为 0,则发送方不能发送数据。 6 | 7 | # TCP 拥塞控制 8 | 9 | 原理: 10 | 11 | - 在某段时间,若对**网络中某资源的需求超过了该资源所能提供的可用部分**,网络的性能就要变坏——产生拥塞(congestion)。 12 | - 出现资源拥塞的条件:**对资源需求的总和 > 可用资源**; 13 | - 若网络中有许多资源同时产生拥塞,网络的性能就要明显变坏,整个网络的吞吐量将随输入负荷的增大而下降。 14 | 15 | 如果网络出现拥塞,分组将会丢失,此时发送方会继续重传,从而导致网络拥塞程度更高。因此当出现拥塞时,应当控制发送方的速率。这一点和流量控制很像,但是出发点不同。流量控制是为了让接收方能来得及接受,而拥塞控制是为了**降低整个网络的拥塞程度**。 16 | 17 | TCP 主要通过四种算法来进行拥塞控制:**慢开始、拥塞避免、快重传、快恢复**。发送方需要维护有一个叫做拥塞窗口(cwnd)的状态变量。注意拥塞窗口与发送方窗口的区别,拥塞窗口只是一个状态变量,实际决定发送方能发送多少数据的是发送方窗口。 18 | 19 | # 流量控制和拥塞控制区分 20 | 21 | - 拥塞控制是一个全局性的过程,涉及到所有的主机、所有的路由器,以及与降低网络传输性能有关的所有因素。 22 | - 流量控制往往指在给定的发送端和接收端之间的点对点通信量的控制。 23 | - 流量控制所要做的就是抑制发送端发送数据的速率,以便使接收端来得及接收。 24 | - 流量控制属于通信双方协商;拥塞控制涉及通信链路全局。 25 | - 流量控制需要通信双方各维护一个发送窗、一个接收窗,对任意一方,接收窗大小由自身决定,发送窗大小由接收方响应的TCP报文段中窗口值确定;拥塞控制的拥塞窗口大小变化由试探性发送一定数据量数据探查网络状况后而自适应调整。 -------------------------------------------------------------------------------- /08 数据库/01 MySQL/notes/MySQL实践.md: -------------------------------------------------------------------------------- 1 | # 1. 如何解决秒杀的性能问题和超卖的讨论 2 | 3 | 抢订单环节一般会带来2个问题: 4 | 5 |   1、高并发 6 | 7 |   比较火热的秒杀在线人数都是10w起的,如此之高的在线人数对于网站架构从前到后都是一种考验。 8 | 9 |   2、超卖 10 | 11 |   任何商品都会有数量上限,如何避免成功下订单买到商品的人数不超过商品数量的上限,这是每个抢购活动都要面临的难题 12 | 13 | ## 解决方案1 14 | 15 |   将存库MySQL前移到Redis中,**所有的写操作放到内存中,由于Redis中不存在锁故不会出现互相等待,并且由于Redis的写性能和读性能都远高于MySQL,这就解决了高并发下的性能问题**。然后通过队列等异步手段,将变化的数据**异步写入到DB中**。 16 | 17 |   优点:解决性能问题 18 | 19 |   缺点:没有解决超卖问题,同时由于异步写入DB,存在某一时刻DB和Redis中数据不一致的风险。 20 | 21 | ## 解决方案2 22 | 23 |   **引入队列,然后将所有写DB操作在单队列中排队,完全串行处理**。当达到库存阀值的时候就不在消费队列,并关闭购买功能。这就解决了超卖问题。 24 | 25 |   优点:解决超卖问题,略微提升性能。 26 | 27 |   缺点:性能受限于队列处理机处理性能和DB的写入性能中最短的那个,另外多商品同时抢购的时候需要准备多条队列。 28 | 29 | ## 解决方案3 30 | 31 |   **将提交操作变成两段式,先申请后确认。然后利用Redis的原子自增操作(相比较MySQL的自增来说没有空洞),同时利用Redis的事务特性来发号,保证拿到小于等于库存阀值的号的人都可以成功提交订单。**然后数据异步更新到DB中。 32 | 33 |   优点:解决超卖问题,库存读写都在内存中,故同时解决性能问题。 34 | 35 |   缺点:由于异步写入DB,可能存在数据不一致。另可能存在少买,也就是如果拿到号的人不真正下订单,可能库存减为0,但是订单数并没有达到库存阀值。 -------------------------------------------------------------------------------- /17 中间件/01 消息队列/notes/消息队列选型.md: -------------------------------------------------------------------------------- 1 | # 常见的消息队列对比 2 | 3 | | 对比方向 | 概要 | 4 | | -------- | ------------------------------------------------------------ | 5 | | 吞吐量 | **万级**的 ActiveMQ 和 RabbitMQ 的吞吐量(ActiveMQ 的性能最差)要比**十万级甚至是百万级**的 RocketMQ 和 Kafka 低一个数量级。 | 6 | | 可用性 | 都可以实现高可用。ActiveMQ 和 RabbitMQ 都是**基于主从架构实现高可用性**。RocketMQ 基于分布式架构。 kafka 也是分布式的,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用 | 7 | | 时效性 | RabbitMQ 基于erlang开发,所以并发能力很强,性能极其好,**延时很低,达到微秒级**。其他三个都是 ms 级。 | 8 | | 功能支持 | 除了 Kafka,其他三个功能都较为完备。 **Kafka 功能较为简单,主要支持简单的MQ功能**,在大数据领域的实时计算以及日志采集被大规模使用,是事实上的标准 | 9 | | 消息丢失 | ActiveMQ 和 RabbitMQ 丢失的可能性非常低, RocketMQ 和 Kafka 理论上不会丢失。 | 10 | 11 | ## 总结 12 | 13 | RabbitMq比kafka成熟,在可用性上,稳定性上,可靠性上,RabbitMq超过kafka 14 | 15 | Kafka设计的初衷就是处理日志的,可以看做是一个日志系统,针对性很强,所以它并没有具备一个成熟MQ应该具备的特性 16 | 17 | Kafka的性能(吞吐量、tps)比RabbitMq要强,这篇文章的作者认为,两者在这方面没有可比性。 18 | 19 | 作者:神一样的编程 20 | 21 | 链接:https://juejin.im/post/5b9a0f75e51d450e8b1392b8 22 | 23 | -------------------------------------------------------------------------------- /10 项目/03 电商基础秒杀/notes/第七章 安全优化.md: -------------------------------------------------------------------------------- 1 | # 秒杀接口地址隐藏 2 | 3 | 思路:秒杀开始之前,先去请求接口获取秒杀地址 4 | 5 | 1. 接口改造,带上PathVariable参数 6 | 7 | 2. 添加生成地址的接口 8 | 9 | 3. 秒杀收到请求,先验证PathVariable 10 | 11 | getmiaoshapath 12 | 13 | 生成UUUID 14 | 15 | 验证path,失败返回非法请求 16 | 17 | # 数学公式验证码 18 | 19 | 思路:**点击秒杀之前,先输入验证码,分散用户的请求** 20 | 21 | 1. 添加生成验证码的接口 22 | 2. 在获取秒杀路径的时候,验证验证码 23 | 3. ScriptEngine使用 24 | 25 | ```java 26 | generateVerifyCode(Random rdm){ 27 | 28 | int num1 = rdm.nextInt(10); 29 | int num2 = rdm.nextInt(10); 30 | int num3 = rdm.nextInt(10); 31 | char op1 = ops[rdm.nextInt(3)]; 32 | char op1 = ops[rdm.nextInt(3)]; 33 | String exp = "" + num1 + op1 + num2 + op2 + num3; 34 | return exp; 35 | } 36 | ``` 37 | 38 | # 接口防刷 39 | 40 | 思路:对接口做限流 41 | 42 | 查询访问路径 43 | 44 | 加上URI和用户ID 45 | 46 | 如果访问次数为空,**设置限定访问次数5** 47 | 48 | 小于5,加一 49 | 50 | 大于5,返回访问太频繁 51 | 52 | 1. 加拦截器 53 | 54 | extends HandlerInterceptorAdapter 55 | 56 | ThreadLocal useholder 和当前线程绑定 57 | 58 | -------------------------------------------------------------------------------- /01 JavaSe/03 基础概念/notes/super.md: -------------------------------------------------------------------------------- 1 | ## super 2 | 3 | - 访问父类的构造函数:可以使用 super() 函数访问父类的构造函数,从**而委托父类完成一些初始化的工作**。 4 | - 访问父类的成员:如果子类重写了父类的某个方法,可以通过使用 super 关键字来引用父类的方法实现。 5 | 6 | ```java 7 | public class SuperExample { 8 | 9 | protected int x; 10 | protected int y; 11 | 12 | public SuperExample(int x, int y) { 13 | this.x = x; 14 | this.y = y; 15 | } 16 | 17 | public void func() { 18 | System.out.println("SuperExample.func()"); 19 | } 20 | } 21 | public class SuperExtendExample extends SuperExample { 22 | 23 | private int z; 24 | 25 | public SuperExtendExample(int x, int y, int z) { 26 | super(x, y); 27 | this.z = z; 28 | } 29 | 30 | @Override 31 | public void func() { 32 | super.func(); 33 | System.out.println("SuperExtendExample.func()"); 34 | } 35 | } 36 | SuperExample e = new SuperExtendExample(1, 2, 3); 37 | e.func(); 38 | SuperExample.func() 39 | SuperExtendExample.func() 40 | ``` -------------------------------------------------------------------------------- /05 设计模式/notes/抽象工厂模式.md: -------------------------------------------------------------------------------- 1 | # 抽象工厂模式 2 | 3 | 抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 4 | 5 | 在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。 6 | 7 | ## 介绍 8 | 9 | **意图:**提供一个**创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类**。 10 | 11 | **主要解决:**主要解决接口选择的问题。 12 | 13 | **何时使用:**系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。 14 | 15 | **如何解决:**在一个产品族里面,定义多个产品。 16 | 17 | **关键代码:**在一个工厂里聚合多个同类产品。 18 | 19 | **应用实例:**工作了,为了参加一些聚会,肯定有两套或多套衣服吧,比如说有商务装(成套,一系列具体产品)、时尚装(成套,一系列具体产品),甚至对于一个家庭来说,可能有商务女装、商务男装、时尚女装、时尚男装,这些也都是成套的,即一系列具体产品。假设一种情况(现实中是不存在的,要不然,没法进入共产主义了,但有利于说明抽象工厂模式),在您的家中,某一个衣柜(具体工厂)只能存放某一种这样的衣服(成套,一系列具体产品),每次拿这种成套的衣服时也自然要从这个衣柜中取出了。用 OOP 的思想去理解,所有的衣柜(具体工厂)都是衣柜类的(抽象工厂)某一个,而每一件成套的衣服又包括具体的上衣(某一具体产品),裤子(某一具体产品),这些具体的上衣其实也都是上衣(抽象产品),具体的裤子也都是裤子(另一个抽象产品)。 20 | 21 | **优点:**当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。 22 | 23 | **缺点:**产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。 24 | 25 | **使用场景:** 1、QQ 换皮肤,一整套一起换。 2、生成不同操作系统的程序。 26 | 27 | **注意事项:**产品族难扩展,产品等级易扩展。 -------------------------------------------------------------------------------- /12 HR常问/非科班.md: -------------------------------------------------------------------------------- 1 | # 为什么不从事自己的专业工作而来编程 2 | 3 | 对于第一个问题,我的考虑是这样的:在我的专业领域,我已经做了3年了,对整个领域的发展现状和前景都有了全面而深入的了解,并且在此领域中也做出了一些成绩,例如.... 。(表明你在这个领域是可以做出成绩的,而且你还可以深入的研究以及你的强大的学习能力和研究能力)但是目前来看,这个领域相比较xx(想从事的方向)发展上存在xx缺陷,而我本身对xx有强烈的兴趣,并且根据我的能力积累,我有想当的实力去挑战这个方向,并且有很大信心在这个方向上作出成绩。 4 | 5 | 链接:https://www.nowcoder.com/discuss/122463?type=2&order=0&pos=26&page=2 6 | 7 | # 另一个是你觉得你比计算机出身的有什么优势? 8 | 9 | (1)从广度上说,在整个学习生涯中,有关xx(想从事的方向)的知识,通过大量的自学,我已经基本全面的掌握,只是可能在1~2门(你的弱项)功课上,我了解的相对较少,因此从广度上说,我和科班出身有一定的差距,但是并不明显; 10 | (2)从深度上说,整个学习过程中,因为我本身具备良好的学习能力(通过科研能力举例说明),因此对核心的知识研究都非常深入(举例说明你在哪些知识上深入研究了,其实就是我列出的知识点),而且对不同方向的知识点和科目之间的联系和异同也做了大量的研究,因此从知识的深度上来说,与科班相比,并不弱势,甚至可以说超过了很多科班的人(如果你确实准备到位了,这句话就是名副其实,如果不到位,那么前面的科研能力的佐证也说明了这个问题) 11 | (3)从学习能力和研究能力来说,平时的科研活动中,我也通过科研锻炼了良好的学习能力(举例说明),在复习的过程中,我也是全程自学,因此学习能力非常强悍;科研过程中,也做出了很多成绩(举例说明),通过科研,也锻炼了我强大的研究能力。 12 | 因此,从广度上说,我可能稍弱于科班,从深度上,丝毫不逊色于科班,甚至略强于科班,从学习能力和科研能力来说,自学证明了我的学习能力,科研的成绩证明了我的研究能力,综合来看,我后期只需要在知识的广度上下功夫就可以了。 13 | 这是我的思考。你可以参考一下。 14 | 15 | 链接:https://www.nowcoder.com/discuss/122463?type=2&order=0&pos=26&page=2 16 | -------------------------------------------------------------------------------- /07 操作系统/notes/硬链接、软链接.md: -------------------------------------------------------------------------------- 1 | ## Linux中软链接和硬链接的区别 2 | 3 | 我们知道文件都有文件名与数据,这在 Linux 上被分成两个部分:用户数据 (user data) 与元数据 (metadata)。 4 | 5 | - 用户数据,即文件数据块 (data block),数据块是记录文件真实内容的地方; 6 | - 元数据,则是文件的附加属性,如文件大小、创建时间、所有者等信息; 7 | 8 | 在 Linux 中,元数据中的 inode 号(inode 是文件元数据的一部分但其并不包含文件名,inode 号即索引节点号)才是 \文件的唯一标识而非文件名。文件名仅是为了方便人们的记忆和使用,系统或程序通过 inode 号寻找正确的文件数据块 9 | 10 | 为解决文件的共享使用,Linux 系统引入了两种链接:硬链接 (hard link) 与软链接(又称符号链接,即 soft link 或 symbolic link)。链接为 Linux 系统解决了文件的共享使用,还带来了隐藏文件路径、增加权限安全及节省存储等好处。若一个 inode 号对应多个文件名,则称这些文件为 硬链接。换言之,硬链接就是同一个文件使用了多个别名。 11 | 12 | 由于硬链接是有着相同 inode 号仅文件名不同的文件,因此硬链接存在以下几点特性: 13 | 14 | - 文件有相同的 inode 及 data block; 15 | - 只能对已存在的文件进行创建; 16 | - 不能交叉文件系统进行硬链接的创建; 17 | - 不能对目录进行创建,只可对文件创建; 18 | - 删除一个硬链接文件并不影响其他有相同 inode 号的文件。 19 | 20 | ln -s source dist # 建立软连接 ln source dist # 建立硬连接 21 | 22 | - 硬链接: 与普通文件没什么不同,inode 都指向同一个文件在硬盘中的区块。建立硬链接时,链接文件和被链接文件必须位于同一个文件系统中,并且不能建立指向目录的硬链接 23 | - 软链接: 保存了其代表的文件的绝对路径,是另外一种文件,在硬盘上有独立的区块,访问时替换自身路径。(简单地理解为 Windows 中常见的快捷方式) 24 | 25 | https://github.com/zaiyunduan123/Java-Summarize/blob/master/notes/os/Linux.md -------------------------------------------------------------------------------- /02 JVM/notes/内存泄漏和内存溢出.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1. 内存碎片简单讲讲,有内存碎片哪里不好(字节) 4 | 5 | ## 2.内存溢出有哪些情况(同程艺龙) 6 | 7 | 堆内存溢出 8 | 9 | 方法区内存溢出 10 | 11 | 线程栈溢出 12 | 13 | 14 | 15 | # 内存泄露 16 | 17 | 是指程序在申请内存后,**无法释放已申请的内存空间**,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。**被分配的对象可达但已无用,可用内存越来越少。** 18 | 19 | 在 Java 中,使用**可达性分析算法**判断对象是否存活的。在这个有向图中,根顶点可达的对象都是有效对象,GC将不回收这些对象。如果某个对象 (连通子图)与这个根顶点不可达(注意,该图为有向图),那么我们认为这个(这些)对象**不再被引用**,可以被GC回收。内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点 20 | 21 | - 这些对象是**可达的**,即在有向图中,存在通路可以与其相连; 22 | - 这些对象是**无用的**,即程序以后不会再使用这些对象。 23 | 24 | 内存泄漏的两种情况:一是堆中**申请的内存没释放**;二是**对象已不再使用,但还在内存中保留着**。 25 | 26 | # 内存溢出 27 | 28 | 程序要求的内存**超出了系统所能分配的范围**(比如:栈满还入栈 出现上溢,栈空还出栈 出现下溢) 29 | 30 | 指你申请了10个字节的空间,但是你在这个空间写入11或以上字节的数据,就是溢出。 31 | 32 | 可以看出内存泄漏是内存溢出的一种诱因,但不是唯一因素。 33 | 34 | ## 堆内存溢出 35 | 36 | ## 方法区内存溢出 37 | 38 | ## 线程栈溢出 39 | 40 | ## 内存溢出的解决方案 41 | 42 | 1.修改JVM启动参数,直接增加内存。(-Xms,-Xms参数一定不要忘记加) 43 | 44 | 2.检查错误日志,查看“OutOfMemory”错误前是否有其他异常或错误。 45 | 46 | 3.对代码进行走查和分析,找出可能发生内存溢出的位置。 47 | 48 | https://blog.csdn.net/qian520ao/article/details/78952895 49 | 50 | # 内存碎片 51 | 52 | -------------------------------------------------------------------------------- /09 数据结构与算法/06 大数据/TOP K问题.md: -------------------------------------------------------------------------------- 1 | # 方案1: HashMap + Heap 2 | 3 | 用一个 HashMap,存放所有元素出现的次数,用一个小根堆,容量为k,存放目前出现过的最频繁的k个元素, 4 | 5 | 1. 每次从数据流来一个元素,如果在HashMap里已存在,则把对应的计数器增1,如果不存在,则插入,计数器初始化为1 6 | 7 | 1. 在堆里查找该元素,如果找到,把堆里的计数器也增1,并调整堆;如果没有找到,把这个元素的次数跟堆顶元素比较,如果大于堆丁元素的出现次数,则把堆丁元素替换为该元素,并调整堆 8 | 9 | 1. 空间复杂度O(n)。HashMap需要存放下所有元素,需要O(n)的空间,堆需要存放k个元素,需要O(k)的空间,跟O(n)相比可以忽略不急,总的时间复杂度是O(n) 10 | 11 | 1. 时间复杂度O(n)。每次来一个新元素,需要在HashMap里查找一下,需要O(1)的时间;然后要在堆里查找一下,O(k)的时间,有可能需要调堆,又需要O(logk)的时间,总的时间复杂度是O(n(k+logk)),k是常量,所以可以看做是O(n)。 12 | 13 | 如果元素数量巨大,单机内存存不下,怎么办? 有两个办法,见方案2和3。 14 | 15 | # 方案2: 多机HashMap + Heap 16 | 17 | - 可以把数据进行分片。假设有8台机器,第1台机器只处理hash(elem)%8==0的元素,第2台机器只处理hash(elem)%8==1的元素,以此类推。 18 | - 每台机器都有一个HashMap和一个 Heap, 各自独立计算出 top k 的元素 19 | - 把每台机器的Heap,通过网络汇总到一台机器上,将多个Heap合并成一个Heap,就可以计算出总的 top k 个元素了 20 | 21 | # 方案3: Count-Min Sketch + Heap 22 | 23 | # 方案4: Lossy Counting 24 | 25 | Lossy Couting 算法流程: 26 | 27 | 1. 建立一个HashMap,用于存放每个元素的出现次数 28 | 1. 建立一个窗口(窗口的大小由错误率决定,后面具体讨论) 29 | 1. 等待数据流不断流进这个窗口,直到窗口满了,开始统计每个元素出现的频率,统计结束后,每个元素的频率减1,然后将出现次数为0的元素从HashMap中删除 30 | 1. 返回第2步,不断循环 -------------------------------------------------------------------------------- /07 操作系统/notes/页面置换算法.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1.**页面置换算法有哪些?** 4 | 5 | - 最佳OPT 6 | - 先进先出FIFO 7 | - 最近最久未使用 LRU 8 | - 最近未使用 9 | - 时钟 10 | 11 | # 页面置换算法 12 | 13 | 在程序运行过程中,若其所要访问的页面不在内存而需要把它们调入内存,但是**内存已无空闲空间时,系统必须从内存中调出一个页面到磁盘对换区中**,并且将程序所需要的页面调入内存中。页面置换算法的主要目标是使页面置换频率最低(也可以说缺页率最低)。 14 | 15 | ## 1. 最佳(Optimal) 16 | 17 | 所选择的被换出的页面将是**最长时间内不再被访问**,通常可以保证获得最低的缺页率。 18 | 19 | 是一种理论上的算法,因为无法知道一个页面多长时间会被再访问到。 20 | 21 | 举例:一个系统为某进程分配了三个物理块,并有如下页面引用序列: 22 | 23 | 7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1 24 | 25 | 进程运行时,先将 7,0,1 三个页面装入内存。当进程要访问页面 2 时,产生缺页中断,会将页面 7 换出,因为页面 7 再次被访问的时间最长。 26 | 27 | ## 2. 先进先出(FIFO) 28 | 29 | 所选择换出的页面是**最先进入的页面**。 30 | 31 | 该算法会将那些经常被访问的页面也被换出,从而使缺页率升高。 32 | 33 | ## 3. 最近最久未使用(LRU, Least Recently Used) 34 | 35 | 虽然无法知道将来要使用的页面情况,但是可以知道过去使用页面的情况。LRU 将最近最久未使用的页面换出。 36 | 37 | 可以**用栈来实现该算法**,栈中存储页面的页面号。当进程访问一个页面时,将**该页面的页面号从栈移除**,并将它压入栈顶。这样,**最近被访** 38 | 39 | **问的页面的页面号总是在栈顶,而最近最久未使用的页面的页面号总是在栈底。** 40 | 41 | 因为每次访问都需要更新链表,因此这种方式实现的 LRU 代价很高。 42 | 43 | ## 4. 时钟(Clock) 44 | 45 | Clock 页面置换算法需要用到一个访问位,当一个页面被访问时,将访问为置为 1。 46 | 47 | 首先,将内存中的所有页面链接成一个循环队列,当缺页中断发生时,检查当前指针所指向页面的访问位,如果访问位为 0,就将该页面换出;否则 48 | 49 | 将该页的访问位设置为 0,给该页面第二次的机会,移动指针继续检查。 -------------------------------------------------------------------------------- /05 设计模式/notes/简单工厂模式.md: -------------------------------------------------------------------------------- 1 | # 介绍 2 | 3 | **意图:**定义一个创建对象的接口,**让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行**。 4 | 5 | **主要解决:**主要解决接口选择的问题。 6 | 7 | **何时使用:**我们明确地计划不同条件下创建不同实例时。 8 | 9 | **如何解决:**让其子类实现工厂接口,返回的也是一个抽象的产品。 10 | 11 | **关键代码:**创建过程在其子类执行。 12 | 13 | **应用实例:** 1、您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现。 2、Hibernate 换数据库只需换方言和驱动就可以。 14 | 15 | **优点:** 1、一个调用者想创建一个对象,只要知道其名称就可以了。 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 3、屏蔽产品的具体实现,调用者只关心产品的接口。 16 | 17 | **缺点:**每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。 18 | 19 | **使用场景:** 1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。 2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。 3、设计一个连接服务器的框架,需要三个协议,"POP3"、"IMAP"、"HTTP",可以把这三个作为产品类,共同实现一个接口。 20 | 21 | **注意事项:**作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。 22 | 23 | # 应用案例 24 | 25 | ## 简单工厂模式 26 | 27 | 定义一个创建对象的类,**由这个类来封装实例化对象的行为**(代码) 28 | 29 | ### 思路分析 30 | 31 | ![](https://raw.githubusercontent.com/wuqifan1098/picBed/master/20190731211721.png) 32 | 33 | ## 工厂方法模式 34 | 35 | 披萨项目新的需求:客户在点披萨时,可以点不同口味的披萨,比如 北京的奶酪pizza、北京的胡椒pizza、伦敦的。。。 36 | 37 | ## 38 | 39 | -------------------------------------------------------------------------------- /01 JavaSe/03 基础概念/notes/final关键字.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1. final修饰符的作用 4 | 5 | 1. 修饰变量,**变量的引用地址不可变,但是地址中的内容可以变**。 6 | 2. 修饰方法,**方法不可被重写**,但是还是可以重载 7 | 3. 修饰类,**类不可继承**。 8 | 9 | # 一、final关键字的基本用法 10 | 11 | final关键字可以用来修饰类、方法和变量(包括成员变量和局部变量)。 12 | 13 | ## 1.修饰类 14 | 15 | 当用final修饰一个类时,表明**这个类不能被继承**。也就是说,如果一个类你永远不会让他被继承,就可以用final进行修饰。final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员方法都会被隐式地指定为final方法。 16 | 17 | 在使用final修饰类的时候,要注意谨慎选择,除非这个类真的在以后不会用来继承或者出于安全的考虑,尽量不要将类设计为final类。 18 | 19 | ## 2.修饰方法 20 | 21 | 下面这段话摘自《Java编程思想》第四版第143页: 22 | 23 |   “使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升。在最近的Java版本中,不需要使用final方法进行这些优化了。“ 24 | 25 | 因此,如果只有在想明确禁止该方法在子类中被覆盖的情况下才将方法设置为final的。 26 | 27 | ## 3.修饰变量 28 | 29 | **修饰变量是final用得最多的地方**。 30 | 31 | 对于一个final变量,如果是基本数据类型的变量,则其**数值一旦在初始化之后便不能更改**;如果是引用类型的变量,则在**对其初始化之后便不能再让其指向另一个对象**,**但该引用所指向的对象的内容是可以发生变化的**。 32 | 33 | # 二.深入理解final关键字 34 | 35 | ## 1.类的final变量和普通变量有什么区别? 36 | 37 | ## 2.被final修饰的引用变量指向的对象内容可变吗? 38 | 39 | 可变。 40 | 41 | - 对于基本类型,final 使数值不变; 42 | - 对于引用类型,final 使引用不变,也就不能引用其它对象,但是被引用的对象本身是可以修改的。 43 | 44 | ## 3.final和static 45 | 46 | static作用于成员变量用来表示**只保存一份副本**,而final的作用是用来**保证变量不可变**。 47 | 48 | 49 | -------------------------------------------------------------------------------- /07 操作系统/notes/设备管理.md: -------------------------------------------------------------------------------- 1 | # 磁盘结构 2 | - 盘面(Platter):一个磁盘有多个盘面; 3 | - 磁道(Track):盘面上的圆形带状区域,一个盘面可以有多个磁道; 4 | - 扇区(Track Sector):磁道上的一个弧段,一个磁道可以有多个扇区,它是最小的物理储存单位,目前主要有 512 bytes 与 4 K 两种大小; 5 | - 磁头(Head):与盘面非常接近,能够将盘面上的磁场转换为电信号(读),或者将电信号转换为盘面的磁场(写); 6 | - 制动手臂(Actuator arm):用于在磁道之间移动磁头; 7 | - 主轴(Spindle):使整个盘面转动。 8 | 9 | ![](https://raw.githubusercontent.com/wuqifan1098/picBed/master/%E7%A3%81%E7%9B%98%E7%BB%93%E6%9E%84.jpg) 10 | 11 | # 磁盘调度算法 12 | 13 | 当多个进程同时请求访问磁盘时,需要进行磁盘调度来控制对磁盘的访问。磁盘调度的主要目标是使磁盘的平均寻道时间最少。 14 | 15 | 读写一个磁盘块的时间的影响因素有: 16 | 17 | - 旋转时间(主轴转动盘面,使得磁头移动到适当的扇区上) 18 | - 寻道时间(制动手臂移动,使得磁头移动到适当的磁道上) 19 | - 实际的数据传输时间 20 | 21 | 其中,寻道时间最长,因此磁盘调度的主要目标是使磁盘的平均寻道时间最短。 22 | 23 | ## 1. 先来先服务(FCFS, First Come First Serverd) 24 | 25 | 根据进程请求访问磁盘的先后次序来进行调度。优点是**公平和简单**,缺点也很明显,因为未对寻道做任何优化,使**平均寻道时间可能较长**。 26 | 27 | ## 2. 最短寻道时间优先(SSTF, Shortest Seek Time First) 28 | 29 | 要求访问的磁道与当前磁头所在磁道**距离最近的优先进行调度**。这种算法并不能保证平均寻道时间最短,但是比 FCFS 好很多。 30 | 31 | ## 3. 扫描算法(SCAN) 32 | 33 | SSTF 会出现进行饥饿现象。考虑以下情况,新进程请求访问的磁道与磁头所在磁道的距离总是比一个在等待的进程来的近,那么等待的进程会一直等待下去。 34 | 35 | SCAN 算法在 SSTF 算法之上考虑了磁头的移动方向,要求所请求访问的磁道在磁头当前移动方向上才能够得到调度。因为考虑了移动方向,那么一个进程请求访问的磁道一定会得到调度。 36 | 37 | 当一个磁头自里向外移动时,移到最外侧会改变移动方向为自外向里,这种移动的规律类似于电梯的运行,因此又常称 SCAN 算法为电梯调度算法。 38 | 39 | ## 4. 循环扫描算法(CSCAN) 40 | 41 | CSCAN 对 SCAN 进行了改动,要求磁头始终沿着一个方向移动。 -------------------------------------------------------------------------------- /09 数据结构与算法/04 字符串/常用思路和API.md: -------------------------------------------------------------------------------- 1 | # substring() 方法 2 | 3 | substring() 方法返回字符串的子字符串。 4 | 5 | ### 语法 6 | 7 | ```java 8 | public String substring(int beginIndex) 9 | 10 | 或 11 | 12 | public String substring(int beginIndex, int endIndex) 13 | ``` 14 | 15 | ### 参数 16 | 17 | - **beginIndex** -- 起始索引(包括), 索引从 0 开始。 18 | - **endIndex** -- 结束索引(不包括)。 19 | 20 | # toCharArray() 方法 21 | 22 | toCharArray() 方法将字符串转换为字符数组。 23 | 24 | ### 语法 25 | 26 | ```java 27 | public char[] toCharArray() 28 | ``` 29 | 30 | ### 参数 31 | 32 | - 无 33 | 34 | ### 返回值 35 | 36 | 字符数组。 37 | 38 | # toLowerCase() 方法 39 | 40 | toLowerCase() 方法用于将大写字符转换为小写。 41 | 42 | ### 语法 43 | 44 | ```java 45 | char toLowerCase(char ch) 46 | ``` 47 | 48 | ### 参数 49 | 50 | - **ch** -- 要转换的字符。 51 | 52 | ### 返回值 53 | 54 | 返回转换后字符的小写形式,如果有的话;否则返回字符本身。 55 | 56 | # toString() 方法 57 | 58 | toString() 方法用于返回以一个字符串表示的 Number 对象值。 59 | 60 | 如果方法使用了原生的数据类型作为参数,返回原生数据类型的 String 对象值。 61 | 62 | 如果方法有两个参数, 返回用第二个参数指定基数表示的第一个参数的字符串表示形式。 63 | 64 | ### 语法 65 | 66 | 以 String 类为例,该方法有以下几种语法格式: 67 | 68 | ```java 69 | String toString() 70 | static String toString(int i) 71 | ``` 72 | 73 | ### 参数 74 | 75 | - **i** -- 要转换的整数。 76 | 77 | ### 返回值 78 | 79 | - **toString():** 返回表示 Integer 值的 String 对象。 80 | - **toString(int i):** 返回表示指定 int 的 String 对象。 81 | 82 | -------------------------------------------------------------------------------- /08 数据库/01 MySQL/notes/聚集索引和非聚集索引.md: -------------------------------------------------------------------------------- 1 | # 聚集索引 2 | 3 | 定义:数据行的物理顺序与列值(一般是主键的那一列)的逻辑顺序相同,一个表中只能拥有一个聚集索引。 4 | 5 | | 地址 | id | username | score | 6 | |-------|------|-----------|-------| 7 | | 0x01 | 1 | 小明 | 90 | 8 | | 0x02 | 2 | 小红 | 80 | 9 | | 0x03 | 3 | 小华 | 92 | 10 | | .. | .. | .. | .. | 11 | | 0xff | 256 | 小英 | 70 | 12 | 13 | 注:第一列的地址表示该行数据在磁盘中的物理地址,后面三列才是我们SQL里面用的表里的列,其中id是主键,建立了聚集索引。 14 | 15 | 结合上面的表格就可以理解这句话了吧:**数据行的物理顺序与列值的顺序相同,如果我们查询id比较靠后的数据,那么这行数据的地址在磁盘中的物理地址也会比较靠后** 16 | 17 | 聚集索引实际存放的示意图 18 | 19 | 从上图可以看出聚集索引的好处了,索引的叶子节点就是对应的数据节点(MySQL的MyISAM除外,此存储引擎的聚集索引和非聚集索引只多了个唯一约束,其他没什么区别),可以直接获取到对应的全部列的数据,而非聚集索引在索引没有覆盖到对应的列的时候需要进行二次查询,后面会详细讲。因此在查询方面,聚集索引的速度往往会更占优势。 20 | 21 | 创建聚集索引 22 | 23 | 1.创建表的时候指定主键 24 | 25 | 2.创建表后添加聚集索引 26 | 27 | # 非聚集索引 28 | 29 | 定义:该索引中**索引的逻辑顺序与磁盘上行的物理存储顺序不同**,一个表中可以拥有多个非聚集索引。 30 | 31 | 其实按照定义,除了聚集索引以外的索引都是非聚集索引,只是人们想细分一下非聚集索引,分成普通索引,唯一索引,全文索引。如果非要把非聚集索引类比成现实生活中的东西,那么非聚集索引就像新华字典的偏旁字典,他结构顺序与实际存放顺序不一定一致。 32 | 33 | # 如何解决非聚集索引的二次查询问题 34 | 35 | **复合索引(覆盖索引)** 36 | 37 | 建立两列以上的索引,即可查询复合索引里的列的数据而不需要进行回表二次查询,如index(col1, col2),执行下面的语句 38 | 39 | # 总结 40 | 41 | 1. 使用**聚集索引的查询效率要比非聚集索引的效率要高**,但是如果需要频繁去改变聚集索引的值,写入性能并不高,因为需要移动对应数据的物理位置。 42 | 1. 非聚集索引在查询的时候可以的话就避免二次查询,这样性能会大幅提升。 43 | 1. 不是所有的表都适合建立索引,只有数据量大表才适合建立索引,且建立在选择性高的列上面性能会更好。 -------------------------------------------------------------------------------- /09 数据结构与算法/03 二叉树/notes/题目总结.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1. 之字型打印二叉树(头条) 4 | 5 | 6 | 7 | ## 2. 二叉树按层打印(头条) 8 | 9 | ```java 10 | public class TreeNode{ 11 | int val; 12 | TreeNode right; 13 | TreeNode left; 14 | TreeNode(int x){ 15 | val = x; 16 | } 17 | } 18 | class solution{ 19 | public List> levelOrder(TreeNode root){ 20 | List> res = new ArrayList>(); //存放结果 21 | if(root == null){ 22 | return res; 23 | } 24 | Queue queue = new LinkedList(); //新建一个列表 25 | TreeNode cur = null; 26 | queue.add(root);//加入根节点 27 | 28 | while(!queue.isEmpty()){ 29 | ArrayList level = new ArrayList(); // 30 | int l = queue.size(); 31 | for(int i = 0; i < l; i++){ 32 | cur = queue.poll();//先弹出根节点 33 | level.add(cur.val);//加入到列表中 34 | if(cur.left != null){ 35 | queue.add(cur.left); 36 | } 37 | if(cur.right != null){ 38 | queue.add(cur.right); 39 | } 40 | }res.add(level);//每一层都是一个列表 41 | }return res; 42 | } 43 | } 44 | ``` 45 | 46 | ## 3.两个叶子节点最近的公共祖先(小红书) 47 | 48 | -------------------------------------------------------------------------------- /06 计算机网络/notes/URI.md: -------------------------------------------------------------------------------- 1 | ## URI 2 | 3 | URI 包含 URL 和 URN。 4 | 5 | - URI(Uniform Resource Identifier,统一资源标识符) 6 | - URL(Uniform Resource Locator,统一资源定位符) 7 | - URN(Uniform Resource Name,统一资源名称) 8 | 9 | ![](https://raw.githubusercontent.com/wuqifan1098/picBed/master/20190731223406.png) 10 | 11 | ## URL 统一资源定位符 12 | 13 | URL 英文全称为 Uniform Resource Locator,中文为翻译“统一资源定位符”,是用于在网络中传播和访问互联网资源的一个地址,只有通过特定的地址才能够访问的指定的资源或者网页,简而言之就是我们所说的网址,当然这样有些不太恰当,但是确实最容易被理解的,就如你必须通过 https://zhangzifan.com/about 这个 URL 地址才能访问到我泪雪博客关于子凡的页面,而通过其他的链接都是不行的,这个地址就被称之为 URL。 14 | 15 | ## URI 统一资源标识符 16 | 17 | URI 英文全称为 Uniform Resource Identifier,中文翻译为“统一资源标识符”,也可以被理解为标识、定位任何资源的字符串,子凡感觉在某些程序或者标注的地方,许多人就喜欢将 URL 和 URI 两者混淆,其实通过反正其实都非常相似,但是却也有所不同,用子凡的简而言之来描述就是 **URI包含相对地址和绝对地址,URL 就属于绝对地址**,所以 URI 包含 URI,简单的举例就是很多的网站可能都有/about 这个路径,但是不同的域名或者 IP 访问到的就是不同的资源页面,所以这就只是一个标识,并不能标识其具体未知或者唯一性。 18 | 19 | ## IRI 国际化资源标识符 20 | 21 | IRI 英文全称为 Internationalized Resource Identifiers,中文翻译为“国际化资源标识符”,和 URI 可以相提并论,其中的区别在于 URI 只能使用英文字符,所以没有办法很好的国际化兼容不同的文字语言,所以 IRI 就引入了 Unicode 字符来解决这个兼容问题,最后就有了国际化资源标识符(IRI)。 22 | 23 | ## URN 统一资源名称 24 | 25 | URN 英文全称为 Uniform Resource Name,中文翻译为“统一资源名称”,这是用于表示唯一一个实体的标识符,但是有不能给出实体的位置,用于标识持久性 Internet 资源,URN 可以提供一种机制,用于查找和检索定义特定命名空间的架构文件。尽管普通的 URL 可以提供类似的功能,但是在这方面,URN 更加强大并且更容易管理,因为 URN 可以引用多个 URL。子凡举个最简单的例子大家就明白了,那就是:磁力链接,它就是 URN 的一种实现,可以持久化的标识一个 BT 资源,资源分布式的存储在 P2P 网络中,无需中心服务器用户即可找到并下载它。 -------------------------------------------------------------------------------- /10 项目/03 电商基础秒杀/notes/第五章知识点.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | @RequestMapping(value="/to_list",produces="text/html") 4 | 5 | SpringWebContext 6 | 7 | URL 8 | 9 | 缓存更新模式 10 | 11 | spring.resouces 12 | 13 | @NeedLogin拦截器 14 | 15 | # CDN优化 16 | 17 | CDN就可以理解为分布在每个县城的火车票代售点,用户在浏览网站的时候,CDN会选择一个离用户最近的CDN边缘节点来响应用户的请求,这样海南移动用户的请求就不会千里迢迢跑到北京电信机房的服务器(假设源站部署在北京电信机房)上了。 18 | 19 | 浏览器向服务器请求数据,如果中间加上一层CDN,那么用户浏览器与服务器的交互如下: 20 | 21 | ![这里写图片描述](https://mccdn.qcloud.com/img5680ff0b3dfc4.png) 22 | 23 | 客户端浏览器先检查本地缓存是否过期,如果过期,则向CDN边缘节点发起请求,CDN边缘节点会检测用户请求数据的缓存是否过期,如果没有过期,则直接响应用户请求,此时一个完成http请求结束;如果数据已经过期,那么CDN还需要向源站发出回源请求(back to the source request),来拉取最新的数据。 24 | 25 | **CDN的典型拓扑图:** 26 | 27 | ![这里写图片描述](https://mccdn.qcloud.com/img5680ff38c14d6.png) 28 | 29 | CDN 的分流作用: 30 | 1、减少了用户的访问延时, 31 | 2、也减少了源站的负载。 32 | 33 | 但其缺点也很明显:当网站更新时,如果CDN节点上数据没有及时更新,即便用户再浏览器使用 Ctrl +F5/command+shift+r 的方式使浏览器端的缓存失效,也会因为 CDN 边缘节点没有同步最新数据而导致用户访问异常。 34 | 35 | ## CDN 缓存策略 36 | 37 | CDN 边缘节点缓存策略因服务商不同而不同,但一般都会遵循http标准协议,通过 http 响应头中的 Cache-control: max-age 的字段来设置 CDN 边缘节点数据缓存时间。 38 | 39 | CDN 缓存时间会对“回源率”产生直接的影响。 40 | 41 | - 若CDN缓存时间较短,CDN 边缘节点上的数据会经常失效,导致频繁回源,增加了源站的负载,同时也增大的访问延时; 42 | - 若CDN缓存时间太长,会带来数据更新时间慢的问题。开发者需要增对特定的业务,来做特定的数据缓存时间管理。 43 | 44 | ## CDN 缓存刷新 45 | 46 | CDN边缘节点对开发者是透明的,相比于浏览器Ctrl+F5的强制刷新来使浏览器本地缓存失效,开发者可以通过CDN服务商提供的“刷新缓存”接口来达到清理CDN边缘节点缓存的目的。这样开发者在更新数据后,可以使用“刷新缓存”功能来强制CDN节点上的数据缓存过期,保证客户端在访问时,拉取到最新的数据。 -------------------------------------------------------------------------------- /01 JavaSe/03 基础概念/notes/字符串常量池.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1.jdk1.8常量池在哪个区 (360企业安全) 4 | 5 | 堆中。 6 | 7 | 在 Java 7 之前,String Pool 被放在**运行时常量池**中,它属于永久代。而在 Java 7,String Pool 被移到堆中。这是因为永久代的空间有限,在大量使用字符串的场景下会导致 OutOfMemoryError 错误。 8 | 9 | ## 2.比如 private String a = "abc" 语句,定义了一个字符串常量,它是存储在哪里? 10 | 11 | 字符串常量池 12 | 13 | # 字符串常量池 14 | 15 | Java 中字符串对象创建有两种形式,一种为字面量形式,如 String str = "abc";,另一种就是使用 new 这种标准的构造对象的方法,如 String str = new String("abc");,这两种方式我们在代码编写时都经常使用,尤其是字面量的方式。然而这**两种实现其实存在着一些性能和内存占用的差别**。这一切都是源于 JVM 为了减少字符串对象的重复创建,其维护了一个特殊的内存,这段内存被成为**字符串常量池**或者**字符串字面量池**。 16 | 17 | ## 工作原理 18 | 19 | 当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量进行检查,如果字符串常量池中**存在相同内容的字符串对象的引用**,则将**这个引用返回**,否则**新的字符串对象被创建**,然后**将这个引用放入字符串常量池,并返回该引用**。 20 | 21 | ```java 22 | public class Test { 23 | public static void main(String[] args) { 24 | 25 | String s1 = "abc"; 26 | String s2 = "abc"; 27 | 28 | // 以上两个局部变量都存在了常量池中 29 | System.out.println(s1 == s2); // true 30 | ``` 31 | 32 | 33 | ```java 34 | // new出来的对象不会放到常量池中,内存地址是不同的 35 | String s3 = new String(); 36 | String s4 = new String(); 37 | 38 | /** 39 | * 字符串的比较不可以使用双等号,这样会比较内存地址 40 | * 字符串比较应当用equals,可见String重写了equals 41 | */ 42 | System.out.println(s3 == s4); // false 43 | System.out.println(s3.equals(s4)); // true 44 | } 45 | } 46 | ``` 47 | 48 | 常量池是用来放置一堆常量的,如果其中有相同的值,**那么就不用再次创建对象,这是为了节约内存空间,如果再次创建,就会浪费内存空间,第一个创建的字符串放在常量池中,如果要用的时候,就拿来用。** -------------------------------------------------------------------------------- /17 中间件/01 消息队列/notes/怎么保证MQ的高可用性.md: -------------------------------------------------------------------------------- 1 | # 问题 2 | 3 | 使用了MQ之后,我们肯定是希望MQ有高可用特性,因为不可能接受机器宕机了,就无法收发消息的情况。 4 | 5 | 这一块我们也是基于RabbitMQ这种经典的MQ来说明一下: 6 | 7 | RabbitMQ是比较有代表性的,因为是基于主从做高可用性的,我们就以他为例子讲解第一种MQ的高可用性怎么实现。 8 | 9 | rabbitmq有三种模式:单机模式,普通集群模式,镜像集群模式 10 | 11 | # **单机模式** 12 | 13 | 单机模式就是demo级别的,就是说只有一台机器部署了一个RabbitMQ程序。 14 | 15 | 这个会存在单点问题,宕机就玩完了,没什么高可用性可言。一般就是你本地启动了玩玩儿的,没人生产用单机模式。 16 | 17 | # **普通集群模式** 18 | 19 | 这个模式的意思就是在多台机器上启动多个rabbitmq实例。类似的master-slave模式一样。 20 | 21 | 但是创建的queue,只会放在一个master rabbtimq实例上,其他实例都同步那个接收消息的RabbitMQ元数据。 22 | 23 | 在消费消息的时候,如果你连接到的RabbitMQ实例不是存放Queue数据的实例,这个时候RabbitMQ就会从存放Queue数据的实例上拉去数据,然后返回给客户端。 24 | 25 | 总的来说,这种方式有点麻烦,没有做到真正的分布式,每次消费者连接一个实例后拉取数据,如果连接到不是存放queue数据的实例,这个时候会造成额外的性能开销。如果从放Queue的实例拉取,会导致单实例性能瓶颈。 26 | 27 | 如果放queue的实例宕机了,会导致其他实例无法拉取数据,这个集群都无法消费消息了,没有做到真正的高可用。 28 | 29 | 所以这个事儿就比较尴尬了,这就没有什么所谓的高可用性可言了,这方案主要是提高吞吐量的,就是说让集群中多个节点来服务某个queue的读写操作。 30 | 31 | # **镜像集群模式** 32 | 33 | **镜像集群模式**才是真正的rabbitmq的高可用模式,跟普通集群模式不一样的是:创建的queue无论元数据还是queue里的消息都会存在于多个实例上, 34 | 35 | 每次写消息到queue的时候,都会自动把消息到多个实例的queue里进行消息同步。 36 | 37 | 这样的话任何一个机器宕机了别的实例都可以用提供服务,这样就做到了真正的高可用了。 38 | 39 | 但是也存在着不好之处: 40 | 41 | - 性能开销过高,消息需要同步所有机器,会导致网络带宽压力和消耗很重 42 | 43 | - 扩展性低:无法解决某个queue数据量特别大的情况,导致queue无法线性拓展。 44 | 45 | 就算加了机器,那个机器也会包含queue的所有数据,queue的数据没有做到分布式存储。 46 | 47 | 对于RabbitMQ的高可用一般的做法都是开启镜像集群模式,这样起码来说做到了高可用,一个节点宕机了,其他节点可以继续提供服务。 48 | 49 | 作者:石杉的架构笔记链接:https://juejin.im/post/5d1e201ff265da1b6c5f9423 -------------------------------------------------------------------------------- /03 多线程和高并发/notes/CPU密集型和IO密集型.md: -------------------------------------------------------------------------------- 1 | # **什么是CPU密集型、IO密集型?** 2 | 3 | # CPU密集型(CPU-bound) 4 | 5 | CPU密集型也叫计算密集型,指的是系统的硬盘、内存性能相对CPU要好很多,此时,系统运作大部分的状况是CPU Loading 100%,CPU要读/写I/O(硬盘/内存),I/O在很短的时间就可以完成,而CPU还有许多运算要处理,CPU Loading很高。 6 | 7 | 在多重程序系统中,大部份时间用来做计算、逻辑判断等CPU动作的程序称之CPU bound。例如一个计算圆周率至小数点一千位以下的程序,在执行的过程当中绝大部份时间用在三角函数和开根号的计算,便是属于CPU bound的程序。 8 | 9 | CPU bound的程序一般而言CPU占用率相当高。这可能是因为任务本身不太需要访问I/O设备,也可能是因为程序是多线程实现因此屏蔽掉了等待I/O的时间。 10 | 11 | # IO密集型(I/O bound) 12 | 13 | IO密集型指的是系统的CPU性能相对硬盘、内存要好很多,此时,系统运作,大部分的状况是CPU在等I/O (硬盘/内存) 的读/写操作,此时CPU Loading并不高。 14 | 15 | I/O bound的程序一般在达到性能极限时,CPU占用率仍然较低。这可能是因为任务本身需要大量I/O操作,而pipeline做得不是很好,没有充分利用处理器能力。 16 | 17 | # CPU密集型 vs IO密集型 18 | 19 | 我们可以把任务分为计算密集型和IO密集型。 20 | 21 | 计算密集型任务的特点是要进行大量的计算,消耗CPU资源,比如计算圆周率、对视频进行高清解码等等,全靠CPU的运算能力。这种计算密集型任务虽然也可以用多任务完成,但是任务越多,花在任务切换的时间就越多,CPU执行任务的效率就越低,所以,要最高效地利用CPU,计算密集型任务同时进行的数量应当等于CPU的核心数。 22 | 23 | 计算密集型任务由于主要消耗CPU资源,因此,代码运行效率至关重要。Python这样的脚本语言运行效率很低,完全不适合计算密集型任务。对于计算密集型任务,最好用C语言编写。 24 | 25 | 第二种任务的类型是IO密集型,涉及到网络、磁盘IO的任务都是IO密集型任务,这类任务的特点是CPU消耗很少,任务的大部分时间都在等待IO操作完成(因为IO的速度远远低于CPU和内存的速度)。对于IO密集型任务,任务越多,CPU效率越高,但也有一个限度。常见的大部分任务都是IO密集型任务,比如Web应用。 26 | 27 | IO密集型任务执行期间,99%的时间都花在IO上,花在CPU上的时间很少,因此,用运行速度极快的C语言替换用Python这样运行速度极低的脚本语言,完全无法提升运行效率。对于IO密集型任务,最合适的语言就是开发效率最高(代码量最少)的语言,脚本语言是首选,C语言最差。 28 | 29 | 总之,计算密集型程序适合C语言多线程,I/O密集型适合脚本语言开发的多线程。 30 | --------------------- 31 | 作者:Java技术栈 32 | 来源:CSDN 33 | 原文:https://blog.csdn.net/youanyyou/article/details/78990156 34 | 版权声明:本文为博主原创文章,转载请附上博文链接! -------------------------------------------------------------------------------- /09 数据结构与算法/10 数据结构/notes/链表.md: -------------------------------------------------------------------------------- 1 | ### 简介 2 | 3 | **链表(LinkedList)** 虽然是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)。由于不必须按顺序存储,链表在插入和删除的时候可以达到 O(1) 的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要 O(n) 的时间,而顺序表相应的时间复杂度分别是O(logn) 和O(1)。 4 | 5 | **使用链表结构可以克服数组需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但链表不会节省空间,相比于数组会占用更多的空间,因为链表中每个节点存放的还有指向其他节点的指针。链表不具有数组随机读取的优点,但是插入删除元素的时间复杂度为O(1)** 6 | 7 | ### 分类 8 | 9 | 1. 单链表 10 | 2. 双向链表 11 | 3. 循环链表 12 | 4. 双向循环链表 13 | 14 | 假如链表中有n个元素。 15 | 访问:O(n)//访问特定位置的元素 16 | 插入删除:O(1)//必须要要知道插入元素的位置 17 | 18 | #### 单链表 19 | 20 | **单链表** 单链表是链表中结构最简单的。一个单链表的节点(Node)分为两个部分,第一个部分(data)保存或者显示关于节点的信息,另一个部分存储下一个节点的地址。最后一个节点存储地址的部分指向空值。 21 | 22 | 单向链表只可向一个方向遍历,一般查找一个节点的时候需要从第一个节点开始每次访问下一个节点,一直访问到需要的位置。而插入一个节点,对于单向链表,我们只提供在链表头插入,只需要将当前插入的节点设置为头节点,next指向原头节点即可。删除一个节点,我们将该节点的上一个节点的next指向该节点的下一个节点。 23 | 24 | ![](https://raw.githubusercontent.com/wuqifan1098/picBed/master/Single-Linked%20List.png) 25 | 26 | #### 循环链表 27 | 28 | **循环链表** 其实是一种特殊的单链表,和单链表不同的是循环链表的尾结点不是指向null,而是指向链表的头结点。 29 | 30 | ![](https://raw.githubusercontent.com/wuqifan1098/picBed/master/SingleCirularLinkedList.png) 31 | 32 | #### 双向链表 33 | 34 | **双向链表** 包含两个指针,一个prev指向前一个节点,一个next指向后一个节点,可以从两个方向遍历。 35 | 36 | ![](https://raw.githubusercontent.com/wuqifan1098/picBed/master/TwoWayLinkedList.png) 37 | 38 | #### 双向循环链表 39 | 40 | **双向循环链表** 最后一个节点的 next 指向head,而 head 的prev指向最后一个节点,构成一个环。 41 | 42 | ![](https://raw.githubusercontent.com/wuqifan1098/picBed/master/TwoWayCirularLinkedList.png) -------------------------------------------------------------------------------- /11 分布式与微服务/02 分布式/notes/分布式事务.md: -------------------------------------------------------------------------------- 1 | # 分布式事务 2 | 3 | 指事务的操作位于不同的节点上,需要保证事务的 ACID 特性。 4 | 5 | 例如在下单场景下,库存和订单如果不在同一个节点上,就涉及分布式事务。 6 | 7 | ## 2PC 8 | 9 | 两阶段提交(Two-phase Commit,2PC),通过引入协调者(Coordinator)来协调参与者的行为,并最终决定这些参与者是否要真正执行事务。 10 | 11 | ### 1. 运行过程 12 | 13 | #### 1.1 准备阶段 14 | 15 | 协调者询问参与者事务是否执行成功,参与者发回事务执行结果。 16 | 17 | ![img](https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/44d33643-1004-43a3-b99a-4d688a08d0a1.png) 18 | 19 | #### 1.2 提交阶段 20 | 21 | 如果事务在每个参与者上都执行成功,事务协调者发送通知让参与者提交事务;否则,协调者发送通知让参与者回滚事务。 22 | 23 | 需要注意的是,在准备阶段,参与者执行了事务,但是还未提交。只有在提交阶段接收到协调者发来的通知后,才进行提交或者回滚。 24 | 25 | ![img](https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/d2ae9932-e2b1-4191-8ee9-e573f36d3895.png) 26 | 27 | 28 | 29 | ### 2. 存在的问题 30 | 31 | #### 2.1 同步阻塞 32 | 33 | 所有事务参与者在等待其它参与者响应的时候都处于同步阻塞状态,无法进行其它操作。 34 | 35 | #### 2.2 单点问题 36 | 37 | 协调者在 2PC 中起到非常大的作用,发生故障将会造成很大影响。特别是在阶段二发生故障,所有参与者会一直等待,无法完成其它操作。 38 | 39 | #### 2.3 数据不一致 40 | 41 | 在阶段二,如果协调者只发送了部分 Commit 消息,此时网络发生异常,那么只有部分参与者接收到 Commit 消息,也就是说只有部分参与者提交了事务,使得系统数据不一致。 42 | 43 | #### 2.4 太过保守 44 | 45 | 任意一个节点失败就会导致整个事务失败,没有完善的容错机制。 46 | 47 | ## 本地消息表 48 | 49 | 本地消息表与业务数据表处于同一个数据库中,这样就能利用本地事务来保证在对这两个表的操作满足事务特性,并且使用了消息队列来保证最终一致性。 50 | 51 | 1. 在分布式事务操作的一方完成写业务数据的操作之后向本地消息表发送一个消息,本地事务能保证这个消息一定会被写入本地消息表中。 52 | 2. 之后将本地消息表中的消息转发到消息队列中,如果转发成功则将消息从本地消息表中删除,否则继续重新转发。 53 | 3. 在分布式事务操作的另一方从消息队列中读取一个消息,并执行消息中的操作。 54 | 55 | ![img](https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/476329d4-e2ef-4f7b-8ac9-a52a6f784600.png) -------------------------------------------------------------------------------- /09 数据结构与算法/06 大数据/预备知识点.md: -------------------------------------------------------------------------------- 1 | ## **预备知识点** 2 | 3 | **Bitmap和布隆过滤器(Bloom Filter)** 4 | 5 | [https://blog.csdn.net/zdxiq000/article/details/57626464](https://link.zhihu.com/?target=https%3A//blog.csdn.net/zdxiq000/article/details/57626464) 6 | 7 | ## **Bitmap** 8 | 9 | 我们只想知道某个元素出现过没有。**如果为每个所有可能的值分配1个bit**,32bit的int所有可能取值需要内存空间为: 10 | 11 | 2^32bit=2^29Byte=512MB 12 | 13 | 但对于海量的、取值分布很均匀的集合进行去重,Bitmap极大地压缩了所需要的内存空间。**于此同时,还额外地完成了对原始数组的排序工作**。缺点是,Bitmap对于每个元素只能记录1bit信息,如果还想完成额外的功能,恐怕只能靠牺牲更多的空间、时间来完成了。 14 | 15 | ## **Bloom Filter** 16 | 17 | 如果说Bitmap对于每一个可能的整型值,通过直接寻址的方式进行映射,相当于使用了一个哈希函数,那布隆过滤器就是引入了k(k>1)个相互独立的哈希函数,保证在给定的空间、误判率下,完成元素判重的过程。下图中是k=3时的布隆过滤器。 18 | 19 | ![img](https://pic3.zhimg.com/80/v2-38d92745c0665233c225ae39c35a1e7e_hd.jpg) 20 | 21 | 那么布隆过滤器的误差有多少?我们假设所有哈希函数散列足够均匀,散列后落到Bitmap每个位置的概率均等。 22 | 23 | ![img](https://pic1.zhimg.com/80/v2-7bccbb56a1ce6c3cfa9770b7f7974984_hd.jpg) 24 | 25 | 若以m=16nm=16n计算,Bitmap集合的大小为238bit=235Byte=32GB238bit=235Byte=32GB,此时的ε≈0.0005。并且要知道,以上计算的都是误差的上限。 26 | 27 | 布隆过滤器通过引入一定错误率,使得海量数据判重在可以接受的内存代价中得以实现。从上面的公式可以看出,随着集合中的元素不断输入过滤器中(nn增大),误差将越来越大。但是,当Bitmap的大小mm(指bit数)足够大时,比如比所有可能出现的不重复元素个数还要大10倍以上时,错误概率是可以接受的。 28 | 29 | 这里有一个google实现的布隆过滤器,我们来看看它的误判率: 30 | 31 | 在这个实现中,Bitmap的集合m、输入的原始数集合n、哈希函数k的取值都是按照上面最优的方案选取的,默认情况下保证误判率ε=0.5k<0.03≈0.55,因而此时k=5。 32 | 33 | 而还有一个很有趣的地方是,实际使用的却并不是5个哈希函数。实际进行映射时,而是分别使用了一个64bit哈希函数的高、低32bit进行循环移位。注释中包含着这个算法的论文“Less Hashing, Same Performance: Building a Better Bloom Filter”,论文中指明其对过滤器性能没有明显影响。很明显这个实现对于m>232时的支持并不好,因为当大于231−1的下标在算法中并不能被映射到。 -------------------------------------------------------------------------------- /01 JavaSe/02 IO/notes/文件读写.md: -------------------------------------------------------------------------------- 1 | # I/O操作 2 | 3 | ![img](https://img2018.cnblogs.com/blog/1157683/201811/1157683-20181108172513032-1236142535.png) 4 | 5 | ## 概念框架 6 | 7 | - 方式: 字节流 Byte 和 字符流 Char 8 | - 方向: 输入 Input 和 输出 Output ; 读 Reader 和 写 Writer 9 | - 源: 字符串 String, 数组 Array, 对象 Object, 文件 File, 通道 Channel, 管道 Pipe, 过滤器 Filter,控制台 Console, 网络 Network Link ; 一切可产生/接收数据的 Data 10 | - 性能: 带缓冲和不带缓冲的 11 | - 行为: Readable, Appendable, Closable, Flushable, Serializable/Externalizable 12 | 13 | ### 字节流 14 | 15 | ``` 16 | 字节输入流:InputStream, BufferedInputStream, FileInputStream, ByteArrayInputStream, PipedInputStream, FilterInputStream, DataInputStream, ObjectInputStream; 17 | 字节输出流: OuputStream, BufferedOuputStream, FileOuputStream, ByteArrayOuputStream, PipedOuputStream, FilterOuputStream, DataOuputStream, ObjectOuputStream, PrintStream; 18 | ``` 19 | 20 | ### 字符流 21 | 22 | ``` 23 | 字符输入流: Reader, BufferedReader, FileReader, CharArrayReader, PipedReader, FilterReader, StringReader, LineNumberReader; 24 | 字符输出流: Writer, BufferedWriter, FileWriter, CharArrayWriter, PipedWriter, FilterWriter, StringWriter, PrintWriter; 25 | ``` 26 | 27 | ### 互相转换 28 | 29 | 整个IO包实际上分为字节流和字符流,但是除了这两个流之外,还存在一组字节流-字符流的转换类。 30 | 31 | OutputStreamWriter:是Writer的子类,将输出的字符流变为字节流,即将一个字符流的输出对象变为字节流输出对象。 32 | 33 | InputStreamReader:是Reader的子类,将输入的字节流变为字符流,即将一个字节流的输入对象变为字符流的输入对象。 34 | 35 | ## 装饰器模式 36 | 37 | ​ 多个类实现同一个接口,并且这些实现类均持有一个该接口的引用,通过构造器传入,从而可以在这些实现类的基础上任意动态地组合叠加,构造出所需特性的实现来。装饰器模式可以实现数学公式/逻辑公式运算函数。 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /08 数据库/01 MySQL/notes/回表查询.md: -------------------------------------------------------------------------------- 1 | # **什么是回表查询?** 2 | 3 | 这先要从InnoDB的索引实现说起,InnoDB有两大类索引: 4 | 5 | - 聚集索引(clustered index) 6 | - 普通索引(secondary index) 7 | 8 | **InnoDB聚集索引和普通索引有什么差异?** 9 | 10 | InnoDB**聚集索引**的叶子节点存储行记录,因此, InnoDB必须要有,且只有一个聚集索引: 11 | 12 | (1)如果表定义了PK,则PK就是聚集索引; 13 | 14 | (2)如果表没有定义PK,则第一个not NULL unique列是聚集索引; 15 | 16 | (3)否则,InnoDB会创建一个隐藏的row-id作为聚集索引; 17 | 18 | *画外音:所以PK查询非常快,直接定位行记录。* 19 | 20 | InnoDB**普通索引**的叶子节点存储主键值。 21 | 22 |  *画外音:注意,不是存储行记录头指针,MyISAM的索引叶子节点存储记录指针。* 23 | 24 | 举个栗子,不妨设有表: 25 | 26 |   *t(id PK, name KEY, sex, flag);* 27 | 28 | *画外音:id是聚集索引,name是普通索引。* 29 | 30 | 表中有四条记录: 31 | 32 |   *1, shenjian, m, A* 33 | 34 |   *3, zhangsan, m, A* 35 | 36 |   *5, lisi, m, A* 37 | 38 |   *9, wangwu, f, B* 39 | 40 | ![img](https://img2018.cnblogs.com/blog/885859/201907/885859-20190729184808306-758660222.png) 41 | 42 | 两个B+树索引分别如上图: 43 | 44 |   (1)id为PK,聚集索引,叶子节点存储行记录; 45 | 46 |   (2)name为KEY,普通索引,叶子节点存储PK值,即id; 47 | 48 | 既然从普通索引无法直接定位行记录,那**普通索引的查询过程是怎么样的呢?** 49 | 50 | 通常情况下,需要扫码两遍索引树。 51 | 52 | 例如: 53 | 54 | ``` 55 | `select` `* ``from` `t ``where` `name``=``'lisi'``; ` 56 | ``` 57 | 58 | **是如何执行的呢?** 59 | 60 | ![img](https://img2018.cnblogs.com/blog/885859/201907/885859-20190729184911699-676257427.png) 61 | 62 | 如**粉红色**路径,需要扫码两遍索引树: 63 | 64 | (1)先通过普通索引定位到主键值id=5; 65 | 66 | (2)在通过聚集索引定位到行记录; 67 | 68 | 这就是所谓的**回表查询**,先定位主键值,再定位行记录,它的性能较扫一遍索引树更低。 69 | 70 | # 什么是索引覆盖? 71 | 72 | # **如何实现索引覆盖?** 73 | 74 | 将被查询的字段,建立到联合索引里去。 75 | 76 | https://www.cnblogs.com/myseries/p/11265849.html -------------------------------------------------------------------------------- /09 数据结构与算法/08 DFS BFS/Leetcode总结.md: -------------------------------------------------------------------------------- 1 | # [200. 岛屿数量](https://leetcode-cn.com/problems/number-of-islands/) 2 | 3 | 给定一个由 `'1'`(陆地)和 `'0'`(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。 4 | 5 | **示例 1:** 6 | 7 | ``` 8 | 输入: 9 | 11110 10 | 11010 11 | 11000 12 | 00000 13 | 14 | 输出: 1 15 | ``` 16 | 17 | **示例 2:** 18 | 19 | ``` 20 | 输入: 21 | 11000 22 | 11000 23 | 00100 24 | 00011 25 | 26 | 输出: 3 27 | ``` 28 | 29 | **思路:** 30 | 31 | - 典型的DFS,递归的作用是以当前的位置为起点,进行深度优先搜索,将上下左右为1的都置0 32 | - 每执行完一次,意味着存在一座岛屿,则sum++ 33 | 34 | ```java 35 | class Solution { 36 | public int numIslands(char[][] grid) { 37 | if(grid == null || grid.length == 0 || grid[0].length == 0){ 38 | return 0; 39 | } 40 | int numIslands = 0; 41 | int rows = grid.length; 42 | int cols = grid[0].length; 43 | for(int i = 0; i < rows; i++){ 44 | for(int j = 0; j < cols; j++){ 45 | if(grid[i][j] == '1'){ 46 | numIslands++; 47 | dfs(grid, i, j, rows, cols); 48 | } 49 | } 50 | } 51 | return numIslands++; 52 | } 53 | private void dfs(char[][] grid, int i, int j, int rows, int cols){ 54 | if(j < cols && i < rows && j>=0 && i>=0 && grid[i][j] == '1') 55 | { 56 | grid[i][j] = '0'; 57 | dfs(grid,i+1,j,rows,cols); 58 | dfs(grid,i,j+1,rows,cols); 59 | dfs(grid,i-1,j,rows,cols); 60 | dfs(grid,i,j-1,rows,cols); 61 | } 62 | } 63 | } 64 | ``` 65 | 66 | ## 并查集 67 | 68 | 并行计算 -------------------------------------------------------------------------------- /01 JavaSe/03 基础概念/notes/继承.md: -------------------------------------------------------------------------------- 1 | ## 访问权限 2 | 3 | Java 中有三个访问权限修饰符:private、protected 以及 public,如果不加访问修饰符,表示包级可见。 4 | 5 | 可以对类或类中的成员(字段以及方法)加上访问修饰符。 6 | 7 | - 类可见表示其它类可以用这个类创建实例对象。 8 | - 成员可见表示其它类可以用这个类的实例对象访问到该成员; 9 | 10 | protected 用于修饰成员,表示在继承体系中成员对于子类可见,但是这个访问修饰符对于类没有意义。 11 | 12 | 设计良好的模块会隐藏所有的实现细节,把它的 API 与它的实现清晰地隔离开来。模块之间只通过它们的 API 进行通信,一个模块不需要知道其他模块的内部工作情况,这个概念被称为信息隐藏或封装。因此访问权限应当尽可能地使每个类或者成员不被外界访问。 13 | 14 | 如果子类的方法重写了父类的方法,那么子类中该方法的访问级别不允许低于父类的访问级别。这是为了确保可以使用父类实例的地方都可以使用子类实例,也就是确保满足里氏替换原则。 15 | 16 | 字段决不能是公有的,因为这么做的话就失去了对这个字段修改行为的控制,客户端可以对其随意修改。例如下面的例子中,AccessExample 拥有 id 公有字段,如果在某个时刻,我们想要使用 int 存储 id 字段,那么就需要修改所有的客户端代码。 17 | 18 | ```java 19 | public class AccessExample { 20 | public String id; 21 | }Copy to clipboardErrorCopied 22 | ``` 23 | 24 | 可以使用公有的 getter 和 setter 方法来替换公有字段,这样的话就可以控制对字段的修改行为。 25 | 26 | ```java 27 | public class AccessExample { 28 | 29 | private int id; 30 | 31 | public String getId() { 32 | return id + ""; 33 | } 34 | 35 | public void setId(String id) { 36 | this.id = Integer.valueOf(id); 37 | } 38 | }Copy to clipboardErrorCopied 39 | ``` 40 | 41 | 但是也有例外,如果是包级私有的类或者私有的嵌套类,那么直接暴露成员不会有特别大的影响。 42 | 43 | ```java 44 | public class AccessWithInnerClassExample { 45 | 46 | private class InnerClass { 47 | int x; 48 | } 49 | 50 | private InnerClass innerClass; 51 | 52 | public AccessWithInnerClassExample() { 53 | innerClass = new InnerClass(); 54 | } 55 | 56 | public int getValue() { 57 | return innerClass.x; // 直接访问 58 | } 59 | } 60 | ``` -------------------------------------------------------------------------------- /08 数据库/01 MySQL/notes/优化.md: -------------------------------------------------------------------------------- 1 | ## 使用 Explain 进行分析 2 | 3 | Explain 用来分析 SELECT 查询语句,开发人员可以通过分析 Explain 结果来优化查询语句。 4 | 5 | 比较重要的字段有: 6 | 7 | - select_type : 查询类型,有简单查询、联合查询、子查询等 8 | - key : 使用的索引 9 | - rows : 扫描的行数 10 | 11 | ## 优化数据访问 12 | 13 | ### 1. 减少请求的数据量 14 | 15 | - 只返回必要的列:最好**不要使用 SELECT * 语句**。 16 | - 只返回必要的行:使用 **LIMIT 语句来限制返回的数据**。 17 | - 缓存重复查询的数据:使用缓存可以避免在数据库中进行查询,特别在要查询的数据经常被重复查询时,缓存带来的查询性能提升将会是非常明显的。 18 | 19 | ### 2. 减少服务器端扫描的行数 20 | 21 | 最有效的方式是使用索引来覆盖查询。 22 | 23 | ## 重构查询方式 24 | 25 | ### 1. 切分大查询 26 | 27 | 一个大查询如果一次性执行的话,可能一次锁住很多数据、占满整个事务日志、耗尽系统资源、阻塞很多小的但重要的查询。 28 | 29 | ```sql 30 | DELETE FROM messages WHERE create < DATE_SUB(NOW(), INTERVAL 3 MONTH); 31 | rows_affected = 0 32 | do { 33 | rows_affected = do_query( 34 | "DELETE FROM messages WHERE create < DATE_SUB(NOW(), INTERVAL 3 MONTH) LIMIT 10000") 35 | } while rows_affected > 0 36 | ``` 37 | 38 | ### 2. 分解大连接查询 39 | 40 | 将一个大连接查询分解成对每一个表进行一次单表查询,然后在应用程序中进行关联,这样做的好处有: 41 | 42 | - 让缓存更高效。对于连接查询,如果其中一个表发生变化,那么整个查询缓存就无法使用。而分解后的多个查询,即使其中一个表发生变化,对其它表的查询缓存依然可以使用。 43 | - 分解成多个单表查询,这些单表查询的缓存结果更可能被其它查询使用到,从而减少冗余记录的查询。 44 | - 减少锁竞争; 45 | - 在应用层进行连接,可以更容易对数据库进行拆分,从而更容易做到高性能和可伸缩。 46 | - 查询本身效率也可能会有所提升。例如下面的例子中,使用 IN() 代替连接查询,可以让 MySQL 按照 ID 顺序进行查询,这可能比随机的连接要更高效。 47 | 48 | ```sql 49 | SELECT * FROM tab 50 | JOIN tag_post ON tag_post.tag_id=tag.id 51 | JOIN post ON tag_post.post_id=post.id 52 | WHERE tag.tag='mysql'; 53 | SELECT * FROM tag WHERE tag='mysql'; 54 | SELECT * FROM tag_post WHERE tag_id=1234; 55 | SELECT * FROM post WHERE post.id IN (123,456,567,9098,8904); 56 | ``` 57 | 58 | -------------------------------------------------------------------------------- /06 计算机网络/notes/IP地址.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1 .子网掩码的作用 4 | 5 | 子网掩码只有一个作用,就是将某个IP地址划分成网络地址和主机地址两部分。 6 | 7 | # 网络地址 8 | 9 |   IP地址由网络号(包括子网号)和主机号组成,网络地址的主机号为全0,网络地址代表着整个网络。 10 | 11 | # 广播地址 12 | 13 |   广播地址通常称为直接广播地址,是为了区分受限广播地址。 14 | 15 |   广播地址与网络地址的主机号正好相反,广播地址中,主机号为全1。当向某个网络的广播地址发送消息时,该网络内的所有主机都能收到该广播消息。 16 | 17 | # 组播地址 18 | 19 |   D类地址就是组播地址。 20 | 21 |   先回忆下A,B,C,D类地址吧: 22 | 23 |   A类地址以0开头,第一个字节作为网络号,地址范围为:0.0.0.0~127.255.255.255;(modified @2016.05.31) 24 | 25 |   B类地址以10开头,前两个字节作为网络号,地址范围是:128.0.0.0~191.255.255.255; 26 | 27 |   C类地址以110开头,前三个字节作为网络号,地址范围是:192.0.0.0~223.255.255.255。 28 | 29 |   D类地址以1110开头,地址范围是224.0.0.0~239.255.255.255,D类地址作为组播地址(一对多的通信); 30 | 31 |   E类地址以1111开头,地址范围是240.0.0.0~255.255.255.255,E类地址为保留地址,供以后使用。 32 | 33 |   注:只有A,B,C有网络号和主机号之分,D类地址和E类地址没有划分网络号和主机号。 34 | 35 | # 255.255.255.255 36 | 37 |   该IP地址指的是受限的广播地址。受限广播地址与一般广播地址(直接广播地址)的区别在于,受限广播地址只能用于本地网络,路由器不会转发以受限广播地址为目的地址的分组;一般广播地址既可在本地广播,也可跨网段广播。例如:主机192.168.1.1/30上的直接广播数据包后,另外一个网段192.168.1.5/30也能收到该数据报;若发送受限广播数据报,则不能收到。 38 | 39 |   注:一般的广播地址(直接广播地址)能够通过某些路由器(当然不是所有的路由器),而受限的广播地址不能通过路由器。 40 | 41 | # 0.0.0.0 42 | 43 |   常用于寻找自己的IP地址,例如在我们的RARP,BOOTP和DHCP协议中,若某个未知IP地址的无盘机想要知道自己的IP地址,它就以255.255.255.255为目的地址,向本地范围(具体而言是被各个路由器屏蔽的范围内)的服务器发送IP请求分组。 44 | 45 | # 回环地址 46 | 47 |   127.0.0.0/8被用作回环地址,回环地址表示本机的地址,常用于对本机的测试,用的最多的是127.0.0.1。 48 | 49 | # A、B、C类私有地址 50 | 51 |   私有地址(private address)也叫专用地址,它们不会在全球使用,只具有本地意义。 52 | 53 |   A类私有地址:10.0.0.0/8,范围是:10.0.0.0~10.255.255.255 54 | 55 |   B类私有地址:172.16.0.0/12,范围是:172.16.0.0~172.31.255.255 56 | 57 |   C类私有地址:192.168.0.0/16,范围是:192.168.0.0~192.168.255.255 -------------------------------------------------------------------------------- /04 框架/02 Spring MVC/notes/SpringMVC.md: -------------------------------------------------------------------------------- 1 | # Spring MVC 2 | 3 | Spring MVC是Spring中的基础 Web 框架,基于模型-视图-控制器(Model-View-Controller,[MVC](https://zh.wikipedia.org/wiki/MVC))模式实现,它能够帮你构建像Spring框架那样灵活和松耦合的Web应用程序。 4 | 在该框架下,一次web请求大致可以分为如下图几个步骤,这些划分分离了职责,使得代码灵活、维护性更好。 5 | 6 | ![](https://raw.githubusercontent.com/wuqifan1098/picBed/master/DispatchServlet.png) 7 | 8 | 具体步骤: 9 | 10 | ​ 1、客户端发送**请求先要经过前端控制器**,请求被Spring 前端控制器DispatcherServlet获取,如详细图第一步:DispatcherServlet对请求URL进行解析(比如我们发送一个url如下的请求(http://localhost:8080/SpringMVC/hello.action),就会得到请求资源标示符(URI,相当于就是上面的hello.action )。 11 | 12 | ​ 2、然后前端控制器DispatcherServlet根据URI,**调用处理器映射器(HandlerMapping)获得该Handler配置的所有相关对象**(包括Handler对象以及Handler对象对应的拦截器),最后**生成处理器对象并返回给前端控制器**。 13 | 14 | ​ 3、前端控制器**调用处理器适配器去执行Handler**,Handler执行完成给适配器**返回ModelAndView**,并将ModelAndView返回给DispatcherServlet。 15 | 16 | ​ 4、DispatcherServlet将**ModelAndView传给ViewReslover视图解析器解析**(解析成jsp),并**返回View**。 17 | 18 | ​ 5、DispatcherServlet**对View进行渲染视图**(即将模型数据填充至视图中)。 19 | 20 | ​ 6、最后将渲染视图的结果响应给客户端。 21 | 22 | 为了使用该框架,我们**首先要配置DispatchServlet,也就是前端控制器,然后启用Spring MVC,并编写控制器,视图,模型等等。** 23 | 其中,DispatcherServlet是Spring MVC的核心,DispatcherServlet启动的时候,它会创建Spring应用上下文,并加载配置文件或配置类中所声明的bean或者自动扫描的bean,但是在Spring Web应用中,通常还会有另外一个应用上下文,这个应用上下文是由ContextLoaderListener创建的。DispatcherServlet加载包含Web组件的bean,如控制器、视图解析器以及处理器映射,而ContextLoaderListener要加载应用中的其他bean,通常是驱动应用后端的中间层和数据层组件。 24 | 25 | Spring MVC是一个强大灵活的Web框架。借助于注解,Spring MVC提供了近似于POJO的开发模式,这使得开发处理请求的控制器变得非常简单,同时也易于测试。而且Spring MVC还支持多种视图解析器如JSP,Tiles,Thymeleaf,使得前端界面的功能更强大,编写更容易。 -------------------------------------------------------------------------------- /03 多线程和高并发/notes/自旋锁.md: -------------------------------------------------------------------------------- 1 | # 自旋锁 2 | 3 | 指尝试获取锁的线程**不会立即阻塞**,而是采用阻塞的方式去尝试获取锁,这样的好处是**减少上下文切换的消耗**,缺点是会消耗CPU。 4 | 5 | 手写自旋锁 6 | 7 | ```java 8 | public class SpinLockDemo{ 9 | 10 | 11 | // 原子引用线程 12 | AtomicReference atomicReference = new AtomicReference<>();//初始值为null 13 | 14 | public void myLock(){ 15 | Thread thread = Thread.currentThread(); 16 | System.out.println(Thread.currentThread().getName()+"\t come in "); 17 | 18 | while(!atomicReference.compareAndSet(null,thread)){ 19 | 20 | } 21 | } 22 | public void myUnlock(){ 23 | Thread thread = Thread.currentThread(); 24 | atomicReference.compareAndSet(thread,null); 25 | System.out.printIn(Thread.currentThread().getName()+"\t invoked myUnlock "); 26 | } 27 | } 28 | 29 | public static void main(String[] args){ 30 | SpinLockDemo spinLockDemo = new SpinLockDemo(); 31 | 32 | new Thread(() ->{ 33 | spinLockDemo.myLock(); 34 | //暂停一会儿线程 35 | try{TimeUnit.SECONDS.sleep(5);}catch(InterruptedException e){e.printStackTrace();} 36 | spinLockDemo.myUnlock(); 37 | },"AA").start(); 38 | //保证AA先 39 | try{TimeUnit.SECONDS.sleep(1);}catch(InterruptedException e){e.printStackTrace();} 40 | 41 | new Thread(() ->{ 42 | spinLockDemo.myLock(); 43 | spinLockDemo.myUnlock(); 44 | },"BB").start(); 45 | } 46 | ``` 47 | 48 | -------------------------------------------------------------------------------- /07 操作系统/notes/线程间通信和进程间通信.md: -------------------------------------------------------------------------------- 1 | # 线程间通信 2 | 3 | ## synchronized同步 4 | 5 | - 这种方式,本质上就是 “共享内存” 式的通信。多个线程需要访问同一个共享变量,谁拿到了锁(获得了访问权限),谁就可以执行。 6 | 7 | ## while轮询的方式 8 | 9 | - 在这种方式下,ThreadA 不断地改变条件,ThreadB 不停地通过 while 语句检测这个条件 (list.size()==5) 是否成立 ,从而实现了线程间的通信。但**是这种方式会浪费 CPU 资源**。 10 | 11 | - 之所以说它浪费资源,是因为 JVM 调度器将 CPU 交给 ThreadB 执行时,它没做啥 “有用” 的工作,只是在不断地测试某个条件是否成立。 12 | 13 | - 就类似于现实生活中,某个人一直看着手机屏幕是否有电话来了,而不是:在干别的事情,当有电话来时,响铃通知TA电话来了。 14 | 15 | ## wait/notify机制 16 | 17 | - 当条件未满足时,ThreadA 调用 wait() 放弃 CPU,并进入阻塞状态。(不像 while 轮询那样占用 CPU) 18 | 19 | 当条件满足时,ThreadB 调用 notify() 通知线程 A,所谓通知线程 A,就是唤醒线程 A,并让它进入可运行状态。 20 | 21 | ## 管道通信 22 | 23 | - java.io.PipedInputStream 和 java.io.PipedOutputStream进行通信 24 | 25 | # 进程间通信 26 | 27 | ## 管道(Pipe) 28 | 管道可用于具有亲缘关系进程间的通信,允许一个进程和另一个与它有共同祖先的进程之间进行通信。 29 | 30 | ## 命名管道(named pipe) 31 | 命名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关 系 进程间的通信。命名管道在文件系统中有对应的文件名。命名管道通过命令mkfifo或系统调用mkfifo来创建。 32 | 33 | ## 信号(Signal) 34 | 信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送 信号给进程本身;Linux除了支持Unix早期信号语义函数sigal外,还支持语义符合Posix.1标准的信号函数sigaction(实际上,该函数是基于BSD的,BSD为了实现可靠信号机制,又能够统一对外接口,用sigaction函数重新实现了signal函数)。 35 | 36 | ## 消息(Message)队列 37 | 消息队列是消息的链接表,包括Posix消息队列system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺 38 | 39 | ## 共享内存 40 | 使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通信机制运行效率较低而设计的。往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。 41 | 42 | ## 内存映射(mapped memory) 43 | 内存映射允许任何多个进程间通信,每一个使用该机制的进程通过把一个共享的文件映射到自己的进程地址空间来实现它。 44 | 45 | ## 信号量(semaphore) 46 | 主要作为进程间以及同一进程不同线程之间的同步手段。 47 | 48 | ## 套接口(Socket) 49 | 更为一般的进程间通信机制,可用于不同机器之间的进程间通信。起初是由Unix系统的BSD分支开发出来的,但现在一般可以移植到其它类Unix系统上:linux和System V的变种都支持套接字。 50 | 51 | -------------------------------------------------------------------------------- /06 计算机网络/notes/ARP、RARP.md: -------------------------------------------------------------------------------- 1 | # ARP 2 | 3 | 1. 每个主机都会在自己的ARP缓冲区中建立一个ARP列表,**以表示IP地址和MAC地址之间的对应关系。** 4 | 2. 当源主机要发送数据时,**首先检查ARP列表中是否有对应IP地址的目的主机的MAC地址,如果有,则直接发送数据,如果没有,就向本网段的所有主机发送ARP数据包,**该数据包包括的内容有:源主机 IP地址,源主机MAC地址,目的主机的IP地址。 5 | 3. 当本网络的所有主机收到该ARP数据包时,首先检查数据包中的IP地址是否是自己的IP地址,如果不是,则忽略该数据包,如果是,则首先从数据包中取出源主机的IP和MAC地址写入到ARP列表中,如果已经存在,则覆盖,然后将自己的MAC地址写入ARP响应包中,告诉源主机自己是它想要找的MAC地址。 6 | 4. 源主机收到ARP响应包后。**将目的主机的IP和MAC地址写入ARP列表,并利用此信息发送数据。**如果源主机一直没有收到ARP响应数据包,表示ARP查询失败。 7 | 8 | 广播发送ARP请求,单播发送ARP响应。 9 | 10 | ## ARP工作流程举例: 11 | 12 |   主机A的IP地址为192.168.1.1,MAC地址为0A-11-22-33-44-01; 13 |   主机B的IP地址为192.168.1.2,MAC地址为0A-11-22-33-44-02; 14 | 15 |   当主机A要与主机B通信时,地址解析协议可以将主机B的IP地址(192.168.1.2)解析成主机B的MAC地址,以下为工作流程: 16 | 17 |   (1)根据主机A上的路由表内容,IP确定用于访问主机B的转发IP地址是192.168.1.2。然后A主机在自己的本地ARP缓存中检查主机B的匹配MAC地址。 18 | 19 |   (2)如果主机A在ARP缓存中没有找到映射,它将询问192.168.1.2的硬件地址,从而将ARP请求帧广播到本地网络上的所有主机。源主机A的IP地址和MAC地址都包括在ARP请求中。本地网络上的每台主机都接收到ARP请求并且检查是否与自己的IP地址匹配。如果主机发现请求的IP地址与自己的IP地址不匹配,它将丢弃ARP请求。 20 | 21 |   (3)主机B确定ARP请求中的IP地址与自己的IP地址匹配,则将主机A的IP地址和MAC地址映射添加到本地ARP缓存中。 22 | 23 |   (4)主机B将包含其MAC地址的ARP回复消息直接发送回主机A。 24 | 25 |   (5)当主机A收到从主机B发来的ARP回复消息时,会用主机B的IP和MAC地址映射更新ARP缓存。本机缓存是有生存期的,生存期结束后,将再次重复上面的过程。主机B的MAC地址一旦确定,主机A就能向主机B发送IP通信了。 26 | 27 | # RARP 28 | 29 | 逆地址解析协议,即RARP,功能和ARP协议相对,其将局域网中某个主机的物理地址转换为IP地址,比如局域网中有一台主机只知道物理地址而不知道IP地址,那么可以通过RARP协议发出征求自身IP地址的广播请求,然后由RARP服务器负责回答。 30 | 31 | ## RARP协议工作流程: 32 | 33 |   (1)给主机发送一个本地的RARP广播,在此广播包中,声明自己的MAC地址并且请求任何收到此请求的RARP服务器分配一个IP地址; 34 | 35 |   (2)本地网段上的RARP服务器收到此请求后,检查其RARP列表,查找该MAC地址对应的IP地址; 36 | 37 |   (3)如果存在,RARP服务器就给源主机发送一个响应数据包并将此IP地址提供给对方主机使用; 38 | 39 |   (4)如果不存在,RARP服务器对此不做任何的响应; 40 | 41 |   (5)源主机收到从RARP服务器的响应信息,就利用得到的IP地址进行通讯;如果一直没有收到RARP服务器的响应信息,表示初始化失败。 42 | -------------------------------------------------------------------------------- /08 数据库/01 MySQL/notes/SQL语句.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1. varchar和char的区别 4 | 5 | 区别一,定长和变长 6 | 7 | char 表示定长,长度固定,varchar表示变长,即长度可变。char如果插入的长度小于定义长度时,则用空格填充;varchar小于定义长度时,还是按实际长度存储,插入多长就存多长。 8 | 9 | 因为其长度固定,char的存取速度还是要比varchar要快得多,**方便程序的存储与查找**;但是char也为此付出的是空间的代价,因为其长度固定,所以会**占据多余的空间,可谓是以空间换取时间效率**。varchar则刚好相反,**以时间换空间**。 10 | 11 | 区别之二,存储的容量不同 12 | 13 | 对 char 来说,**最多能存放的字符个数 255**,和编码无关。 14 | 而 varchar 呢,**最多能存放 65532 个字符**。varchar的最大有效长度由最大行大小和使用的字符集确定。整体最大长度是 65,532字节。 15 | 16 | 原文链接:https://blog.csdn.net/qq_20264581/article/details/83755789 17 | 18 | ## 2. groupby where having join 执行的顺序(CVTE) 19 | 20 | - 先连接from后的数据源(若有join,则先执行on后条件,再连接数据源)。 21 | - 执行where条件 22 | - 执行group by 23 | - 执行having 过滤 24 | - 执行order by 25 | - 输出结果 26 | 27 | having是分组(group by)后的筛选条件,分组后的数据组内再筛选 28 | where则是在分组前筛选 29 | 30 | where子句中不能使用聚集函数,而having子句中可以,所以在集合函数中加上了HAVING来起到测试查询结果是否符合条件的作用。 31 | 即having子句的适用场景是可以使用聚合函数 32 | 33 | having 子句限制的是组,而不是行 34 | having 子句中的每一个元素也必须出现在select列表中。有些数据库例外,如oracle 35 | 36 | 当同时含有 where 子句、group by 子句 、having 子句及聚集函数时,执行顺序如下: 37 | 执行where子句查找符合条件的数据; 38 | 使用group by 子句对数据进行分组;对group by 子句形成的组运行聚集函数计算每一组的值;最后用having 子句去掉不符合条件的组 39 | 40 | https://blog.csdn.net/alice_tl/article/details/88764591 41 | 42 | ## 3.分页怎么做 43 | 44 | **select \* from table limit (start-1)\*pageSize,pageSize;** 其中**start**是页码,**pageSize**是每页显示的条数。 45 | 46 | https://www.cnblogs.com/youyoui/p/7851007.html 47 | 48 | Mybatis中有分页插件 49 | 50 | ```java 51 | 52 | 53 | com.github.pagehelper 54 | pagehelper 55 | 5.0.0 56 | 57 | ``` 58 | 59 | http://www.ciphermagic.cn/mybatis-page-2.html 60 | 61 | ## 4.聚合函数 62 | 63 | -------------------------------------------------------------------------------- /05 设计模式/notes/工厂模式.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1. 工厂模式和抽象工厂模式的区别(CVTE) 4 | 5 | 6 | 7 | # 总结 8 | 9 | 1. 将实例化的对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦。从而提高项目的扩展和维护性。 10 | 2. 三种工厂模式(简单工厂模式、工厂方法模式、抽象工厂模式) 11 | 3. 设计模式的**依赖抽象**原则 12 | 13 | - 创建对象实例时,不要直接new类,而是把这个new类的动作放在一个工厂的方法中,并返回 14 | - 不要让类继承具体类,而是继承抽象类或者实现interface(接口) 15 | - 不要覆盖类中已经实现的方法 16 | 17 | 简单工厂模式:专门定义一个类用来负责创建其他类的实例,被创建的实例通常都具有共同的父类。 18 | 19 | 工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类。使一个类的实例化延迟到子类。 20 | 21 | 抽象工厂模式:提供一个创建一系列相关或者相互依赖对象的接口,而无需指定他们具体的类。 22 | 23 | ### 简单工厂模式 24 | 25 | 简单工厂模式不是 23 种里的一种,简而言之,就是有一个专门生产某个产品的类。 26 | 27 | 比如下图中的鼠标工厂,专业生产鼠标,给参数 0,生产戴尔鼠标,给参数 1,生产惠普鼠标。 28 | 29 | ![img](https://www.runoob.com/wp-content/uploads/2018/07/1530601914-2143-DP-SimpleFactory.png) 30 | 31 | 工厂模式也就是鼠标工厂是个父类,有生产鼠标这个接口。 32 | 33 | 戴尔鼠标工厂,惠普鼠标工厂继承它,可以分别生产戴尔鼠标,惠普鼠标。 34 | 35 | 生产哪种鼠标不再由参数决定,而是创建鼠标工厂时,由戴尔鼠标工厂创建。 36 | 37 | 后续直接调用**鼠标工厂.生产鼠标()**即可 38 | 39 | ![img](https://www.runoob.com/wp-content/uploads/2018/07/1530601917-1999-DP-Factory.png) 40 | 41 | 抽象工厂模式也就是不仅生产鼠标,同时生产键盘。 42 | 43 | 也就是 PC 厂商是个父类,有生产鼠标,生产键盘两个接口。 44 | 45 | 戴尔工厂,惠普工厂继承它,可以分别生产戴尔鼠标+戴尔键盘,和惠普鼠标+惠普键盘。 46 | 47 | 创建工厂时,由戴尔工厂创建。 48 | 49 | 后续**工厂.生产鼠标()**则生产戴尔鼠标,**工厂.生产键盘()**则生产戴尔键盘。 50 | 51 | ![img](https://www.runoob.com/wp-content/uploads/2018/07/1530601916-7298-DP-AbstractFactory.png) 52 | 53 | 假设我们增加华硕工厂,则我们需要增加华硕工厂,和戴尔工厂一样,继承 PC 厂商。 54 | 55 | 之后创建华硕鼠标,继承鼠标类。创建华硕键盘,继承键盘类即可。 56 | 57 | ![img](https://www.runoob.com/wp-content/uploads/2018/07/1530601980-8080-P-AbstractFactory-AddFactory.png) 58 | 59 | 假设我们增加耳麦这个产品,则首先我们需要增加耳麦这个父类,再加上戴尔耳麦,惠普耳麦这两个子类。 60 | 61 | 之后在PC厂商这个父类中,增加生产耳麦的接口。最后在戴尔工厂,惠普工厂这两个类中,分别实现生产戴尔耳麦,惠普耳麦的功能。 以上。 62 | 63 | ![img](https://www.runoob.com/wp-content/uploads/2018/07/1530601917-7462-P-AbstractFactory-AddProduct.png) 64 | 65 | https://www.runoob.com/design-pattern/abstract-factory-pattern.html -------------------------------------------------------------------------------- /09 数据结构与算法/09 二分查找/Leetcode总结.md: -------------------------------------------------------------------------------- 1 | # [704. 二分查找](https://leetcode-cn.com/problems/binary-search/) 2 | 3 | 给定一个 `n` 个元素有序的(升序)整型数组 `nums` 和一个目标值 `target` ,写一个函数搜索 `nums` 中的 `target`,如果目标值存在返回下标,否则返回 `-1`。 4 | 5 | 6 | **示例 1:** 7 | 8 | ``` 9 | 输入: nums = [-1,0,3,5,9,12], target = 9 10 | 输出: 4 11 | 解释: 9 出现在 nums 中并且下标为 4 12 | ``` 13 | 14 | **示例 2:** 15 | 16 | ``` 17 | 输入: nums = [-1,0,3,5,9,12], target = 2 18 | 输出: -1 19 | 解释: 2 不存在 nums 中因此返回 -1 20 | ``` 21 | 22 | **提示:** 23 | 24 | 1. 你可以假设 `nums` 中的所有元素是不重复的。 25 | 2. `n` 将在 `[1, 10000]`之间。 26 | 3. `nums` 的每个元素都将在 `[-9999, 9999]`之间。 27 | 28 | ```java 29 | class Solution { 30 | public int search(int[] nums, int target) { 31 | int left = 0; 32 | int right = nums.length - 1; 33 | while(left <= right) { 34 | int mid = right - (right - left) / 2; 35 | if(target == nums[mid]){ 36 | return mid; 37 | } 38 | else if(target < nums[mid]){ 39 | right = mid - 1; 40 | } 41 | else if(target > nums[mid]){ 42 | left = mid + 1; 43 | } 44 | } 45 | return -1; 46 | } 47 | } 48 | ``` 49 | 50 | *1*. 为什么 while 循环的条件中是 <=,而不是 < ? 51 | 52 | 答:因为初始化 right 的赋值是 nums.length - 1,即最后一个元素的索引,而不是 nums.length。 53 | 54 | 这二者可能出现在不同功能的二分查找中,区别是:前者相当于两端都闭区间 [left, right],后者相当于左闭右开区间 [left, right),因为索引大小为 nums.length 是越界的。 55 | 56 | 我们这个算法中使用的是 [left, right] 两端都闭的区间。**这个区间就是每次进行搜索的区间,我们不妨称为「搜索区间」**。 57 | 58 | *2*. 为什么 left = mid + 1,right = mid - 1?我看有的代码是 right = mid 或者 left = mid,没有这些加加减减,到底怎么回事,怎么判断? 59 | 60 | 答:这也是二分查找的一个难点,不过只要你能理解前面的内容,就能够很容易判断。 61 | 62 | 刚才明确了「搜索区间」这个概念,而且本算法的搜索区间是两端都闭的,即 [left, right]。那么当我们发现索引 mid 不是要找的 target 时,如何确定下一步的搜索区间呢? 63 | 64 | 当然是去搜索 [left, mid - 1] 或者 [mid + 1, right] 对不对?因为 mid 已经搜索过,应该从搜索区间中去除。 -------------------------------------------------------------------------------- /01 JavaSe/03 基础概念/notes/封装.md: -------------------------------------------------------------------------------- 1 | # 概念 2 | 3 | **封装是将代码及其处理的数据绑定在一起的一种编程机制,该机制保证了程序和数据都不受外部干扰且不被误用。**封装的目的在于保护信息,使用它的主要优点如下。 4 | 5 | - 保护类中的信息,它可以阻止在外部定义的代码随意访问内部代码和数据。 6 | - 隐藏细节信息,一些不需要程序员修改和使用的信息,比如取款机中的键盘,用户只需要知道按哪个键实现什么操作就可以,至于它内部是如何运行的,用户不需要知道。 7 | - 有助于建立各个系统之间的松耦合关系,提高系统的独立性。当一个系统的实现方式发生变化时,只要它的接口不变,就不会影响其他系统的使用。例如 U 盘,不管里面的存储方式怎么改变,只要 U 盘上的 USB 接口不变,就不会影响用户的正常操作。 8 | - 提高软件的复用率,降低成本。每个系统都是一个相对独立的整体,可以在不同的环境中得到使用。例如,一个 U 盘可以在多台电脑上使用。 9 | 10 | Java 语言的基本封装单位是类。由于类的用途是封装复杂性,所以类的内部有隐藏实现复杂性的机制。Java 提供了私有和公有的访问模式,类的公有接口代表外部的用户应该知道或可以知道的每件东西,私有的方法数据只能通过该类的成员代码来访问,这就可以确保不会发生不希望的事情。 11 | 12 | # 优点 13 | 14 | 在面向对象程式设计方法中,封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部份包装、隐藏起来的方法。 15 | 16 | 封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。 17 | 18 | 要访问该类的代码和数据,必须通过严格的接口控制。 19 | 20 | 封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。 21 | 22 | 适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性。 23 | 24 | 封装的优点 25 | 26 | 1. 良好的封装能够减少耦合。 27 | 2. 类内部的结构可以自由修改。 28 | 3. 可以对成员变量进行更精确的控制。 29 | 4. 隐藏信息,实现细节。 30 | 31 | Java 封装,说白了就是将一大坨公共通用的实现逻辑玩意,装到一个盒子里(class),出入口都在这个盒子上。你要用就将这个盒子拿来用,连接出入口,就能用了,不用就可以直接扔,对你代码没什么影响。 32 | 33 | 对程序员来说,使用封装的目的: 34 | 35 | 1. 偷懒,辛苦一次,后面都能少敲很多代码,增强了代码得复用性 36 | 37 | 2. 简化代码,看起来更容易懂 38 | 39 | 3. 隐藏核心实现逻辑代码,简化外部逻辑,并且不让其他人修改,jar 都这么干 40 | 41 | 4. 一对一,一个功能就只为这个功能服务;避免头发绳子一块用,导致最后一团糟 42 | 43 | 44 | 45 | # 实现步骤 46 | 47 |      ![img](https://mmbiz.qpic.cn/mmbiz_png/yrbzLUhDJu02wewSgmgf7ySdDib23ibnFegKN1GVic1fcxxDCxmW6jnZ59BKgYpWO5T9ia4k1bJJpvTCWN0vHLSISg/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 48 | 49 |     需要注意:对封装的属性不一定要通过get/set方法,其他方法也可以对封装的属性进行操作。当然最好使用get/set方法,比较标准。 50 | 51 | ------ 52 | 53 | ##### A、访问修饰符 54 | 55 |  ![img](https://mmbiz.qpic.cn/mmbiz_png/yrbzLUhDJu02wewSgmgf7ySdDib23ibnFeicZ3taapN1aAddMLHrrOPhtwU2WibI2h7KtcPiaJZx2CTm7nDsusQEJbA/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 56 | 57 |     从表格可以看出**从上到下封装性越来越差**。 -------------------------------------------------------------------------------- /09 数据结构与算法/07 动态规划/BFS和DFS.md: -------------------------------------------------------------------------------- 1 | ## 一、前言 2 | 3 | 我们首次接触 [BFS](https://cuijiahua.com/blog/tag/bfs/) 和 DFS 时,应该是在数据结构课上讲的 “图的遍历”。还有就是刷题的时候,遍历二叉树我们会经常用到[BFS](https://cuijiahua.com/blog/tag/bfs/)和DFS。它们的实现都很简单,这里我就不哆嗦去贴代码了。 4 | 5 | 想看代码的可以看《[剑指Offer(三十八):二叉树的深度](https://cuijiahua.com/blog/2018/01/basis_38.html)》这个题目就可以利用BFS和DFS进行求解。那么,这两者“遍历” 的序列到底有何差别? 6 | 7 | 本篇文章就单纯来讲讲它们的区别和各自的应用,不会涉及任何代码。我们以“图的遍历”为例,进行说明。 8 | 9 | ## 二、区别 10 | 11 | **广度优先搜索算法(Breadth-First-Search,缩写为 BFS)**,是一种利用**队列**实现的搜索算法。简单来说,其搜索过程和 “湖面丢进一块石头激起层层涟漪” 类似。 12 | 13 | **深度优先搜索算法(Depth-First-Search,缩写为 DFS)**,是一种利用**递归**实现的搜索算法。简单来说,其搜索过程和 “不撞南墙不回头” 类似。 14 | 15 | **BFS 的重点在于队列,而 DFS 的重点在于递归。这是它们的本质区别。** 16 | 17 | 举个典型例子,如下图,灰色代表墙壁,绿色代表起点,红色代表终点,规定每次只能走一步,且只能往下或右走。求一条绿色到红色的最短路径。 18 | 19 | [![算法基础:BFS和DFS的直观解释](https://cuijiahua.com/wp-content/uploads/2018/01/alogrithm_10_1.png)](https://cuijiahua.com/wp-content/uploads/2018/01/alogrithm_10_1.png) 20 | 21 | 对于上面的问题,BFS 和 DFS 都可以求出结果,它们的区别就是在复杂度上存在差异。我可以先告诉你,该题 BFS 是较佳算法。 22 | 23 | **BFS示意图:** 24 | 25 | [![算法基础:BFS和DFS的直观解释](https://cuijiahua.com/wp-content/uploads/2018/01/alogrithm_10_2.gif)](https://cuijiahua.com/wp-content/uploads/2018/01/alogrithm_10_2.gif) 26 | 27 | 如上图所示,从起点出发,对于每次出队列的点,都要遍历其四周的点。所以说 BFS 的搜索过程和 “湖面丢进一块石头激起层层涟漪” 很相似,此即 “广度优先搜索算法” 中“广度”的由来。 28 | 29 | **DFS示意图:** 30 | 31 | [![算法基础:BFS和DFS的直观解释](https://cuijiahua.com/wp-content/uploads/2018/01/alogrithm_10_3.gif)](https://cuijiahua.com/wp-content/uploads/2018/01/alogrithm_10_3.gif) 32 | 33 | 如上图所示,从起点出发,先把一个方向的点都遍历完才会改变方向...... 所以说,DFS 的搜索过程和 “不撞南墙不回头” 很相似,此即 “深度优先搜索算法” 中“深度”的由来。 34 | 35 | ## 三、总结 36 | 37 | 现在,你不妨对照着图,再去看看你打印出的遍历序列,是不是一目了然呢? 38 | 39 | 最后再说下它们的应用方向。 40 | 41 | BFS 常用于找单一的最短路线,它的特点是 "搜到就是最优解",而 DFS 用于找所有解的问题,它的空间效率高,而且找到的不一定是最优解,必须记录并完成整个搜索,故一般情况下,深搜需要非常高效的剪枝(剪枝的概念请百度)。 42 | 43 | PS:BFS 和 DFS 是很重要的算法,读者如果想要更深入地了解它们,建议去 OJ 或 Leetcode 上找一些相关赛题训练下,一定会给你一个别样的天地。 -------------------------------------------------------------------------------- /09 数据结构与算法/07 动态规划/LeetCode总结.md: -------------------------------------------------------------------------------- 1 | # [322. 零钱兑换](https://leetcode-cn.com/problems/coin-change/) 2 | 3 | 给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 `-1`。 4 | 5 | **示例 1:** 6 | 7 | ``` 8 | 输入: coins = [1, 2, 5], amount = 11 9 | 输出: 3 10 | 解释: 11 = 5 + 5 + 1 11 | ``` 12 | 13 | **示例 2:** 14 | 15 | ``` 16 | 输入: coins = [2], amount = 3 17 | 输出: -1 18 | ``` 19 | 20 | **说明**: 21 | 你可以认为每种硬币的数量是无限的。 22 | 23 | # [121. 买卖股票的最佳时机](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/) 24 | 25 | 给定一个数组,它的第 *i* 个元素是一支给定股票第 *i* 天的价格。 26 | 27 | 如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。 28 | 29 | 注意你不能在买入股票前卖出股票。 30 | 31 | **示例 1:** 32 | 33 | ``` 34 | 输入: [7,1,5,3,6,4] 35 | 输出: 5 36 | 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 37 | 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。 38 | ``` 39 | 40 | **示例 2:** 41 | 42 | ``` 43 | 输入: [7,6,4,3,1] 44 | 输出: 0 45 | 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 46 | ``` 47 | 48 | ```java 49 | class Solution { 50 | public int maxProfit(int[] prices) { 51 | int min = Integer.MAX_VALUE; 52 | int max = 0; 53 | for(int i = 0;i < prices.length;i++){ 54 | if(prices[i] < min) 55 | min = prices[i]; 56 | else if(prices[i] - min > max) 57 | max = prices[i] - min; 58 | } 59 | return max; 60 | } 61 | } 62 | ``` 63 | 64 | **思路:** 65 | 66 | 1. 记录【今天之前买入的最小值】 67 | 2. 计算【今天之前最小值买入,今天卖出的获利】,也即【今天卖出的最大获利】 68 | 3. 比较【每天的最大获利】,取最大值即可 69 | 70 | ```java 71 | class Solution { 72 | public int maxProfit(int[] prices) { 73 | if(prices.length <= 1) 74 | return 0; 75 | int min = prices[0], max = 0; 76 | for(int i = 1; i < prices.length; i++) { 77 | max = Math.max(max, prices[i] - min); 78 | min = Math.min(min, prices[i]); 79 | } 80 | return max; 81 | } 82 | } 83 | ``` 84 | 85 | -------------------------------------------------------------------------------- /11 分布式与微服务/02 分布式/notes/分布式锁.md: -------------------------------------------------------------------------------- 1 | # 分布式锁 2 | 3 | 在单机场景下,可以使用语言的内置锁来实现进程同步。但是在分布式场景下,需要同步的进程可能位于不同的节点上,那么就需要使用分布式锁。 4 | 5 | 阻塞锁通常使用互斥量来实现: 6 | 7 | - 互斥量为 0 表示有其它进程在使用锁,此时处于锁定状态; 8 | - 互斥量为 1 表示未锁定状态。 9 | 10 | 1 和 0 可以用一个整型值表示,也可以用某个数据是否存在表示。 11 | 12 | ## 数据库的唯一索引 13 | 14 | 获得锁时向表中插入一条记录,释放锁时删除这条记录。唯一索引可以保证该记录只被插入一次,那么就可以用这个记录是否存在来判断是否存于锁定状态。 15 | 16 | 存在以下几个问题: 17 | 18 | - 锁**没有失效时间**,解锁失败的话其它进程无法再获得该锁。 19 | - 只能是**非阻塞锁**,插入失败直接就报错了,无法重试。 20 | - **不可重入**,已经获得锁的进程也必须重新获取锁。 21 | 22 | ## Redis 的 SETNX 指令 23 | 24 | 使用 SETNX(set if not exist)指令插入一个键值对,**如果 Key 已经存在,那么会返回 False,否则插入成功并返回 True。** 25 | 26 | SETNX 指令和数据库的唯一索引类似,保证了只存在一个 Key 的键值对,那么可以用一个 Key 的键值对是否存在来判断是否存于锁定状态。 27 | 28 | EXPIRE 指令可以为一个键值对设置一个过期时间,从而避免了数据库唯一索引实现方式中释放锁失败的问题。 29 | 30 | ## Redis 的 RedLock 算法 31 | 32 | 使用了多个 Redis 实例来实现分布式锁,这是为了保证在发生单点故障时仍然可用。 33 | 34 | - 尝试从 N 个互相独立 Redis 实例获取锁; 35 | - 计算获取锁消耗的时间,只有当这个时间小于锁的过期时间,并且从大多数(N / 2 + 1)实例上获取了锁,那么就认为锁获取成功了; 36 | - 如果锁获取失败,就到每个实例上释放锁。 37 | 38 | ## Zookeeper 的有序节点 39 | 40 | ### 1. Zookeeper 抽象模型 41 | 42 | Zookeeper 提供了一种树形结构的命名空间,/app1/p_1 节点的父节点为 /app1。 43 | 44 | ![img](https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/aefa8042-15fa-4e8b-9f50-20b282a2c624.png) 45 | 46 | ### 2. 节点类型 47 | 48 | - 永久节点:不会因为会话结束或者超时而消失; 49 | - 临时节点:如果会话结束或者超时就会消失; 50 | - 有序节点:会在节点名的后面加一个数字后缀,并且是有序的,例如生成的有序节点为 /lock/node-0000000000,它的下一个有序节点则为 /lock/node-0000000001,以此类推。 51 | 52 | ### 3. 监听器 53 | 54 | 为一个节点注册监听器,在节点状态发生改变时,会给客户端发送消息。 55 | 56 | ### 4. 分布式锁实现 57 | 58 | - 创建一个锁目录 /lock; 59 | - 当一个客户端需要获取锁时,在 /lock 下创建临时的且有序的子节点; 60 | - 客户端获取 /lock 下的子节点列表,判断自己创建的子节点是否为当前子节点列表中序号最小的子节点,如果是则认为获得锁;否则监听自己的前一个子节点,获得子节点的变更通知后重复此步骤直至获得锁; 61 | - 执行业务代码,完成后,删除对应的子节点。 62 | 63 | ### 5. 会话超时 64 | 65 | 如果一个已经获得锁的会话超时了,因为创建的是临时节点,所以该会话对应的临时节点会被删除,其它会话就可以获得锁了。可以看到,Zookeeper 分布式锁不会出现数据库的唯一索引实现的分布式锁释放锁失败问题。 66 | 67 | ### 6. 羊群效应 68 | 69 | 一个节点未获得锁,只需要监听自己的前一个子节点,这是因为如果监听所有的子节点,那么任意一个子节点状态改变,其它所有子节点都会收到通知(羊群效应),而我们只希望它的后一个子节点收到通知。 -------------------------------------------------------------------------------- /06 计算机网络/notes/计算机网络体系结构.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1. 说一下OSI七层模型 TCP/IP四层模型 五层协议 4 | 5 | 分层的方法 6 | 7 | ![](https://raw.githubusercontent.com/wuqifan1098/picBed/master/7%E5%B1%82%E6%A8%A1%E5%9E%8B%20%E5%9B%9B%E5%B1%82%E6%A8%A1%E5%9E%8B%20%E4%BA%94%E5%B1%82%E5%8D%8F%E8%AE%AE.png) 8 | 9 | 10 | 七层中各层的作用 11 | 12 | ![](https://raw.githubusercontent.com/wuqifan1098/picBed/master/%E5%90%84%E5%B1%82%E7%9A%84%E4%BD%9C%E7%94%A8.png) 13 | 14 | ## 2.哪一层有差错校验,有什么方法 (美团) 15 | 16 | 传输层 17 | 18 | # OSI参考模型 19 | 20 | - 应用层:提供**用户接口**,特制能够发起网络通信的应用程序,比如客户端程序,QQ,浏览器等,服务器程序有Web服务器,邮件服务器,流媒体服务器等。 21 | 22 | - 表示层:使用**何种编码方式**。比如要传输的数据使用ASCI编码,Unicode编码还是二进制文件,是否要加密和压缩。发送端和接收端程序必须使用相同的编码方式,才能正确显示,否则就产生乱码。 23 | 24 | - 会话层:通信的应用程序之间建立、维护和释放面向用户的连接。通信的应用程序之间立会话,需要传输层建立1个或多个连接。 25 | 26 | - 传输层:负责**在通信的两个计算机之间建立连接**,实现**可靠的或不可靠的数据通信**, 能够发现发送端和接收端的丢包重传,访量控制。 27 | - 传输控制协议 TCP,提供**面向连接、可靠的数据传输服务**,数据单位为报文段; 28 | - 用户数据报协议 UDP,提供**无连接、尽最大努力的数据传输服务**,数据单位为用户数据报。 29 | - TCP 主要提供完整性服务,UDP 主要提供及时性服务。 30 | 31 | - 网路层:路由器查看数据包目标IP地址,**根据路由表为数据包选择路径**。路由表中的条目可以人工添加静态路由) 也可以动态生成(动态路由) 。 32 | 33 | - 数据链路层:不同的网络类型,发送数据的机制不同,数据链路层就是将数据包封装成能够在不同网络传输的帧。能够进行差错检查,但不纠错,检测出错误去掉该帧。 34 | 35 | - 物理层:该层规定了**网络设备接口标准、电压标准**。尽可能的通过频分复用、时分复用技术在通信和链路上更快的传输数据。 36 | 37 | # TCP/IP模型 38 | 39 | 它只有四层,相当于五层协议中**数据链路层和物理层**合并为**网络接口层**。 40 | 41 | DNS,HTTP,FTP等协议在应用层; 42 | 43 | TCP/UDP在传输层; 44 | 45 | IP在网络层。 46 | 47 | # 五层协议 48 | 49 | - **应用层** :为特定应用程序提供数据传输服务,例如 HTTP、DNS 等协议。数据单位为报文。 50 | - **传输层** :为进程提供通用数据传输服务。由于应用层协议很多,定义通用的传输层协议就可以支持不断增多的应用层协议。运输层包括两种协议:传输控制协议 TCP,提供面向连接、可靠的数据传输服务,数据单位为报文段;用户数据报协议 UDP,提供无连接、尽最大努力的数据传输服务,数据单位为用户数据报。TCP 主要提供完整性服务,UDP 主要提供及时性服务。 51 | - **网络层** :为主机提供数据传输服务。而传输层协议是为主机中的进程提供数据传输服务。网络层把传输层传递下来的报文段或者用户数据报封装成分组。 52 | - **数据链路层** :网络层针对的还是主机之间的数据传输服务,而主机之间可以有很多链路,链路层协议就是为同一链路的主机提供数据传输服务。数据链路层把网络层传下来的分组封装成帧。 53 | - **物理层** :考虑的是怎样在传输媒体上传输数据比特流,而不是指具体的传输媒体。物理层的作用是尽可能屏蔽传输媒体和通信手段的差异,使数据链路层感觉不到这些差异。 54 | 55 | # 数据在各层之间的传递过程 56 | 57 | 在向下的过程中,需要添加下层协议所需要的首部或者尾部,而在向上的过程中不断拆开首部和尾部。 58 | 59 | 路由器只有下面三层协议,因为路由器位于网络核心中,不需要为进程或者应用程序提供服务,因此也就不需要传输层和应用层。 -------------------------------------------------------------------------------- /01 JavaSe/01 集合框架/notes/TreeSet and TreeMap.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1.TreeMap 最大的特点是什么? 4 | 5 | TreeMap 在一个“红-黑”树的基础上实现。查看键或者“键-值”对时,它们会按固定的顺序排列(取决于Comparable或Comparator,稍后即会讲到)。TreeMap最大的好处就是我们得到的是**已排好序的结果**。 6 | 7 | 在需要排序的Map时候才用TreeMap。 8 | 9 | # TreeSet and TreeMap 10 | 11 | # 总体介绍 12 | 13 | 之所以把TreeSet和TreeMap放在一起讲解,是因为二者在Java里有着相同的实现,前者仅仅是对后者做了一层包装,也就是说TreeSet里面有一个**TreeMap(适配器模式)**。因此本文将重点分析TreeMap。 14 | 15 | TreeMap底层通过**红黑树**(Red-Black tree)实现,也就意味着containsKey(), get(), put(), remove()都有着**log(n)**的时间复杂度。 16 | 17 | ![](https://raw.githubusercontent.com/wuqifan1098/picBed/master/TreeMap_base.png) 18 | 19 | **红黑树是一种近似平衡的二叉查找树,它能够确保任何一个节点的左右子树的高度差不会超过二者中较低那个的一陪。** 20 | 21 | - 每个节点要么是红色,要么是黑色。 22 | - **根节点必须是黑色** 23 | - **红色节点不能连续**(也即是,红色节点的孩子和父亲都不能是红色)。 24 | - 对于每个节点,从该点至null(树尾端)的任何路径,**都含有相同个数的黑色节点**。 25 | 26 | # 预备知识 27 | 28 | 当查找树的结构发生改变时,红黑树的约束条件可能被破坏,**需要通过调整使得查找树重新满足红黑树的约束条件。**调整可以分为两类:一类是颜色调整,即**改变某个节点的颜色**;另一类是结构调整,集改变检索树的结构关系。结构调整过程包含两个基本操作:**左旋(Rotate Left),右旋(RotateRight)。** 29 | 30 | ## 左旋 31 | 32 | 左旋的过程是将x的**右子树绕x逆时针旋转**,**使得x的右子树成为x的父亲**,同时修改相关节点的引用。旋转之后,二叉查找树的属性仍然满足。 33 | 34 | ![](https://raw.githubusercontent.com/wuqifan1098/picBed/master/TreeMap_rotateLeft.png) 35 | 36 | ## 右旋 37 | 38 | 右旋的过程是将x的**左子树绕x顺时针旋转,使得x的左子树成为x的父亲**,同时修改相关节点的引用。旋转之后,二叉查找树的属性仍然满足。 39 | 40 | ![](https://raw.githubusercontent.com/wuqifan1098/picBed/master/TreeMap_rotateRight.png) 41 | 42 | # TreeSet 43 | 44 | TreeSet是对TreeMap的简单包装,对TreeSet的函数调用都会转换成合适的TreeMap方法,因此TreeSet的实现非常简单。 45 | 46 | ```java 47 | // TreeSet是对TreeMap的简单包装 48 | public class TreeSet extends AbstractSet 49 | implements NavigableSet, Cloneable, java.io.Serializable 50 | { 51 | ...... 52 | private transient NavigableMap m; 53 | // Dummy value to associate with an Object in the backing Map 54 | private static final Object PRESENT = new Object(); 55 | public TreeSet() { 56 | this.m = new TreeMap();// TreeSet里面有一个TreeMap 57 | } 58 | ...... 59 | public boolean add(E e) { 60 | return m.put(e, PRESENT)==null; 61 | } 62 | ...... 63 | } 64 | ``` -------------------------------------------------------------------------------- /01 JavaSe/03 基础概念/notes/Object.md: -------------------------------------------------------------------------------- 1 | ## Object类简介 2 | 3 | Object类是所有类的父类,在Java中只有基本数据类型不是对象。对于所有数组类型(对象类型&&基本数据类型数组)都继承于Object类; 4 | 5 | ## equals方法 6 | 7 | Object类中通过判断两个对象是否具有相同引用,从而判断两个对象是否相同; 8 | **子类只要重写equals方法,就必须重写hashCode方法** 9 | 10 | ```java 11 | // in java.lang.Object 12 | public boolean equals(Object obj) { 13 | return (this == obj); 14 | } 15 | ``` 16 | 17 | ### 重写equals方法原则: 18 | 19 | - **自反性**:A.equals(A)返回true; 20 | - **对称性**:A.equals(B)结果和B.equals(A)相同; 21 | - **传递性**:A.equals(B)为true,B.equals(C)为true,则A.equals(C)为true 22 | - **一致性**:对于非null引用A,B, 只要equals()比较操作所用到对象信息不变,多次调用A.equals(B),结果一致; 23 | - 对于任何非null引用,x.equals(null)必须返回false; 24 | - **重写equals方法时,参数类型必须为Object类型** 25 | 26 | ### 重写equals方法示例 27 | 28 | ```java 29 | class myObject { 30 | private String name; 31 | private int age; 32 | ... 33 | public getName() { 34 | return this.name; 35 | } 36 | public getAge() { 37 | return this.age; 38 | } 39 | } 40 | 41 | /** 42 | * 重写equals方法demo步骤 43 | * Effective Java中推荐方式 44 | */ 45 | public boolean equals(Object x) { 46 | // 1. 检查x和this是否引用同一个对象 47 | if (x == this) { 48 | return true; 49 | } 50 | 51 | // 2. 检查x对象类型是否是myObject派生 52 | if (!(x instanceof myObject)) { 53 | return false; 54 | } 55 | 56 | // 3. 比较数据域 57 | // 经过1,2检查,将参数转换为正确类型 58 | myObject o = (myObject)(x); 59 | return this.name.equals(x.getName()) && this.age == (x.getAge()); 60 | } 61 | ``` 62 | 63 | ## hashCode()方法 64 | 65 | `hashCode方法`返回对象的散列码,**相等对象必须返回相等的hashCode,不同对象的hashCode尽可能不相等**; 66 | 67 | ```java 68 | // in java.lang.Object 69 | public native int hashCode(); 70 | ``` 71 | 72 | ## 重写equals时总要重写hashCode 73 | 74 | - 重写equals不重写hashCode,会导致**“不相等对象拥有相同的hashCode”**,导致集合类`HashMap`,`HashSet`和`Hashtable`无法工作;极端情况下,在散列表中使所有对象的hashCode都相等,所有对象都被映射到同一个桶中,散列表退化成链表; 75 | - 当两个对象调用equal返回**true**,则两个对象各自调用hashCode()返回**相同**hashCode; 76 | - 当两个对象调用equal返回false, 两个对象各自调用hashCode()返回的hashCode可以相同(**散列冲突不能完全避免**) 77 | 78 | ## toString()方法 79 | 80 | Object类中toString方法,输出对象的“对象类名@散列码”; -------------------------------------------------------------------------------- /08 数据库/01 MySQL/notes/分库分表.md: -------------------------------------------------------------------------------- 1 | # 分库与分表 2 | 3 | 简单来说,数据的切分就是通过某种特定的条件,将我们存放在**同一个数据库中的数据分散存放到多个数据库(主机)中,以达到分散单台设备负载的效果,即分库分表**。 4 | 5 | ## **1. 分表与分区的不同** 6 | 7 | 分表,就是讲一张表分成多个小表,这些小表拥有不同的表名;而分区是将一张表的数据分为多个区块,这些区块可以存储在同一个磁盘上,也可以存储在不同的磁盘上,这种方式下表仍然只有一个。 8 | 9 | ## **2. 使用分库与分表的原因** 10 | 11 | 随着时间和业务的发展,数据库中的表会越来越多,并且表中的数据量也会越来越大,那么读写操作的开销也会随着增大。 12 | 13 | ## **3. 垂直切分** 14 | 15 | 垂直切分是将**一张表按列切分成多个表**,通常是按照列的关系密集程度进行切分,也可以利用垂直切分将经常被使用的列和不经常被使用的列切分到不同的表中。 16 | 17 | 将**表按功能模块、关系密切程度划分出来,部署到不同的库**上。例如,我们会建立商品数据库 payDB、用户数据库 userDB 等,分别用来存储项目与商品有关的表和与用户有关的表。 18 | 19 | ### 垂直切分的优点 20 | 21 | - 拆分后业务清晰,拆分规则明确 22 | 23 | - 系统之间进行整合或扩展很容易 24 | 25 | - 按照成本、应用的等级、应用的类型等将表放到不同的机器上,便于管理 26 | 27 | - 便于实现动静分离、冷热分离的数据库表的设计模式 28 | 29 | 数据维护简单 30 | 31 | ### 垂直切分的缺点 32 | 33 | - 部分业务表无法关联(Join),只能通过接口方式解决,提高了系统的复杂度 34 | 35 | - 受每种业务的不同限制,存在单库性能瓶颈,不易进行数据扩展和提升性能 36 | 37 | - 事务处理复杂 38 | 39 | 40 | ## **4. 水平切分** 41 | 42 | 把表中的数据按照某种规则存储到多个结构相同的表中,例如按 id 的散列值、性别等进行划分, 43 | 44 | ### 水平切分的优点 45 | 46 | - 单库单表的数据保持在一定的量级,有助于性能的提高 47 | - 切分的表的结构相同,应用层改造较少,只需要增加路由规则即可 48 | - 提高了系统的稳定性和负载能力 49 | 50 | ### 水平切分的缺点 51 | 52 | - 切分后,数据是分散的,很难利用数据库的Join操作,跨库Join性能较差 53 | - 拆分规则难以抽象 54 | - 分片事务的一致性难以解决 55 | - 数据扩容的难度和维护量极大 56 | 57 | ## **5. 垂直切分与水平切分的选择** 58 | 59 | 如果数据库中的表太多,并且项目各项业务逻辑清晰,那么垂直切分是首选。 60 | 61 | 如果数据库的表不多,但是单表的数据量很大,应该选择水平切分。 62 | 63 | ## **6. 水平切分的实现方式** 64 | 65 | 最简单的是使用 merge 存储引擎。 66 | 67 | ## **7. 分库与分表存在的问题** 68 | 69 | - 垂直切分和水平切分的共同点 70 | - 存在分布式事务的问题 71 | - 存在跨节点Join的问题 72 | - 存在跨节点合并排序、分页的问题 73 | - 存在多数据源管理的问题 74 | 75 | (1) 事务问题 76 | 77 | 在执行分库分表之后,由于数据存储到了不同的库上,数据库事务管理出现了困难。如果依赖数据库本身的分布式事务管理功能去执行事务,将付出高昂的性能代价;如果由应用程序去协助控制,形成程序逻辑上的事务,又会造成编程方面的负担。 78 | 79 | (2) 跨库跨表连接问题 80 | 81 | 在执行了分库分表之后,难以避免会将原本逻辑关联性很强的数据划分到不同的表、不同的库上。这时,表的连接操作将受到限制,我们无法连接位于不同分库的表,也无法连接分表粒度不同的表,导致原本只需要一次查询就能够完成的业务需要进行多次才能完成。 82 | 83 | ## 常用的分库分表中间件 84 | 85 | 简单易用的组件: 86 | 87 | - 当当sharding-jdbc 88 | - 蘑菇街TSharding 89 | 90 | 强悍重量级的中间件: 91 | 92 | - sharding 93 | - TDDL Smart Client的方式(淘宝) 94 | - Atlas(Qihoo 360) 95 | - alibaba.cobar(是阿里巴巴(B2B)部门开发) 96 | - MyCAT(基于阿里开源的Cobar产品而研发) 97 | - Oceanus(58同城数据库中间件) 98 | - OneProxy(支付宝首席架构师楼方鑫开发) 99 | - vitess(谷歌开发的数据库中间件) -------------------------------------------------------------------------------- /01 JavaSe/03 基础概念/notes/多态.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1. 怎么理解多态(美团) 4 | 5 | **同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。** 6 | 7 | 如果按照这个概念来定义的话,那么多态应该是一种运行期的状态。 为了实现运行期的多态,或者说是动态绑定,需要满足三个条件。 8 | 9 | **即有类继承或者接口实现、子类要重写父类的方法、父类的引用指向子类的对象。** 10 | 11 | 多态就是同一个接口,使用不同的实例而执行不同操作,如图所示: 12 | 13 | ![img](https://mmbiz.qpic.cn/mmbiz_png/yrbzLUhDJu02wewSgmgf7ySdDib23ibnFeZUnicQWBBFwpIPzfD7JjqwehyuC1sVSqJeVNuVxxVLrYpcEJicIyLQJQ/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 14 | 15 | 简单来一段代码解释下: 16 | 17 | ```java 18 | public class Parent{ 19 | 20 | public void call(){ 21 | sout("im Parent"); 22 | } 23 | } 24 | 25 | public class Son extends Parent{// 1.有类继承或者接口实现 26 | public void call(){// 2.子类要重写父类的方法 27 | sout("im Son"); 28 | } 29 | } 30 | 31 | public class Daughter extends Parent{// 1.有类继承或者接口实现 32 | public void call(){// 2.子类要重写父类的方法 33 | sout("im Daughter"); 34 | } 35 | } 36 | 37 | public class Test{ 38 | 39 | public static void main(String[] args){ 40 | Parent p = new Son(); //3.父类的引用指向子类的对象 41 | Parent p1 = new Daughter(); //3.父类的引用指向子类的对象 42 | } 43 | } 44 | ``` 45 | 46 | 这样,就实现了多态,同样是Parent类的实例,p.call 调用的是Son类的实现、p1.call调用的是Daughter的实现。 有人说,你自己定义的时候不就已经知道p是son,p1是Daughter了么。但是,有些时候你用到的对象并不都是自己声明的啊 。 比如Spring 中的IOC出来的对象,你在使用的时候就不知道他是谁,或者说你可以不用关心他是谁。根据具体情况而定。 47 | 48 | 另外,还有一种说法,包括维基百科也说明,多态还分为动态多态和静态多态。 上面提到的那种动态绑定认为是动态多态,因为只有在运行期才能知道真正调用的是哪个类的方法。 49 | 50 | 还有一种静态多态,一般认为Java中的函数重载是一种静态多态,因为他需要在编译期决定具体调用哪个方法、 51 | 52 | 转载: https://github.com/hollischuang/toBeTopJavaer/blob/master/basics/java-basic/polymorphism.md 53 | 54 | https://mp.weixin.qq.com/s?__biz=MzU3MDc3OTI1NA==&mid=2247484681&idx=1&sn=b09a69f660105dd676790c883e9e4a28&chksm=fceb7610cb9cff0652973811899d0e66ef1c1cc23c60631a78a43bd38c43c2da8f92747aea3c&mpshare=1&scene=1&srcid=&sharer_sharetime=1568611254544&sharer_shareid=6bdaaaa7a7186e9db8bed8df0280488e&key=cc53f48e7cf7aa7ed4802fd11a1c7d2a60ff15e3ea513bc6449d28089d864cf27d7068c1fe9d391d15ef021efd32cef05c26406a2800b330af62b66c9cd88e8975a36ba1d85d528eb258b59111c4a3cb&ascene=1&uin=NjQwMDg5ODE2&devicetype=Windows+10&version=62060833&lang=zh_CN&pass_ticket=a4F7soNIQYb1PpIqG%2B5cOa6dCQ7j%2Blo0DiOeBmEY2ALSbWV3ozWD1AfnsIAnEFiR -------------------------------------------------------------------------------- /02 JVM/notes/JVM内存对象.md: -------------------------------------------------------------------------------- 1 | # 对象的创建 2 | 3 | java程序中创建对象的常用方式是: 4 | 5 | ``` 6 | `Object obj = ``new` `Object();` 7 | ``` 8 | 9 | 该行代码的执行过程如下: 10 | 11 | ![](https://raw.githubusercontent.com/wuqifan1098/picBed/master/%E5%AF%B9%E8%B1%A1%E5%88%9B%E5%BB%BA%E8%BF%87%E7%A8%8B.png) 12 | 13 | 从图中我们可以发现**对象创建的步骤**如下 14 | 15 | 1. 执行new执行 16 | 2. 检查这个指令参数是否能够在常量池中定位到一个类的符号引用,并且检查这个符号引用所代表的类是否已经被加载,解析和初始化。 17 | 3. 如果该类没有被加载则先执行类的加载操作 18 | 4. 如果该类已经被加载,则开始给该对象在jvm的堆中分配内存。分配规则后面介绍 19 | 5. 虚拟机初始化操作,虚拟机对分配的空间初始化为零值。 20 | 6. 执行init方法,初始化对象的属性,至此对象被创建完成。 21 | 7. java虚拟机栈中的Reference执行我们刚刚创建的对象。 22 | 23 | 在上面的过程中的类加载的过程,后面会单独介绍,而内存分配这块我们来介绍下 24 | 25 | # **内存的分配原则** 26 | 27 | 内存分配的基本原则: 28 | 29 | | 序号 | 介绍 | 30 | | :--- | :----------------------------------------------------------- | 31 | | 1 | 优先在Eden分配,如果Eden空间不足虚拟机则会进行一次MinorGC | 32 | | 2 | 大对象直接接入老年代,很长的字符串或数组 | 33 | | 3 | 长期存活的对象进入老年代,每个对象都有一个age,当age到达设定的年龄的时候就会进入老年代,默认是15岁 | 34 | 35 | **内存的分配方法** 36 | 37 | 内存分配的方法有两种:指针碰撞(Bump the Pointer)和空闲列表(Free List) 38 | 39 | | 分配方法 | 说明 | 收集器 | 40 | | :------- | :--------------- | :-------------------------- | 41 | | 指针碰撞 | 内存地址是连续的 | Serial和ParNew收集器 | 42 | | 空闲列表 | 内存地址不连续 | CMS收集器和Mark-Sweep收集器 | 43 | 44 | **内存分配的安全问题** 45 | 46 | 在分配内存的同时,存在线程安全的问题,即虚拟机给A线程分配内存过程中,指针未修改,B线程可能同时使用了同样一块内存。 47 | 在JVM中有两种解决办法: 48 | 49 | 1. 同步处理,即CAS(compare & swap)搭配失败重试的方式 50 | 2. 将内存分配的动作按线程分配到不同空间中,每个线程都有一小块内存,成为**本地线程分配缓冲**(Thread Local Allocation Buffer即TLAB)。 51 | 52 | # **对象的访问定位** 53 | 54 | 建立对象是为了使用对象,java程序是通过栈上的reference数量来操作堆上的具体的对象,具体操作对象的方式有两种: 55 | 56 | **通过句柄访问对象** 57 | 58 | ![](https://raw.githubusercontent.com/wuqifan1098/picBed/master/%E5%8F%A5%E6%9F%84%E8%AE%BF%E9%97%AE%E5%AF%B9%E8%B1%A1.png) 59 | 60 | **通过直接指针访问对象** 61 | 62 | ![](https://raw.githubusercontent.com/wuqifan1098/picBed/master/%E6%8C%87%E9%92%88%E8%AE%BF%E9%97%AE%E5%AF%B9%E8%B1%A1.png) 63 | 64 | 两种方式的比较 65 | 66 | | 方式 | 优点 | 67 | | :------- | :----------------------------------- | 68 | | 句柄 | 稳定,对象被移动只要修改句柄中的地址 | 69 | | 直接指针 | 访问速度快,节省了一次指针定位的开销 | 70 | 71 | https://www.jb51.net/article/157742.htm -------------------------------------------------------------------------------- /01 JavaSe/03 基础概念/notes/反射.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1.什么是反射机制?(贝贝) 4 | 5 | Java 反射机制在程序**运行时**,对于任意一个类,都能够知道这个类的**所有属性和方法**;对于任意一个对象,都能够调用它的任意一个方法和属性。这种 **动态的获取信息** 以及 **动态调用对象的方法** 的功能称为 **java 的反射机制**。 6 | 7 | - 简单来说反射就是**解剖一个类,然后获取这个类中的属性和方法**,前提是要获取这个类的Class对象 8 | 9 | ## 2. 反射机制的具体实现(贝贝) 10 | 11 | 首先都要获取Class对象,判断某个类是否为某个类的实例,创建实例,获取方法,获取构造器信息,获取类的成员变量,调用方法 12 | 13 | https://juejin.im/post/598ea9116fb9a03c335a99a4 14 | 15 | https://blog.csdn.net/android_ku_ku/article/details/52336734 16 | 17 | https://www.jianshu.com/p/3ea4a6b57f87 18 | 19 | ## 3.反射的用途(趋势科技) 20 | 21 | 解耦的作用,不用去new,可以通过**反射获得实例化对象,获取类的所有方法** 22 | 23 | 应用程序已经运行,**无法在其中进行new对象的建立,就无法使用对象**。这时可以根据配置文件的类全名去找对应的字节码文件,并加载进内存,并创建该类对象实例。 24 | 25 | https://www.zhihu.com/question/24304289 26 | 27 | # 反射 28 | 29 | 每个类都有一个 **Class** 对象,包含了与类有关的信息。当编译一个新类时,会产生一个同名的 .class 文件,该文件内容保存着 Class 对象。 30 | 31 | 类加载相当于 Class 对象的加载,类在第一次使用时才动态加载到 JVM 中。也可以使用 `Class.forName("com.mysql.jdbc.Driver")` 这种方式来控制类的加载,该方法会返回一个 Class 对象。 32 | 33 | 反射可以提供运行时的类信息,并且这个类可以在运行时才加载进来,甚至在编译时期该类的 .class 不存在也可以加载进来。 34 | 35 | Class 和 java.lang.reflect 一起对反射提供了支持,java.lang.reflect 类库主要包含了以下三个类: 36 | 37 | - **Field** :可以使用 get() 和 set() 方法读取和修改 Field 对象关联的字段; 38 | - **Method** :可以使用 invoke() 方法调用与 Method 对象关联的方法; 39 | - **Constructor** :可以用 Constructor 创建新的对象。 40 | 41 | ## **反射的优点:** 42 | 43 | - **可扩展性** :应用程序可以利用全限定名创建可扩展对象的实例,来使用来自外部的用户自定义类。 44 | - **类浏览器和可视化开发环境** :一个类浏览器需要可以枚举类的成员。可视化开发环境(如 IDE)可以从利用反射中可用的类型信息中受益,以帮助程序员编写正确的代码。 45 | - **调试器和测试工具** : 调试器需要能够检查一个类里的私有成员。测试工具可以利用反射来自动地调用类里定义的可被发现的 API 定义,以确保一组测试中有较高的代码覆盖率。 46 | 47 | ## **反射的缺点:** 48 | 49 | 尽管反射非常强大,但也不能滥用。如果一个功能可以不用反射完成,那么最好就不用。在我们使用反射技术时,下面几条内容应该牢记于心。 50 | 51 | - **性能开销** :反射涉及了动态类型的解析,所以 JVM 无法对这些代码进行优化。因此,反射操作的效率要比那些非反射操作低得多。我们应该避免在经常被执行的代码或对性能要求很高的程序中使用反射。 52 | - **安全限制** :使用反射技术要求程序必须在一个没有安全限制的环境中运行。如果一个程序必须在有安全限制的环境中运行,如 Applet,那么这就是个问题了。 53 | - **内部暴露** :由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用,这可能导致代码功能失调并破坏可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。 54 | 55 | - [Trail: The Reflection API](https://docs.oracle.com/javase/tutorial/reflect/index.html) 56 | - [深入解析 Java 反射(1)- 基础](http://www.sczyh30.com/posts/Java/java-reflection-1/) 57 | 58 | # 总结 59 | 60 | 反射之中包含了一个“反”的概念,所以要想解释反射就必须先从“正”开始解释,一般而言,当用户使用一个类的时候,应该**先知道这个类,而后通过这个类产生实例化对象,但是“反”指的是通过对象找到类。** 61 | 62 | -------------------------------------------------------------------------------- /10 项目/03 电商基础秒杀/notes/负载均衡.md: -------------------------------------------------------------------------------- 1 | 负载均衡是高可用网络基础架构的的一个关键组成部分,有了负载均衡,我们通常可以将我们的应用服务器部署多台,然后通过负载均衡将用户的请求分发到不同的服务器用来提高网站、应用、数据库或其他服务的性能以及可靠性。 2 | 3 | ## 为什么要引入负载均衡 4 | 5 | 先看一个没有负载均衡机制的web架构: 6 | 7 | ![img](https://img-blog.csdn.net/20180614101618504?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21vYWt1bg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) 8 | 9 | 上图中的架构有什么缺陷了?首先,用户是通过网络直接和web服务器相连,想象一下,如果这个服务器挂了(这种情况随时都可能发生的),那么用户的请求就会得不到响应,将无法访问该网站,这就是著名的单点故障问题,这肯定是不行的,一般而言,商业上的网站其可靠性需要达到至少4个9,也就是99.99&以上。 10 | 11 | **其次,即使服务器是正常工作的情况,但是如果很多用户在同一时间内访问服务器,超过了服务器的处理能力,那么会出现响应速度慢甚至无法连接的情况,这也是用户无法接受的。** 12 | 13 | 负载均衡的出现可以很好的解决上面两个问题,通过引入一个负载均衡器和至少两个web 服务器,可以有效的解决上面两个问题。注:通常情况下,所有的后端服务器会保证提供相同的内容,以便用户无论哪个服务器响应,都能收到一致的内容。 14 | 15 | ![img](https://img-blog.csdn.net/20180614101627539?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21vYWt1bg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) 16 | 17 | 如上图架构,现在,即使App 01即使挂了,负载均衡会将用户的请求转发到正常工作的App 02上,这解决了上面的第一个问题;其次,根据业务需要,负载均衡后端的App可以很方便的扩展,这样就能解决第上面的第二个问题。但是,现在单点故障问题转移到了负载均衡器,可以通过引入第二个负载均衡器来缓解,后面还会讲到。 18 | 19 | ## 负载均衡如何选择要转发的后端服务器 20 | 21 | 负载均衡器一般根据两个因素来决定要将请求转发到哪个服务器。 22 | 23 | 1:确保所选择的后端服务器是正常工作的,能给对用户的请求做出响应; 24 | 25 | 2:根据预先设置的负载均衡算法从健康服务器池中进行选择。 26 | 27 | 由于负载均衡器只应当选择能正常做出响应的后端服务器,因此就需要有一种机制能判断它所连的后端服务器是否正常工作。为了监视后台服务器的运行状况,运行状态检查服务会定期尝试使用转发规则定义的协议和端口去连接后端服务器。如果某个服务器没有通过健康检查,就会从健康池中剔除,保证流量不会被转发到该服务器,直到其再次通过健康检查为止。 28 | 29 | ## 负载均衡算法 30 | 31 | 负载均衡算法决定了后端的哪些健康服务器会被选中。下面是几个常用的算法,这里只是简单介绍,不具体研究其算法实现了,后面会专门用一篇文章来总结: 32 | 33 | 轮询:为第一个请求选择健康池中的第一个后端服务器,然后按顺序往后依次选择,直到最后一个,然后循环。 34 | 35 | 最小连接:优先选择连接数最少,也就是压力最小的后端服务器,在会话较长的情况下可以考虑采取这种方式。 36 | 37 | 散列:根据请求源的 IP 的散列(hash)来选择要转发的服务器。这种方式可以一定程度上保证特定用户能连接到相同的服务器。如果你的应用需要处理状态而要求用户能连接到和之前相同的服务器,可以考虑采取这种方式。 38 | 39 | 最后,想要解决负载均衡器的单点故障问题,可以将第二个负载均衡器连接到第一个上,从而形成一个集群。如下图所示: 40 | 41 | ![img](https://img-blog.csdn.net/20180614101641662?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21vYWt1bg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) 42 | 43 | 当主负载均衡器发生了故障,就需要将用户请求转到第二个负载均衡器。由于 DNS 更改通常会在较长的时间才能生效,因此需要有一种能灵活解决 IP 地址重新映射的方法,比如浮动 IP(floating IP)。这样域名可以保持和相同的 IP 相关联,而 IP 本身则能在服务器之间移动。下面就是一个使用浮动 IP 的负载均衡架构动态示意图: 44 | 45 | ![img](https://img-blog.csdn.net/20180614101652159?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21vYWt1bg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) -------------------------------------------------------------------------------- /08 数据库/01 MySQL/notes/视图.md: -------------------------------------------------------------------------------- 1 | # **一、视图的概念** 2 | 3 | **视图:**是一个虚拟表,其内容由查询定义。同真实的表一样,视图包含一系列带有名称的列和行数据 4 | 5 |   视图(子查询):是从**一个或多个表导出的虚拟的表,其内容由查询定义**。具有普通表的结构,但是不实现数据存储。**单表视图一般用于查询和修改**,会改变基本表的数据;**多表视图一般用于查询**,不会改变基本表的数据。 6 | 7 | 视图有如下特点; 8 |   1. 视图的列可以来自不同的表,是表的抽象和逻辑意义上建立的新关系。 9 |   2. 视图是由基本表(实表)产生的表(虚表)。 10 |   3. 视图的建立和删除不影响基本表。 11 |   4. **对视图内容的更新(添加、删除和修改)直接影响基本表。** 12 |   5. 当视图来自多个基本表时,不允许添加和删除数据。 13 | 14 | 【例子】: 15 |   在一个班级里,作为班主任需要知道全班同学所有课程的成绩,便于全面指导;而数学老师只需要知道全班学生的数学成绩就行了。所以视图的一个重要作用就是区分权限。 16 | 17 | # **二、视图的SQL相关操作** 18 | 19 | ```sql 20 | /**** 1、创建和删除视图 ****/ 21 | 22 | // 创建视图(指定某些字段,显示字段时重命名),后面还可以接WHERE进行条件查询 23 | CREATE VIEW v1(b,a) AS SELECT bookName, author FROM t_book; 24 | // 通过视图来查询(只能查询到指定的字段,提高了安全性) 25 | SELECT * FROM v1; 26 | 27 | // 删除视图(视图只是一种虚拟的表,删除视图对原来的数据表没有影响) 28 | DROP VIEW IF EXISTS v1; 29 | 30 | /**** 2、查看视图 ****/ 31 | 32 | // 查看视图 33 | desc v1; 34 | 35 | // 查看视图基本信息 36 | SHOW TABLE STATUS LIKE 'v1'; 37 | 38 | // 查看视图详细信息 39 | SHOW CREATE VIEW v1; 40 | 41 | /**** 3、修改视图 ****/ 42 | 43 | // 修改视图 44 | CREATE OR REPLACE VIEW v1(b,p) AS SELECT bookName, price FROM t_book; 45 | 46 | ALTER VIEW v1 AS SELECT * FROM t_book; 47 | 48 | /**** 4、更新视图 ****/ 49 | 50 | // 向视图中插入数据(其实就是在表中插入数据) 51 | INSERT INTO v1 VALUES ( "6", "中国历史", "MK", "45", "4"); 52 | 53 | // 更新视图的数据 54 | UPDATE v1 SET price=54 WHERE id=6; 55 | 56 | // 删除视图的数据 57 | DELETE FROM v1 WHERE id=6; 58 | 1234567891011121314151617181920212223242526272829303132333435363738 59 | ``` 60 | 61 | # **三、视图总结** 62 | 63 | **1、视图的作用** 64 | 65 | **(1)简化了操作,把经常使用的数据定义为视图** 66 | 67 |   我们在使用查询时,在很多时候我们要使用聚合函数,同时还要 显示其它字段的信息,可能还会需要关联到其它表,这时写的语句可能会很长,如果这个动作频繁发生的话,我们可以创建视图,这以后,我们只需要select * from view就可以啦,这样很方便。 68 | 69 | **(2)安全性,用户只能查询和修改能看到的数据** 70 | 71 |   因为**视图是虚拟的,物理上是不存在的,只是存储了数据的集合,我们可以将基表中重要的字段信息,可以不通过视图给用户,视图是动态的数据的集合,数据是随着基表的更新而更新**。同时,用户对视图不可以随意的更改和删除,可以保证数据的安全性。 72 | 73 | **(3)逻辑上的独立性,屏蔽了真实表的结构带来的影响** 74 | 75 |   视图可以使应用程序和数据库表在一定程度上独立。如果没有视图,应用一定是建立在表上的。有了视图之后,程序可以建立在视图之上,从而程序与数据库表被视图分割开来。 76 | 77 | **2、视图的缺点** 78 | 79 | **(1)性能差** 80 | 81 |   数据库必须把视图查询转化成对基本表的查询,如果这个视图是由一个复杂的多表查询所定义,那么,即使是视图的一个简单查询,数据库也要把它变成一个复杂的结合体,需要花费一定的时间。 82 | 83 | **(2)修改限制** 84 | 85 |   当用户试图修改视图的某些信息时,数据库必须把它转化为对基本表的某些信息的修改,对于简单的视图来说,这是很方便的,但是,对于比较复杂的试图,可能是不可修改的。 86 | 87 | 参考:https://blog.csdn.net/buhuikanjian/article/details/53105416 -------------------------------------------------------------------------------- /17 中间件/01 消息队列/notes/怎么保证MQ消息不丢失.md: -------------------------------------------------------------------------------- 1 | # **生产者弄丢了数据** 2 | 3 | RabbitMQ生产者将数据发送到rabbitmq的时候,可能数据在网络传输中搞丢了,这个时候RabbitMQ收不到消息,消息就丢了。 4 | 5 | RabbitMQ提供了两种方式来解决这个问题: 6 | 7 | 事务方式: 8 | 9 | 在生产者发送消息之前,通过`channel.txSelect`开启一个事务,接着发送消息 10 | 11 | 如果消息没有成功被RabbitMQ接收到,生产者会收到异常,此时就可以进行事务回滚`channel.txRollback`然后重新发送。假如RabbitMQ收到了这个消息,就可以提交事务`channel.txCommit`。 12 | 13 | 但是这样一来,生产者的吞吐量和性能都会降低很多,现在一般不这么干。 14 | 15 | 另外一种方式就是**通过confirm机制:** 16 | 17 | 这个confirm模式是在生产者哪里设置的,就是每次写消息的时候会分配一个唯一的id,然后RabbitMQ收到之后会回传一个ack,告诉生产者这个消息ok了。 18 | 19 | 如果rabbitmq没有处理到这个消息,那么就回调一个nack的接口,这个时候生产者就可以重发。 20 | 21 | 事务机制和cnofirm机制**最大的不同**在于事务机制是同步的,提交一个事务之后会阻塞在那儿 22 | 23 | 但是confirm机制是异步的,发送一个消息之后就可以发送下一个消息,然后那个消息rabbitmq接收了之后会异步回调你一个接口通知你这个消息接收到了。 24 | 25 | 所以一般在**生产者这块避免数据丢失,都是用confirm机制的**。 26 | 27 | **这样是不是就可以保障100%消息不丢失了呢?** 28 | 29 | 我们看一下confirm的机制,试想一下,**如果我们生产者每发一条消息,都要MQ持久化到磁盘中,然后再发起ack或nack的回调。这样的话是不是我们MQ的吞吐量很不高,因为每次都要把消息持久化到磁盘中。**写入磁盘这个动作是很慢的。这个在高并发场景下是不能够接受的,吞吐量太低了。 30 | 31 | 所以**MQ持久化磁盘真实的实现,是通过异步调用处理的,他是有一定的机制,如:等到有几千条消息的时候,会一次性的刷盘到磁盘上面。而不是每来一条消息,就刷盘一次。** 32 | 33 | 所以**comfirm机制其实是一个异步监听的机制**,是为了**保证系统的高吞吐量**,这样就导致了还是不能够100%保障消息不丢失,因为即使加上了confirm机制,消息在MQ内存中还没有刷盘到磁盘就宕机了,还是没法处理。 34 | 35 | 36 | 37 | # **Rabbitmq弄丢了数据** 38 | 39 | RabbitMQ集群也会弄丢消息,这个问题在官方文档的教程中也提到过,就是说在消息发送到RabbitMQ之后,默认是没有落地磁盘的,万一RabbitMQ宕机了,这个时候消息就丢失了。 40 | 41 | 所以为了解决这个问题,RabbitMQ提供了一个**持久化**的机制,消息写入之后会持久化到磁盘 42 | 43 | 这样哪怕是宕机了,恢复之后也会自动恢复之前存储的数据,这样的机制可以确保消息不会丢失。 44 | 45 | 设置持久化有两个步骤: 46 | 47 | - 第一个是创建queue的时候将其设置为持久化的,这样就可以保证rabbitmq持久化queue的元数据,但是不会持久化queue里的数据 48 | - 第二个是发送消息的时候将消息的deliveryMode设置为2,就是将消息设置为持久化的,此时rabbitmq就会将消息持久化到磁盘上去。 49 | 50 | 但是这样一来可能会有人说:万一消息发送到RabbitMQ之后,还没来得及持久化到磁盘就挂掉了,数据也丢失了,怎么办? 51 | 52 | 对于这个问题,其实是配合上面的confirm机制一起来保证的,就是在消息持久化到磁盘之后才会给生产者发送ack消息。 53 | 54 | 万一真的遇到了那种极端的情况,生产者是可以感知到的,此时生产者可以通过重试发送消息给别的RabbitMQ节点 55 | 56 | # **消费端弄丢了数据** 57 | 58 | RabbitMQ消费端弄丢了数据的情况是这样的:在消费消息的时候,刚拿到消息,结果进程挂了,这个时候RabbitMQ就会认为你已经消费成功了,这条数据就丢了。 59 | 60 | 对于这个问题,要先说明一下RabbitMQ消费消息的机制:在消费者收到消息的时候,会发送一个ack给RabbitMQ,告诉RabbitMQ这条消息被消费到了,这样RabbitMQ就会把消息删除。 61 | 62 | 但是默认情况下这个发送ack的操作是自动提交的,也就是说消费者一收到这个消息就会自动返回ack给RabbitMQ,所以会出现丢消息的问题。 63 | 64 | 所以针对这个问题的解决方案就是:关闭RabbitMQ消费者的自动提交ack,在消费者处理完这条消息之后再手动提交ack。 65 | 66 | 这样即使遇到了上面的情况,RabbitMQ也不会把这条消息删除,会在你程序重启之后,重新下发这条消息过来。 67 | 68 | 69 | 作者:石杉的架构笔记链接:https://juejin.im/post/5d1e201ff265da1b6c5f9423 -------------------------------------------------------------------------------- /06 计算机网络/notes/HTTPS.md: -------------------------------------------------------------------------------- 1 | # 一、HTTPS和HTTP的区别 2 | 3 | HTTPS协议 = HTTP协议 + SSL/TLS协议 4 | SSL的全称是Secure Sockets Layer,即安全套接层协议,是为网络通信提供安全及数据完整性的一种安全协议。TLS的全称是Transport Layer Security,即安全传输层协议。 5 | 即HTTPS是安全的HTTP。 6 | 7 | # 二、HTTPS的连接建立流程 8 | 9 | HTTPS为了兼顾安全与效率,**同时使用了对称加密和非对称加密**。在传输的过程中会涉及到三个密钥: 10 | 11 | - 服务器端的公钥和私钥,用来进行`非对称加密` 12 | - 客户端生成的随机密钥,用来进行`对称加密` 13 | 14 | ![img](https://upload-images.jianshu.io/upload_images/11034989-a8d488a079e6d31b.png?imageMogr2/auto-orient/strip|imageView2/2/w/1000/format/webp) 15 | 16 | 如上图,HTTPS连接过程大致可分为八步: 17 | 18 | **1、客户端访问HTTPS连接。** 19 | 20 | 客户端会把`安全协议版本号`、客户端支持的加密算法列表、`随机数C`发给服务端。 21 | 22 | **2、服务端发送证书给客户端** 23 | 24 | 服务端接收密钥算法配件后,会和自己支持的加密算法列表进行比对,如果不符合,则断开连接。否则,服务端会在该算法列表中,选择一种对称算法(如AES)、一种公钥算法(如具有特定秘钥长度的RSA)和一种MAC算法发给客户端。 25 | 服务器端有一个密钥对,即`公钥`和`私钥`,是用来进行`非对称加密`使用的,服务器端保存着`私钥`,不能将其泄露,`公钥`可以发送给任何人。 26 | 在发送加密算法的同时还会把`数字证书`和`随机数S`发送给客户端 27 | 28 | **3、客户端验证server证书** 29 | 30 | 会对server公钥进行检查,验证其合法性,如果发现发现公钥有问题,那么HTTPS传输就无法继续。 31 | 32 | **4、客户端组装会话秘钥** 33 | 34 | 如果公钥合格,那么客户端会用服务器公钥来生成一个**`前主秘钥`(Pre-Master Secret,PMS),并通过该`前主秘钥`和随机数C、S来组装成`会话秘钥`** 35 | 36 | **5、客户端将前主秘钥加密发送给服务端** 37 | 38 | 是通过**服务端的公钥来对前主秘钥进行非对称加密**,发送给服务端 39 | 40 | **6、服务端通过私钥解密得到前主秘钥** 41 | 42 | 服务端接收到加密信息后,用私钥解密得到主秘钥。 43 | 44 | **7、服务端组装会话秘钥** 45 | 46 | 服务端通过`前主秘钥`和随机数C、S来组装`会话秘钥`。 47 | 至此,服务端和客户端都已经知道了用于此次会话的主秘钥。 48 | 49 | **8、数据传输** 50 | 51 | 客户端收到服务器发送来的密文,用**客户端密钥**对其进行对称解密,得到服务器发送的数据。 52 | 同理,服务端收到客户端发送来的密文,用**服务端密钥**对其进行对称解密,得到客户端发送的数据。 53 | 54 | **总结:** 55 | 56 | ``` 57 | 会话秘钥` = random S + random C + `前主秘钥 58 | ``` 59 | 60 | - HTTPS连接建立过程使用`非对称加密`,而`非对称加密`是很耗时的一种加密方式 61 | - 后续通信过程使用`对称加密`,减少耗时所带来的性能损耗 62 | - 其中,`对称加密`加密的是实际的数据,`非对称加密`加密的是**对称加密所需要的客户端的密钥。** 63 | 64 | # 三、对称加密和非对称加密 65 | 66 | **1、对称加密** 67 | 68 | 用同一套密钥来进行加密解密。 69 | 对称加密通常有 DES,IDEA,3DES 加密算法。 70 | 71 | **2、非对称加密** 72 | 73 | 用公钥和私钥来加解密的算法。 74 | `公钥`(Public Key)与`私钥`(Private Key)是通过一种算法得到的一个密钥对(即一个`公钥`和一个`私钥`),`公钥`是密钥对中公开的部分,`私钥`则是非公开的部分,`私钥`通常是保存在本地。 75 | 76 | - 用`公钥`进行加密,就要用`私钥`进行解密;反之,用`私钥`加密,就要用`公钥`进行解密(数字签名)。 77 | - 由于私钥是保存在本地的,所以`非对称加密`相对与`对称加密`是安全的。 78 | 但`非对称加密`比`对称加密`耗时(100倍以上),所以通常要结合`对称加密`来使用。 79 | 80 | 常见的非对称加密算法有:RSA、ECC(移动设备用)、Diffie-Hellman、El Gamal、DSA(数字签名用) 81 | 82 | 而为了确保客户端能够确认公钥就是想要访问的网站的公钥,引入了数字证书的概念,由于证书存在一级一级的签发过程,所以就出现了证书链,在证书链中的顶端的就是根CA。 83 | 84 | https://www.jianshu.com/p/ac3a80ca59c3 85 | 86 | https://www.kuacg.com/22672.html 87 | 88 | -------------------------------------------------------------------------------- /08 数据库/01 MySQL/notes/Drop,Delete,Truncate.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1. drop、delete与truncate分别在什么场景之下使用? 4 | 5 | drop table 6 | 7 | - 1)属于DDL 8 | - 2)**不可回滚** 9 | - 3)不可带where 10 | - 4)**表内容和结构删除** 11 | - 5)删除速度快 12 | 13 | truncate table 14 | 15 | - 1)属于DDL 16 | - 2)不可回滚 17 | - 3)**不可带where** 18 | - 4)表内容删除 19 | - 5)删除速度快 20 | 21 | delete from 22 | 23 | - 1)属于DML 24 | - 2)可回滚 25 | - 3)可带where 26 | - 4)表结构在,表内容要看where执行的情况 27 | - 5)删除速度慢,需要**逐行删除** 28 | - **不再需要一张表的时候,用drop** 29 | - **想删除部分数据行时候,用delete,并且带上where子句** 30 | - **保留表而删除所有数据的时候用truncate** 31 | 32 | # delete 33 | 34 | 1、delete是DML,执行delete操作时,每次从表中删除一行,并且同时将该行的的删除操作记录在redo和undo表空间中以便进行回滚(rollback)和重做操作,但要注意表空间要足够大,需要手动提交(commit)操作才能生效,可以通过rollback撤消操作。 35 | 36 | 2、delete可根据条件删除表中满足条件的数据,如果不指定where子句,那么删除表中所有记录。 37 | 38 | 3、delete语句不影响表所占用的extent,高水线(high watermark)保持原位置不变。 39 | 40 | # truncate 41 | 42 | 1、truncate是DDL,会隐式提交,所以,不能回滚,不会触发触发器。 43 | 44 | 2、truncate会删除表中所有记录,并且将重新设置高水线和所有的索引,缺省情况下将空间释放到minextents个extent,除非使用reuse storage,。不会记录日志,所以执行速度很快,但不能通过rollback撤消操作(如果一不小心把一个表truncate掉,也是可以恢复的,只是不能通过rollback来恢复)。 45 | 46 | 3、对于外键(foreignkey )约束引用的表,不能使用 truncate table,而应使用不带 where 子句的 delete 语句。 47 | 48 | 4、truncatetable不能用于参与了索引视图的表。 49 | 50 | # drop 51 | 52 | 1、drop是DDL,会隐式提交,所以,不能回滚,不会触发触发器。 53 | 54 | 2、drop语句删除表结构及所有数据,并将表所占用的空间全部释放。 55 | 56 | 3、drop语句将删除表的结构所依赖的约束,触发器,索引,依赖于该表的存储过程/函数将保留,但是变为invalid状态。 57 | 58 | 区别 59 | 1、表和索引所占空间: 60 |   当表被TRUNCATE 后,这个表和索引所占用的空间会恢复到初始大小; 61 |   DELETE操作不会减少表或索引所占用的空间; 62 |   DROP语句将表所占用的空间全释放掉。 63 |    64 | 2、应用范围: 65 |   TRUNCATE 只能对table; 66 |   DELETE可以是table和view。 67 | 68 | 3、执行速度: 69 |   drop > truncate > delete 70 | 71 | 4、delete from删空表后,会保留一个空的页,truncate在表中不会留有任何页。 72 | 73 | 5、DELETE语句执行删除的过程是每次从表中删除一行,并且同时将该行的删除操作作为事务记录在日志中保存以便进行进行回滚操作。 74 |   TRUNCATE TABLE 则一次性地从表中删除所有的数据并不把单独的删除操作记录记入日志保存,删除行是不能恢复的。并且在删除的过程中不会激活与表有关的删除触发器。执行速度快。 75 | 76 | 6、当使用行锁执行 DELETE 语句时,将锁定表中各行以便删除。truncate始终锁定表和页,而不是锁定各行。 77 | 78 | 7、如果有identity产生的自增id列,delete from后仍然从上次的数开始增加,即种子不变; 79 |  使用truncate删除之后,种子会恢复到初始值。 80 | 81 | # 总结 82 | 83 | 1、在速度上,一般来说,drop> truncate > delete。 84 | 85 | 2、在使用drop和truncate时一定要注意,虽然可以恢复,但为了减少麻烦,还是要慎重。 86 | 87 | 3、如果想删除部分数据用delete,注意带上where子句,回滚段要足够大; 88 | 89 | 如果想**删除表**,当然用drop; 90 | 91 | 如果想**保留表而将所有数据删除,如果和事务无关**,用truncate即可; 92 | 93 | 如果**和事务有关,或者想触发trigger**,还是用delete; 94 | 95 | 如果是整理表内部的碎片,可以用truncate跟上reuse stroage,再重新导入/插入数据。 -------------------------------------------------------------------------------- /10 项目/03 电商基础秒杀/notes/第三章知识点.md: -------------------------------------------------------------------------------- 1 | # 左连接 2 | 3 | left join 4 | 5 | 以左表为基础 6 | 7 | # SpringMVC 8 | 9 | ## @PathVariable 10 | 11 | spring mvc中的@PathVariable是用来获得请求url中的动态参数的 12 | 13 | @PathVariable绑定URI模板变量值 14 | 15 | @PathVariable是用来获得请求url中的动态参数的 16 | 17 | @PathVariable用于将请求URL中的模板变量映射到功能处理方法的参数上。//配置url和方法的一个关系*@RequestMapping("item/{itemId}")* 18 | 19 | 20 | 21 | ```java 22 | 1 @RequestMapping("/zyh/{type}") 23 | 2 public String zyh(@PathVariable(value = "type") int type) throws UnsupportedEncodingException { 24 | 3 String url = "http://wx.diyfintech.com/zyhMain/" + type; 25 | 4 if (type != 1 && type != 2) { 26 | 5 throw new IllegalArgumentException("参数错误"); 27 | 6 } 28 | 7 String encodeUrl = URLEncoder.encode(url, "utf-8"); 29 | 8 String redirectUrl = MessageFormat.format(OAUTH_URL, WxConfig.zyhAppId, encodeUrl, "snsapi_userinfo", UUID.randomUUID().toString().replace("-", "")); 30 | 9 return "redirect:" + redirectUrl; 31 | 10 } 32 | ``` 33 | 34 | 在SpringMVC后台控制层获取参数的方式主要有两种: 35 | 36 | 一种是request.getParameter("name"),另外一种是用注解@RequestParam直接获取 37 | 38 | 这里主要讲这个注解 @RequestParam 39 | 40 | 接下来我们看一下@RequestParam注解主要有哪些参数: 41 | 42 | value:参数名字,即入参的请求参数名字,如username表示请求的参数区中的名字为username的参数的值将传入; 43 | 44 | required:是否必须,默认是true,表示请求中一定要有相应的参数,否则将报404错误码; 45 | 46 | defaultValue:默认值,表示如果请求中没有同名参数时的默认值,例如: 47 | 48 | public List getItemTreeNode(@RequestParam(value="id",defaultValue="0")long parentId) 49 | 50 | ```java 51 | 1 @Controller 52 | 2 @RequestMapping("/wx") 53 | 3 public class WxController { 54 | 4 55 | 5 @Autowired 56 | 6 private WxService wxService; 57 | 7 private static final Log log= LogFactory.getLog(WxController.class); 58 | 8 59 | 9 @RequestMapping(value = "/service",method = RequestMethod.GET) 60 | 10 public void acceptWxValid(@RequestParam String signature, @RequestParam String timestamp, @RequestParam String nonce, 61 | 11 @RequestParam String echostr, HttpServletResponse response) throws IOException { 62 | 12 PrintWriter out = response.getWriter(); 63 | 13 if (SignUtil.checkSignature(signature, timestamp, nonce)) { 64 | 14 out.print(echostr); 65 | 15 }else 66 | 16 out.print("fail"); 67 | 17 out.flush(); 68 | 18 out.close(); 69 | 19 } 70 | ``` 71 | 72 | @SelectKey 73 | 74 | # 支付功能 -------------------------------------------------------------------------------- /02 JVM/notes/锁优化.md: -------------------------------------------------------------------------------- 1 | # 锁优化 2 | 3 | ## 适应性自旋(Adaptive Spinning) 4 | 5 | 线程阻塞的时候,让等待的线程不放弃cpu执行时间,而是执行一个自旋(一般是空循环),这叫做自旋锁。 6 | 7 | 自旋等待本身虽然避免了线程切换的开销,但它是要占用处理器时间的,因此,如果锁被占用的时间很短,自旋等待的效果就非常好,反之,如果锁被占用的时间很长,那么自旋的线程只会白白消耗处理器资源,带来性能上的浪费。 8 | 9 | 因此,自旋等待的时间必须要有一定的限度。如果自旋超过了限定的次数仍然没有成功获得锁,就应当使用传统的方式去挂起线程了。自旋次数的默认值是10次,用户可以使用参数`-XX:PreBlockSpin`来更改。 10 | 11 | JDK1.6引入了自适应的自旋锁。自适应意味着自旋的时间不再固定了,而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。比如前一次自旋了3次就获得了一个锁,那么下一次虚拟机会允许他自旋更多次来获得这个锁。如果一个锁很少能通过自旋成功获得,那么之后再遇到这个情况就会省略自旋过程了。 12 | 13 | ## 锁消除(Lock Elimination) 14 | 15 | 虚拟机即时编译器在运行时,对一些代码上要求同步,但是被检测到不可能存在共享数据竞争的锁进行消除。一般根据逃逸分析的数据支持来作为判定依据。 16 | 17 | ## 锁粗化(Lock Coarsening) 18 | 19 | 原则上,我们在编写代码的时候,总是推荐将同步块的作用范围限制得尽量小——只在共享数据的实际作用域中才进行同步,这样是为了使需要同步的操作数量尽可能变小,如果存在锁竞争,那等待锁的线程也能尽快拿到锁。 20 | 21 | 但如果一系列操作频繁对同一个对象加锁解锁,或者加锁操作再循环体内,会耗费性能,这时**虚拟机会扩大加锁范围。** 22 | 23 | ## 轻量级锁(Lightweight Locking) 24 | 25 | 轻量级锁是JDK 1.6之中加入的新型锁机制。它的作用是在没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗。 26 | 27 | HotSpot虚拟机的对象头(Object Header)分为两部分信息,第一部分用于存储对象自身的运行时数据,这部分称`为Mark Word`。还有一部分存储指向方法区对象类型数据的指针。 28 | 29 | ### 加锁 30 | 31 | 在代码进入同步块的时候,如果此同步对象没有被锁定(锁标志位为“01”状态),虚拟机首先将在当前线程的栈帧中建立一个名为锁记录(Lock Record)的空间,用于存储锁对象目前的Mark Word的拷贝(官方把这份拷贝加了一个Displaced前缀,即Displaced Mark Word)。然后,虚拟机将使用CAS操作尝试将对象的Mark Word更新为指向Lock Record的指针。如果这个更新动作成功,那么这个线程就拥有了该对象的锁,并且对象Mark Word的锁标志位(Mark Word的最后2bit)将转变为“00”,即表示此对象处于轻量级锁定状态。如果这个更新操作失败了,虚拟机首先会检查对象的Mark Word是否指向当前线程的栈帧,如果是说明当前线程已经拥有了这个对象的锁,那就可以直接进入同步块继续执行,否则说明这个锁对象已经被其他线程抢占了。如果有两条以上的线程争用同一个锁,那轻量级锁就不再有效,要膨胀为重量级锁,锁标志的状态值变为“10”,Mark Word中存储的就是指向重量级锁(互斥量)的指针,后面等待锁的线程也要进入阻塞状态。 32 | 33 | ### 解锁 34 | 35 | 解锁过程也是通过CAS操作来进行的。如果对象的Mark Word仍然指向着线程的锁记录,那就用CAS操作把对象当前的Mark Word和线程中复制的Displaced Mark Word替换回来,如果替换成功,整个同步过程就完成了。如果替换失败,说明有其他线程尝试过获取该锁,那就要在释放锁的同时,唤醒被挂起的线程。 36 | 37 | ### 性能 38 | 39 | 没有锁竞争时,轻量级锁用CAS操作替代互斥量的开销,性能较优。有锁竞争时,除了互斥量开销,还有CAS操作开销,所以性能较差。但是,一般情况下,在整个同步周期内都是不存在竞争的”,这是一个经验数据。 40 | 41 | ## 偏向锁(Biased Locking) 42 | 43 | 偏向锁也是JDK1.6中引入的锁优化,它的目的是消除数据在无竞争情况下的同步原语,进一步提高程序的运行性能。如果说轻量级锁是在无竞争的情况下使用CAS操作去消除同步使用的互斥量,那偏向锁就是在无竞争的情况下把整个同步都消除掉,连CAS操作都不做了。 44 | 45 | 当锁对象第一次被线程获取的时候,虚拟机将会把对象头中的标志位设为“01”,即偏向模式。同时使用CAS操作把获取到这个锁的线程的ID记录在对象的Mark Word之中,如果CAS操作成功,持有偏向锁的线程以后每次进入这个锁相关的同步块时,虚拟机都可以不再进行任何同步操作。当有另外一个线程去尝试获取这个锁时,偏向模式结束。 46 | 47 | 偏向锁可以提高带有同步但无竞争的程序性能,但并不一定总是对程序运行有利。如果程序中大多数的锁总是被多个不同的线程访问,那偏向模式就是多余的。在具体问题具体分析的前提下,有时候使用参数`-XX:-UseBiasedLocking`来禁止偏向锁优化反而可以提升性能。 48 | 49 | 50 | 作者:Joepis链接:https://juejin.im/post/5b33516c51882574e40e9c7e 51 | 52 | -------------------------------------------------------------------------------- /11 分布式与微服务/02 分布式/notes/BASE.md: -------------------------------------------------------------------------------- 1 | BASE理论是由eBay架构师提出的。BASE是对CAP中一致性和可用性权衡的结果,其来源于对大规模互联网分布式系统实践的总结,是基于CAP定律逐步演化而来。其核心思想是即使无法做到强一致性,但每个应用都可以根据自身业务特点,才用适当的方式来使系统打到最终一致性。 2 | 3 | ## 1. CAP的3选2伪命题 4 | 5 | 实际上,不是为了P(分区容错性),必须在C(一致性)和A(可用性)之间任选其一。分区的情况很少出现,CAP在大多时间能够同时满足C和A。 6 | 7 | 对于分区存在或者探知其影响的情况下,需要提供一种预备策略做出处理: 8 | 9 | - 探知分区的发生; 10 | - 进入显示的分区模式,限制某些操作; 11 | - 启动恢复过程,恢复数据一致性,补偿分区发生期间的错误。 12 | 13 | ## 2. BASE理论简介 14 | 15 | BASE理论是**Basically Available(基本可用),Soft State(软状态)和Eventually Consistent(最终一致性)**三个短语的缩写。 16 | 17 | 其核心思想是: 18 | 19 | > 既是无法做到强一致性(Strong consistency),但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性(Eventual consistency)。 20 | 21 | ## 3. BASE理论的内容 22 | 23 | - 基本可用(Basically Available) 24 | - 软状态(Soft State) 25 | - 最终一致性(Eventually Consistent) 26 | 27 | 下面展开讨论: 28 | 29 | ### 3.1. 基本可用 30 | 31 | 什么是基本可用呢?假设系统,出现了不可预知的故障,但还是能用,相比较正常的系统而言: 32 | 33 | 1. **响应时间上的损失**:正常情况下的搜索引擎0.5秒即返回给用户结果,而基本可用的搜索引擎可以在2秒作用返回结果。 34 | 2. **功能上的损失**:在一个电商网站上,正常情况下,用户可以顺利完成每一笔订单。但是到了大促期间,为了保护购物系统的稳定性,部分消费者可能会被引导到一个降级页面。 35 | 36 | ### 3.2. 软状态 37 | 38 | 什么是软状态呢?相对于原子性而言,要求多个节点的数据副本都是一致的,这是一种“硬状态”。 39 | 40 | 软状态指的是:允许系统中的数据存在中间状态,并认为该状态不影响系统的整体可用性,即允许系统在多个不同节点的数据副本存在数据延时。 41 | 42 | ### 3.3. 最终一致性 43 | 44 | 上面说软状态,然后不可能一直是软状态,必须有个时间期限。在期限过后,应当保证所有副本保持数据一致性,从而达到数据的最终一致性。这个时间期限取决于网络延时、系统负载、数据复制方案设计等等因素。 45 | 46 | 而在实际工程实践中,最终一致性分为5种: 47 | 48 | #### 3.3.1. 因果一致性(Causal consistency) 49 | 50 | 因果一致性指的是:如果节点A在更新完某个数据后通知了节点B,那么节点B之后对该数据的访问和修改都是基于A更新后的值。于此同时,和节点A无因果关系的节点C的数据访问则没有这样的限制。 51 | 52 | #### 3.3.2. 读己之所写(Read your writes) 53 | 54 | 读己之所写指的是:节点A更新一个数据后,它自身总是能访问到自身更新过的最新值,而不会看到旧值。其实也算一种因果一致性。 55 | 56 | #### 3.3.3. 会话一致性(Session consistency) 57 | 58 | 会话一致性将对系统数据的访问过程框定在了一个会话当中:系统能保证在同一个有效的会话中实现 “读己之所写” 的一致性,也就是说,执行更新操作之后,客户端能够在同一个会话中始终读取到该数据项的最新值。 59 | 60 | #### 3.3.4. 单调读一致性(Monotonic read consistency) 61 | 62 | 单调读一致性指的是:如果一个节点从系统中读取出一个数据项的某个值后,那么系统对于该节点后续的任何数据访问都不应该返回更旧的值。 63 | 64 | #### 3.3.5. 单调写一致性(Monotonic write consistency) 65 | 66 | 单调写一致性指的是:一个系统要能够保证来自同一个节点的写操作被顺序的执行。 67 | 68 | > 在实际的实践中,这5种系统往往会结合使用,以构建一个具有最终一致性的分布式系统。 69 | 70 | 实际上,不只是分布式系统使用最终一致性,关系型数据库在某个功能上,也是使用最终一致性的。比如备份,数据库的复制过程是需要时间的,这个复制过程中,业务读取到的值就是旧的。当然,最终还是达成了数据一致性。这也算是一个最终一致性的经典案例。 71 | 72 | # 小结 73 | 74 | 总体来说BASE理论面向的是大型高可用、可扩展的分布式系统。与传统ACID特性相反,不同于ACID的强一致性模型,BASE提出通过牺牲强一致性来获得可用性,并允许数据段时间内的不一致,但是最终达到一致状态。同时,在实际分布式场景中,不同业务对数据的一致性要求不一样。因此在设计中,ACID和BASE理论往往又会结合使用。 75 | 76 | 77 | 作者:零壹技术栈链接:https://juejin.im/post/5b2663fcf265da59a401e6f8 -------------------------------------------------------------------------------- /08 数据库/01 MySQL/notes/inner join、left join和right join.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1.MySQL 有哪几种连接方式,分别解释一下(华为) 4 | 5 | https://blog.csdn.net/dog_egg_/article/details/87647986 6 | 7 | 8 | # left join 、right join 、inner join之间的区别 9 | 10 | - left join(左联接) 返回包括左表中的所有记录和**右表中联结字段相等的记录**,以左表为基础 11 | 12 | - right join(右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录,以右表为基础 13 | 14 | - inner join(等值连接) 只返回两个表中联结字段相等的行, 15 | 16 | 举例如下: 17 | 18 | 表A记录如下: 19 | 20 | aID     aNum 21 | 1     a20050111 22 | 2     a20050112 23 | 3     a20050113 24 | 4     a20050114 25 | 5     a20050115 26 | 27 | 表B记录如下: 28 | 29 | bID     bName 30 | 1     2006032401 31 | 2     2006032402 32 | 3     2006032403 33 | 4     2006032404 34 | 8     2006032408 35 | 36 | -------------------------------------------- 37 | 1.left join 38 | sql语句如下: 39 | 40 | ```mysql 41 | select * from A left join B on A.aID = B.bID 42 | ``` 43 | 44 | 结果如下: 45 | 46 | aID     aNum     bID     bName 47 | 1     a20050111    1     2006032401 48 | 2     a20050112    2     2006032402 49 | 3     a20050113    3     2006032403 50 | 4     a20050114    4     2006032404 51 | 5     a20050115    NULL     NULL 52 | 53 | (所影响的行数为 5 行) 54 | 结果说明: 55 | 56 | left join是以A表的记录为基础的,**A可以看成左表,B可以看成右表**,left join是以左表为准的. 57 | 换句话说,**左表(A)的记录将会全部表示出来**,而右表(B)只会显示符合搜索条件的记录(例子中为: A.aID = B.bID). 58 | 59 | B表记录**不足的地方均为NULL**. 60 | 61 | 2.right join 62 | 63 | sql语句如下: 64 | 65 | ```mysql 66 | select * from A right join B on A.aID = B.bID 67 | ``` 68 | 69 | 结果如下: 70 | 71 | aID     aNum     bID     bName 72 | 1     a20050111    1     2006032401 73 | 2     a20050112    2     2006032402 74 | 3     a20050113    3     2006032403 75 | 4     a20050114    4     2006032404 76 | NULL     NULL     8     2006032408 77 | 78 | (所影响的行数为 5 行) 79 | 结果说明: 80 | 81 | 仔细观察一下,就会发现,和left join的结果刚好相反,这次是**以右表(B)为基础的,A表不足的地方用NULL填充.** 82 | 83 | 3.inner join 84 | sql语句如下: 85 | 86 | ```mysql 87 | select * from A inner join B on A.aID = B.bID 88 | ``` 89 | 90 | 结果如下: 91 | aID     aNum     bID     bName 92 | 1     a20050111    1     2006032401 93 | 2     a20050112    2     2006032402 94 | 3     a20050113    3     2006032403 95 | 4     a20050114    4     2006032404 96 | 97 | 结果说明: 98 | 很明显,这里只显示出了 A.aID = B.bID的记录.这说明**inner join并不以谁为基础,它只显示符合条件的记录**. 99 | 100 | # 外连接 101 | 102 | -------------------------------------------------------------------------------- /08 数据库/01 MySQL/notes/MySQL事务.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1. 事务是如何通过日志来实现的,说得越深入越好 4 | 5 | 事务日志是通过**redo和innodb的存储引擎日志缓冲(Innodb log buffer)来实现的**,当开始一个事务的时候,会记录该事务的lsn(log sequence number)号; 当事务执行时,会往InnoDB存储引擎的日志的日志缓存里面插入事务日志;当事务提交时,必须将存储引擎的日志缓冲写入磁盘(通过innodb_flush_log_at_trx_commit来控制),也就是写数据前,需要先写日志。这种方式称为“预写日志方式” 6 | 7 | 作者:Java_老男孩链接:https://juejin.im/post/5cb6c4ef51882532b70e6ff0 8 | 9 | # MySQL的事务日志 10 | 11 | ## **undo log** 12 | 13 | 在说明原子性原理之前,首先介绍一下MySQL的事务日志。MySQL的日志有很多种,如二进制日志、错误日志、查询日志、慢查询日志等,此外InnoDB存储引擎还提供了两种事务日志:redo log(重做日志)和undo log(回滚日志)。其中redo log用于保证事务持久性;undo log则是事务原子性和隔离性实现的基础。 14 | 15 | 下面说回undo log。实现原子性的关键,是当事务回滚时能够撤销所有已经成功执行的sql语句。InnoDB实现回滚,靠的是undo log:当事务对数据库进行修改时,InnoDB会生成对应的undo log;如果事务执行失败或调用了rollback,导致事务需要回滚,便可以利用undo log中的信息将数据回滚到修改之前的样子。 16 | 17 | undo log属于逻辑日志,它记录的是sql执行相关的信息。当发生回滚时,InnoDB会根据undo log的内容做与之前相反的工作:对于每个insert,回滚时会执行delete;对于每个delete,回滚时会执行insert;对于每个update,回滚时会执行一个相反的update,把数据改回去。 18 | 19 | 以update操作为例:当事务执行update时,其生成的undo log中会包含被修改行的主键(以便知道修改了哪些行)、修改了哪些列、这些列在修改前后的值等信息,回滚时便可以使用这些信息将数据还原到update之前的状态。 20 | 21 | ## **redo log** 22 | 23 | redo log和undo log都属于InnoDB的事务日志。下面先聊一下redo log存在的背景。 24 | 25 | InnoDB作为MySQL的存储引擎,数据是存放在磁盘中的,但如果每次读写数据都需要磁盘IO,效率会很低。为此,InnoDB提供了缓存(Buffer Pool),Buffer Pool中包含了磁盘中部分数据页的映射,作为访问数据库的缓冲:当从数据库读取数据时,会首先从Buffer Pool中读取,如果Buffer Pool中没有,则从磁盘读取后放入Buffer Pool;当向数据库写入数据时,会首先写入Buffer Pool,Buffer Pool中修改的数据会定期刷新到磁盘中(这一过程称为刷脏)。 26 | 27 | Buffer Pool的使用大大提高了读写数据的效率,但是也带了新的问题:如果MySQL宕机,而此时Buffer Pool中修改的数据还没有刷新到磁盘,就会导致数据的丢失,事务的持久性无法保证。 28 | 29 | 于是,redo log被引入来解决这个问题:当数据修改时,除了修改Buffer Pool中的数据,还会在redo log记录这次操作;当事务提交时,会调用fsync接口对redo log进行刷盘。如果MySQL宕机,重启时可以读取redo log中的数据,对数据库进行恢复。redo log采用的是WAL(Write-ahead logging,预写式日志),所有修改先写入日志,再更新到Buffer Pool,保证了数据不会因MySQL宕机而丢失,从而满足了持久性要求。 30 | 31 | ## **redo log与binlog** 32 | 33 | **我们知道,在MySQL中还存在binlog(二进制日志)也可以记录写操作并用于数据的恢复,但二者是有着根本的不同的:** 34 | 35 | **(1)作用不同:**redo log是用于crash recovery的,保证MySQL宕机也不会影响持久性;binlog是用于point-in-time recovery的,保证服务器可以基于时间点恢复数据,此外binlog还用于主从复制。 36 | 37 | **(2)层次不同:**redo log是InnoDB存储引擎实现的,而binlog是MySQL的服务器层(可以参考文章前面对MySQL逻辑架构的介绍)实现的,同时支持InnoDB和其他存储引擎。 38 | 39 | **(3)内容不同:**redo log是物理日志,内容基于磁盘的Page;binlog是逻辑日志,内容是一条条sql。 40 | 41 | **(4)写入时机不同:**binlog在事务提交时写入;redo log的写入时机相对多元: 42 | 43 | - **前面曾提到:**当事务提交时会调用fsync对redo log进行刷盘;这是默认情况下的策略,修改innodb_flush_log_at_trx_commit参数可以改变该策略,但事务的持久性将无法保证。 44 | - **除了事务提交时,还有其他刷盘时机:**如master thread每秒刷盘一次redo log等,这样的好处是不一定要等到commit时刷盘,commit速度大大加快。 45 | 46 | https://cloud.tencent.com/developer/article/1422024 -------------------------------------------------------------------------------- /08 数据库/01 MySQL/notes/Explain.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1. 怎么查看一条语句用了什么索引?(oppo) 4 | 5 | explain SQL语句 6 | 7 | 一条查询语句在经过`MySQL`查询优化器的各种基于成本和规则的优化会后生成一个所谓的`执行计划`,这个执行计划展示了接下来具体执行查询的方式,比如多表连接的顺序是什么,对于每个表采用什么访问方法来具体执行查询等等。 8 | 9 | 如果我们想看看某个查询的执行计划的话,可以在具体的查询语句前边加一个`EXPLAIN`,就像这样: 10 | 11 | ```mysql 12 | explain select count(*) from userinfo where id = 1; 13 | ``` 14 | 15 | | 列名 | 描述 | 16 | | :-------------: | :----------------------------------------------------------- | 17 | | `id` | 在一个大的查询语句中每个`SELECT`关键字都**对应一个唯一的id** | 18 | | `select_type` | `SELECT`关键字对应的那个查询的类型 | 19 | | `table` | 表名 | 20 | | `partitions` | 匹配的分区信息 | 21 | | `type` | 针对单表的访问方法 | 22 | | `possible_keys` | 可能用到的索引 | 23 | | `key` | 实际上使用的索引 | 24 | | `key_len` | 实际使用到的索引长度 | 25 | | `ref` | 当使用索引列等值查询时,与索引列进行等值匹配的对象信息 | 26 | | `rows` | 预估的需要读取的记录条数 | 27 | | `filtered` | 某个表经过搜索条件过滤后剩余记录条数的百分比 | 28 | | `Extra` | 一些额外的信息 | 29 | 30 | ## 执行计划输出中各列详解 31 | 32 | type显示的是访问类型,是较为重要的一个指标,结果值从好到坏依次是: system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL ,一般来说,得保证查询至少达到range级别,最好能达到ref。 33 | 34 | | 类型 | 说明 | 35 | | :----- | :----------------------------------------------------------- | 36 | | All | 最坏的情况,全表扫描 | 37 | | index | 和全表扫描一样。只是扫描表的时候按照索引次序进行而不是行。主要优点就是避免了排序, 但是开销仍然非常大。如在Extra列看到Using index,说明正在使用覆盖索引,只扫描索引的数据,它比按索引次序全表扫描的开销要小很多 | 38 | | range | 范围扫描,一个有限制的索引扫描。key 列显示使用了哪个索引。当使用=、 <>、>、>=、<、<=、IS NULL、<=>、BETWEEN 或者 IN 操作符,用常量比较关键字列时,可以使用 range | 39 | | ref | 一种索引访问,它返回所有匹配某个单个值的行。此类索引访问只有当使用非唯一性索引或唯一性索引非唯一性前缀时才会发生。这个类型跟eq_ref不同的是,它用在关联操作只使用了索引的最左前缀,或者索引不是UNIQUE和PRIMARY KEY。ref可以用于使用=或<=>操作符的带索引的列。 | 40 | | eq_ref | 最多只返回一条符合条件的记录。使用唯一性索引或主键查找时会发生 (高效) | 41 | | const | 当确定最多只会有一行匹配的时候,MySQL优化器会在查询前读取它而且只读取一次,因此非常快。当主键放入where子句时,mysql把这个查询转为一个常量(高效) | 42 | | system | 这是const连接类型的一种特例,表仅有一行满足条件。 | 43 | | Null | 意味说mysql能在优化阶段分解查询语句,在执行阶段甚至用不到访问表或索引(高效) | 44 | 45 | 46 | 作者:何甜甜在吗链接:https://juejin.im/post/5bcc2935f265da0ac66987c9 -------------------------------------------------------------------------------- /08 数据库/02 Redis/notes/缓存雪崩和缓存穿透.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1.缓存穿透 4 | 5 | 缓存穿透是**指查询一个一定不存在的数据,因为缓存中也无该数据的信息,则会直接去数据库层进行查询**,从系统层面来看像是穿透了缓存层直接达到db,从而称为缓存穿透,没有了缓存层的保护,这种查询一定不存在的数据对系统来说可能是一种危险,如果有人恶意用这种一定不存在的数据来频繁请求系统,不,准确的说是攻击系统,请求都会到达数据库层导致db瘫痪从而引起系统故障。 6 | 7 | ### 解决方案 8 | 9 | 缓存穿透业内的解决方案已经比较成熟,主要常用的有以下几种: 10 | 11 | bloom filter:类似于哈希表的一种算法,**用所有可能的查询条件生成一个bitmap,在进行数据库查询之前会使用这个bitmap进行过滤,如果不在其中则直接过滤,从而减轻数据库层面的压力。guava中有实现BloomFilter算法** 12 | 13 | 空值缓存:一种比较简单的解决办法,在第一次查询完不存在的数据后,将该key与对应的空值也放入缓存中,只不过设定为较短的失效时间,例如几分钟,这样则可以应对短时间的大量的该key攻击,设置为较短的失效时间是因为该值可能业务无关,存在意义不大,且该次的查询也未必是攻击者发起,无过久存储的必要,故可以早点失效。 14 | 15 | ### 缓存雪崩 16 | 17 | 在普通的缓存系统中一般例如redis、memcache等中,我们会给缓存设置一个失效时间,但是如果**所有的缓存的失效时间相同,那么在同一时间失效时,所有系统的请求都会发送到数据库层,db可能无法承受如此大的压力导致系统崩溃。** 18 | 19 | ### 解决方案 20 | 21 | 线程互斥:**只让一个线程构建缓存,其他线程等待构建缓存的线程执行完,重新从缓存获取数据才可以**,每个时刻只有一个线程在执行请求,减轻了db的压力,但缺点也很明显,降低了系统的qps。 22 | 23 | **交错失效时间**:这种方法时间比较简单粗暴,既然在同一时间失效会造成请求过多雪崩,那我们错开不同的失效时间即可从一定长度上避免这种问题,在缓存进行失效时间设置的时候,从某个适当的值域中随机一个时间作为失效时间即可。 24 | 25 | ### 缓存击穿 26 | 27 | 缓存击穿实际上是缓存雪崩的一个特例,大家使用过微博的应该都知道,微博有一个热门话题的功能,用户对于热门话题的搜索量往往在一些时刻会大大的高于其他话题,这种我们成为系统的“热点“,由于系统中对这些热点的数据缓存也存在失效时间,在热点的缓存到达失效时间时,此时可能依然会有大量的请求到达系统,没有了缓存层的保护,这些请求同样的会到达db从而可能引起故障。**击穿与雪崩的区别即在于击穿是对于特定的热点数据来说,而雪崩是全部数据。** 28 | 29 | ### 解决方案 30 | 31 | 二级缓存:**对于热点数据进行二级缓存,并对于不同级别的缓存设定不同的失效时间,则请求不会直接击穿缓存层到达数据库。** 32 | 33 | 这里参考了阿里双11万亿流量的缓存击穿解决方案,解决此问题的关键在于热点访问。由于热点可能随着时间的变化而变化,针对固定的数据进行特殊缓存是不能起到治本作用的,结合LRU算法能够较好的帮我们解决这个问题。 34 | 35 | https://cloud.tencent.com/developer/article/1422153 36 | 37 | # 缓存雪崩 38 | 39 | 简介:**缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。** 40 | 41 | 解决办法(中华石杉老师在他的视频中提到过,视频地址在最后一个问题中有提到): 42 | 43 | 事前:尽量保证整个 **redis 集群的高可用性**,发现机器宕机尽快补上。选择**合适的内存淘汰策略**。 44 | 45 | 事中:**本地ehcache缓存 + hystrix限流&降级**,避免MySQL崩掉 46 | 47 | 事后:利用 redis **持久化机制**保存的数据尽快恢复缓存 48 | 49 | (一)给缓存的失效时间,加上一个随机值,避免集体失效。 50 | (二)使用互斥锁,但是该方案吞吐量明显下降了。 51 | (三)双缓存。我们有两个缓存,缓存A和缓存B。缓存A的失效时间为20分钟,缓存B不设失效时间。自己做缓存预热操作。然后细分以下几个小点 52 | 53 | # 缓存穿透 54 | 55 | 简介:一般是黑客故意去**请求缓存中不存在的数据,导致所有的请求都落到数据库上**,造成数据库短时间内承受大量请求而崩掉。 56 | 57 | ![](https://raw.githubusercontent.com/wuqifan1098/picBed/master/20190529205729.png) 58 | 59 | 解决缓存穿透也有两种方案: 60 | 61 | - 由于请求的参数是不合法的(每次都请求不存在的参数),于是我们可以使用布隆过滤器(BloomFilter)或者压缩filter**提前拦截**,不合法就不让这个请求到数据库层! 62 | - 当我们从数据库找不到的时候,我们也将这个**空对象设置到缓存里边去**。下次再请求的时候,就可以从缓存里边获取了。 63 | - 这种情况我们一般会将空对象设置一个**较短的过期时间**。 64 | 65 | (一)利用互斥锁,**缓存失效的时候,先去获得锁,得到锁了,再去请求数据库**。没得到锁,则休眠一段时间重试 66 | (二)采用异步更新策略,无论key是否取到值,都直接返回。value值中维护一个缓存失效时间,缓存如果过期,异步起一个线程去读数据库,更新缓存。需要做缓存预热(项目启动前,先加载缓存)操作。 67 | (三)提供一个能迅速判断请求是否有效的拦截机制,比如,**利用布隆过滤器,内部维护一系列合法有效的key**。迅速判断出,请求所携带的Key是否合法有效。如果不合法,则直接返回。 68 | 69 | https://zhuanlan.zhihu.com/p/81978256 -------------------------------------------------------------------------------- /01 JavaSe/03 基础概念/notes/对象的序列化和反序列化.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1. 说一下序列化,如何实现序列化 4 | 5 | 序列化就是将Java对象转换成二进制流,便于在网络中传输或被持久化到数据库。 6 | 7 | 实现Serializable 接口。 8 | 9 | # 序列化的含义和作用 10 | 11 | ## 序列化与反序列化 12 | 13 | (1)序列化:将一个java对象**以二进制流的方式在网络中传输并且可以被持久化到数据库、文件系统中** 14 | 15 | (2)反序列化:把之前持久化在数据库或文件系统中的二进制数据以流的方式**读取出来重新构造成一个和之前相同内容的java对象** 16 | 17 | ## 序列化应用的场景 18 | 19 | (1)把的内存中的对象状态**保存到一个文件中或者数据库中** 20 | 21 | (2)用套接字在网络上传送对象 22 | 23 | (3)通过RMI传输对象 24 | 25 | (4)通过序列化在进程间传递对象 26 | 27 | (5)序列化能实现深复制,即复制引用的对象 28 | 29 | ## 对象可序列化的条件 30 | 31 | (1)必须实现 java.io.Serializable 对象 32 | 33 | (2)所有属性必须是可序列化的,如果有一个属性不是可序列化的,则该属性必须注明是短暂(transient)的 34 | 35 | (3)声明为**static和transient类型**的成员数据不能被序列化 36 | 37 | (4)final变量将直接通过值参与序列化,所以将final变量声明为transient变量不会产生任何影响 38 | 39 | (5)是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致(serialVersionUID ),SerialVersionUID用于对象的版本控制,当serialVersionUID不匹配时抛出java.io.InvalidClassException 异常 40 | 41 | (6)当一个父类实现序列化,**子类自动实现序列化**,不需要显式实现Serializable接口 42 | 43 | ## 相关接口及类 44 | 45 | - java.io.Serializable 46 | 47 | - java.io.Externalizable 48 | 49 | - ObjectOutput 50 | 51 | - ObjectInput 52 | 53 | - ObjectOutputStream 54 | 55 | - ObjectInputStream 56 | 57 | (1) Serializable接口 58 | 59 | java.io.Serializable接口是一个标记接口,意味着它不包含任何方法或字段,仅用于标识可序列化的语义。当试图对一个对象进行序列化的时候,如果该对象没有实现 Serializable 接口,将抛出NotSerializableException 60 | 61 | (2)Externalizable接口 62 | 63 | java.io.Externalizable继承了Serializable,该接口中定义了两个抽象方法:writeExternal()与readExternal()。当使用Externalizable接口来进行序列化与反序列化的时候需要开发人员重写writeExternal()与readExternal()方法。 64 | 65 | 在使用Externalizable进行序列化的时候,读取对象会调用被序列化类的无参构造器去创建一个新的对象,然后再将对象的字段值分别填充到新对象中,因此实现Externalizable接口的类必须要提供一个public的无参构造器,若没有无参构造函数,运行时会抛出 java.io.InvalidClassException 异常。 66 | 67 | (3)ObjectOutput和ObjectInput 接口 68 | 69 | ObjectInput接口扩展自 DataInput 接口,ObjectOutput 扩展 DataOutput 接口。DataInput 接口用于从二进制流中读取字节,并根据所有 Java 基本类型数据进行重构,DataOutput 接口用于将数据从任意 Java 基本类型转换为一系列字节,并将这些字节写入二进制流。 70 | 71 | (4)ObjectOutputStream和ObjectInputStream类 72 | 73 | ObjectOutputStream的writeObject方法把一个对象进行持久化,ObjectInputStream的readObject方法将持久化存储中把对象读取出来。 74 | 75 | # 序列化存在的风险与措施 76 | 77 | (1)当序列化对象中存在敏感数据时,存在着信息泄露的风险。 78 | 79 | (2)恶意攻击者可以通过篡改序列化流中的数据,从而进行伪造、命令执行、拒绝服务等。 80 | 81 | ## 通用解决措施 82 | 83 | (1)对序列化的流数据**进行加密** 84 | 85 | (2)在传输过程中**使用 TLS 加密传输** 86 | 87 | (3)对序列化数据进行**完整性校验** 88 | 89 | # JSON序列化和反序列化的工具类 90 | 91 | (1)fastJson在转换java对象为json的时候,默认是不序列化null值属性,gson和fastjson一样,jackson默认是序列化null值属性 92 | 93 | (2)在项目选型的时候通常使用Google的Gson和阿里巴巴的FastJson两种 94 | 95 | (3)有默认的无参构造方法时,gson和fastJson都会调用它来创建对象,没有默认的无参构造方法时,fastJson会直接报错,而gson则会调用Unsafe.allocateInstance()这个native方法直接在内存上创建对象 96 | 97 | (4)数据处理量小的情况下使用gson,数据量大的情况下使用fastjson -------------------------------------------------------------------------------- /07 操作系统/notes/段式管理和页式管理.md: -------------------------------------------------------------------------------- 1 | # 页式和段式存储管理 2 | 3 | 在前面的几种存储管理方法中,为进程分配的空间是连续的,使用的地址都是物理地址。如果允许将一个进程分散到许多不连续的空间,就可以避免**内存紧缩,减少碎片**。基于这一思想,通过引入进程的逻辑地址,把进程地址空间与实际存储空间分离,增加存储管理的灵活性。地址空间和存储空间两个基本概念的定义如下: 4 | 5 | 地址空间:将源程序经过编译后得到的目标程序,存在于它所限定的地址范围内,这个范围称为地址空间。地址空间是逻辑地址的集合。 6 | 7 | 存储空间:指主存中一系列存储信息的物理单元的集合,这些单元的编号称为物理地址存储空间是物理地址的集合。 8 | 9 | 根据分配时所采用的基本单位不同,可将离散分配的管理方式分为以下三种: 10 | **页式存储管理、段式存储管理和段页式存储管理。**其中段页式存储管理是前两种结合的产物。 11 | 12 | # 页式存储管理 13 | 14 | ## 基本原理 15 | 16 | **将程序的逻辑地址空间划分为固定大小的页(page),而物理内存划分为同样大小的页框(page frame)。** 17 | 18 | 页式管理方式的优点是: 19 | 20 | 1)没有外碎片,每个内碎片不超过页大比前面所讨论的几种管理方式的最大进步是, 21 | 22 | 2)一个程序不必连续存放。 23 | 24 | 3)便于改变程序占用空间的大小(主要指随着程序运行,动态生成的数据增多,所要求的地址空间相应增长)。 25 | 26 | 缺点是:要求程序全部装入内存,没有足够的内存,程序就不能执行。 27 | 28 | # 段式存储管理 29 | 30 | ## 基本原理 31 | 32 | 在段式存储管理中,**将程序的地址空间划分为若干个段(segment),这样每个进程有一个二维的地址空间。**在前面所介绍的动态分区分配方式中,系统为整个进程分配一个连续的内存空间。而在段式存储管理系统中,则为每个段分配一个连续的分区,而进程中的各个段可以不连续地存放在内存的不同分区中。程序加载时,操作系统为所有段分配其所需内存,这些段不必连续,物理内存的管理采用动态分区的管理方法。 33 | 34 | 在为某个段分配物理内存时,可以采用首先适配法、下次适配法、最佳适配法等方法。 35 | 36 | 在回收某个段所占用的空间时,要注意将收回的空间与其相邻的空间合并。 37 | 38 | 段式存储管理的优点是:没有内碎片,外碎片可以通过内存紧缩来消除;便于实现内存共享。缺点与页式存储管理的缺点相同,进程必须全部装入内存。 39 | 40 | # 页式和段式管理的区别 41 | 42 | 页式和段式系统有许多相似之处。比如,两者都采用离散分配方式,且都通过地址映射机构来实现地址变换。但概念上两者也有很多区别,主要表现在: 43 | 44 | 1)、需求:是信息的物理单位,分页是为了实现离散分配方式,以减少内存的碎片,提高内存的利用率。或者说,分页仅仅是由于系统管理的需要,而不是用户的需要。段是信息的逻辑单位,它含有一组其意义相对完整的信息。分段的目的是为了更好地满足用户的需要。 45 | 46 | 一条指令或一个操作数可能会跨越两个页的分界处,而不会跨越两个段的分界处。 47 | 2)、大小:页大小固定且由系统决定,把逻辑地址划分为页号和页内地址两部分,是由机器硬件实现的。段的长度不固定,且决定于用户所编写的程序,通常由编译系统在对源程序进行编译时根据信息的性质来划分。 48 | 49 | 3)、逻辑地址表示:页式系统地址空间是一维的,即单一的线性地址空间,程序员只需利用一个标识符,即可表示一个地址。分段的作业地址空间是二维的,程序员在标识一个地址时,既需给出段名,又需给出段内地址。 50 | 51 | 4)、比页大,因而段表比页表短,可以缩短查找时间,提高访问速度。 52 | 53 | # [分段](https://cyc2018.github.io/CS-Notes/#/notes/计算机操作系统 - 内存管理?id=分段) 54 | 55 | 虚拟内存采用的是分页技术,也就是将地址空间划分成固定大小的页,每一页再与内存进行映射。 56 | 57 | 下图为一个编译器在编译过程中建立的多个表,有 4 个表是动态增长的,如果使用分页系统的一维地址空间,动态增长的特点会导致覆盖问题的出现。 58 | 59 | ![img](https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/22de0538-7c6e-4365-bd3b-8ce3c5900216.png) 60 | 61 | 分段的做法是把每个表分成段,一个段构成一个独立的地址空间。每个段的长度可以不同,并且可以动态增长。 62 | 63 | ![img](https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/e0900bb2-220a-43b7-9aa9-1d5cd55ff56e.png) 64 | 65 | # [段页式](https://cyc2018.github.io/CS-Notes/#/notes/计算机操作系统 - 内存管理?id=段页式) 66 | 67 | 程序的地址空间划分成多个拥有独立地址空间的段,每个段上的地址空间划分成大小相同的页。这样既拥有分段系统的共享和保护,又拥有分页系统的虚拟内存功能。 68 | 69 | # [分页与分段的比较](https://cyc2018.github.io/CS-Notes/#/notes/计算机操作系统 - 内存管理?id=分页与分段的比较) 70 | 71 | - 对程序员的透明性:分页**透明**,但是分段需要程序员**显式划分每个段**。 72 | - 地址空间的维度:分页是**一维地址空间**,分段是**二维的**。 73 | - 大小是否可以改变:页的大小**不可变**,段的大小可以**动态改变**。 74 | - 出现的原因:分页主要用于实现虚拟内存,从而获得更大的地址空间;分段主要是为了使程序和数据可以被划分为逻辑上独立的地址空间并且有助于共享和保护。 -------------------------------------------------------------------------------- /01 JavaSe/03 基础概念/notes/装箱和拆箱.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1.下面这段代码的输出结果是什么? 4 | 5 | ```java 6 | public class Main { 7 | public static void main(String[] args) { 8 | 9 | Integer i1 = 100; 10 | Integer i2 = 100; 11 | Integer i3 = 200; 12 | Integer i4 = 200; 13 | 14 | System.out.println(i1==i2); 15 | System.out.println(i3==i4); 16 | } 17 | } 18 | ``` 19 | 20 | 事实上输出结果是: 21 | 22 | ```java 23 | true 24 | false 25 | ``` 26 | 27 | 输出结果表明i1和i2指向的是同一个对象,而i3和i4指向的是不同的对象。此时只需一看源码便知究竟,**下面这段代码是Integer的valueOf方法的具体实现:** 28 | 29 | ```java 30 | public static Integer valueOf(int i) { 31 | if(i >= -128 && i <= IntegerCache.high) 32 | return IntegerCache.cache[i + 128]; 33 | else 34 | return new Integer(i); 35 | } 36 | ``` 37 | 38 | 在通过valueOf方法创建Integer对象的时候,如果**数值在[-128,127]之间**,便返回指向IntegerCache.cache中**已经存在的对象的引用**;否则**创建一个新的Integer对象**。 39 | 40 | ## 2.下面这段代码的输出结果是什么? 41 | 42 | ```java 43 | public class Main { 44 | public static void main(String[] args) { 45 | 46 | Double i1 = 100.0; 47 | Double i2 = 100.0; 48 | Double i3 = 200.0; 49 | Double i4 = 200.0; 50 | 51 | System.out.println(i1==i2); 52 | System.out.println(i3==i4); 53 | } 54 | } 55 | ``` 56 | 57 | 实际输出结果为: 58 | 59 | ```java 60 | false 61 | false 62 | ``` 63 | 64 | 在某个范围内的整型数值的个数是有限的,而浮点数却不是。 65 | 66 | Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的。 67 | 68 | Double、Float的valueOf方法的实现是类似的。 69 | 70 | ## 3.下面这段代码输出结果是什么: 71 | 72 | ```java 73 | public class Main { 74 | public static void main(String[] args) { 75 | 76 | Boolean i1 = false; 77 | Boolean i2 = false; 78 | Boolean i3 = true; 79 | Boolean i4 = true; 80 | 81 | System.out.println(i1==i2); 82 | System.out.println(i3==i4); 83 | } 84 | } 85 | ``` 86 | 87 | 实际输出结果为: 88 | 89 | ```java 90 | true 91 | true 92 | ``` 93 | 94 | ## 4.谈谈Integer i = new Integer(xxx)和Integer i =xxx;这两种方式的区别。 95 | 96 |   当然,这个题目属于比较宽泛类型的。但是要点一定要答上,我总结一下主要有以下这两点区别: 97 | 98 |   1)第一种方式**不会触发自动装箱**的过程;而第二种方式**会触发**; 99 | 100 |   2)在执行效率和资源占用上的区别。第二种方式的**执行效率和资源占用在一般性情况下要优**于第一种情况(注意这并不是绝对的)。 101 | 102 | ## 5.算术运算会触发自动拆箱过程。 103 | 104 | # 装箱和拆箱 105 | 106 | 装箱就是自动将**基本数据类型转换为包装器类型**; 107 | 108 | 拆箱就是自动将**包装器类型转换为基本数据类型**。 109 | 110 | 例如: 111 | 112 | Integer i = 10; //装箱 113 | int n = i; //拆箱 114 | 115 | Integer是包装器类型,int是基本数据类型。 116 | 117 | ## 如何实现的? 118 | 119 | 在装箱的时候自动调用的是Integer的**valueOf**(int)方法。而在拆箱的时候自动调用的是Integer的**intValue**方法。 120 | 121 | 装箱过程是通过调用包装器的**valueOf方法**实现的,而拆箱过程是通过调用包装器的**xxValue**方法实现的。(xxx代表对应的基本数据类型)。 122 | 123 | -------------------------------------------------------------------------------- /03 多线程和高并发/notes/读写锁.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1.读写状态设计 4 | 5 | 在`ReentrantReadWriteLock`中的同步队列,其实是将同步状态分为了两个部分,其中`高16位`表示`读状态`,`低16位`表示`写状态`,具体情况如下图所示: 6 | 7 | ![读写锁状态划分.png](https://user-gold-cdn.xitu.io/2018/12/18/167c114eedc474ee?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) 8 | 9 | 到现在为止我们已经知道同步状态的划分,那接下来又有新的问题了。`如何快速的区分及获取读写状态呢?`其实也非常简单。 10 | 11 | - 读状态:想要获取读状态,只需要将当前同步变量`无符号右移16位` 12 | - 写状态:我们只需要将当前同步状态(这里用S表示)进行这样的操作`S&0x0000FFFF)`,也就是`S&(1<<16-1)`。 13 | 14 | # 独占锁 15 | 16 | 指该锁只能被一个线程锁持有。对ReetrantLock和Synchronized而言都是独占锁。 17 | 18 | # 共享锁 19 | 20 | 指该锁可被多个线程所持有。 21 | 22 | 对ReentrantReadWriteLock其读锁是共享锁,其写锁是独占锁。 23 | 24 | 读锁的共享锁可保证并发读是非常高效的,读写,写读,写写的过程是互斥的。 25 | 26 | ```java 27 | class MyCache{ 28 | 29 | private volatile Map map = new HashMap(); //保证可见性 30 | private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); 31 | //写 独占+原子 中间不能被分割 32 | public void put(String key, Object value){ 33 | rwlock.writeLock().lock(); 34 | System.out.printIn(Thread.currentThread().getName()+"\t 正在写入:"+key); 35 | try{TimeUnit.MILLISECONDS.sleep(300);} catch(InterruptedException e){ 36 | e.printStackTrace(); 37 | }finally{ 38 | rwLock.writeLock().unlock(); 39 | } 40 | map.put(key,value); 41 | System.out.printIn(Thread.currentThread().getName()+"\t 写入完成:"); 42 | 43 | } 44 | //读 ,可以共享 45 | public void get(String key){ 46 | rwlock.readLock().lock(); 47 | System.out.printIn(Thread.currentThread().getName()+"\t 正在读取:"+key); 48 | try{TimeUnit.MILLISECONDS.sleep(300);} catch(InterruptedException e){ 49 | e.printStackTrace(); 50 | }finally{ 51 | rwlock.readLock().unlock(); 52 | } 53 | Object value = map.get(key); 54 | System.out.printIn(Thread.currentThread().getName()+"\t 读取完成:"); 55 | 56 | } 57 | 58 | } 59 | public class ReadWriteLockDemo{ 60 | public static void main(String[] args){ 61 | MyCache myCache = new MyCache(); 62 | //5个线程写 63 | for(int i = 1; i <= 5; i++){ 64 | final int tempInt = i; 65 | new Thread(() ->{ 66 | myCache.put(tempInt+"",tempInt+""); 67 | 68 | }String.valueOf(i).start()); 69 | } 70 | //5个线程读 71 | for(int i = 1; i <= 5; i++){ 72 | final int tempInt = i; 73 | new Thread(() ->{ 74 | myCache.get(tempInt+"",tempInt+""); 75 | 76 | }String.valueOf(i).start()); 77 | } 78 | } 79 | } 80 | ``` 81 | 82 | 保证了数据的一致性,读写分离,提高了并发性。 83 | 84 | -------------------------------------------------------------------------------- /01 JavaSe/03 基础概念/notes/equals.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1. 为什么equals()方法要重写? 4 | 5 | 判断两个对象在逻辑上是否相等,如根据类的成员变量来判断两个类的实例是否相等,而继承Object中的equals方法只能**判断两个引用变量是否是同一个对象**。这样我们往往需要重写equals()方法。 6 | 7 | ## 2. 怎样重写equals()方法? 8 | 9 | 重写equals方法的要求: 10 | 11 | 1、**自反性**:对于任何非空引用x,x.equals(x)应该返回true。 12 | 13 | 2、**对称性**:对于任何引用x和y,如果x.equals(y)返回true,那么y.equals(x)也应该返回true。 14 | 15 | 3、**传递性**:对于任何引用x、y和z,如果x.equals(y)返回true,y.equals(z)返回true,那么x.equals(z)也应该返回true。 16 | 17 | 4、**一致性**:如果x和y引用的对象没有发生变化,那么反复调用x.equals(y)应该返回同样的结果。 18 | 19 | 5、**非空性**:对于任意非空引用x,x.equals(null)应该返回false。 20 | 21 | ## 3. 重写了equals方法都要进而重写Hashcode方法呢? 22 | 23 | 当equals此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该**协定声明相等对象必须具有相等的哈希码**。 24 | 25 | (1)当obj1.equals(obj2)为true时,obj1.hashCode() == obj2.hashCode()必须为true 26 | 27 | (2)当obj1.hashCode() == obj2.hashCode()为false时,obj1.equals(obj2)必须为false 28 | 29 | 这样如果我们对一个对象重写了euqals,意思是只要对象的成员变量值都相等那么euqals就等于true,但不重写hashcode,那么我们再new一个新的对象,当原对象.equals(新对象)等于true时,**两者的hashcode却是不一样的**,由此将产生了理解的不一致。 30 | 31 | ## 4. 重写 equals 不重写 hashcode 会出现什么问题 32 | 33 | 在存储散列集合时(如 Set 类),如果原对象.equals(新对象),但没有对 hashCode 重写,即两个对象拥有不同的 hashCode,则在集合中将会存**储两个值相同的对象,从而导致混淆**。因此在重写 equals 方法时,必须重写 hashCode 方法。 34 | 35 | ## hashCode() 36 | 37 | **hashCode() 返回散列值**,而 equals() 是用来判断两个对象是否等价。等价的两个对象散列值一定相同,但是散列值相同的两个对象不一定等价。 38 | 39 | 在覆盖 equals() 方法时应当总是覆盖 hashCode() 方法,保证等价的两个对象散列值也相等。 40 | 41 | 下面的代码中,新建了两个等价的对象,并将它们添加到 HashSet 中。我们希望将这两个对象当成一样的,只在集合中添加一个对象,但是因为 EqualExample 没有实现 hasCode() 方法,因此这两个对象的散列值是不同的,最终导致集合添加了两个等价的对象。 42 | 43 | ```java 44 | EqualExample e1 = new EqualExample(1, 1, 1); 45 | EqualExample e2 = new EqualExample(1, 1, 1); 46 | System.out.println(e1.equals(e2)); // true 47 | HashSet set = new HashSet<>(); 48 | set.add(e1); 49 | set.add(e2); 50 | System.out.println(set.size()); // 2 51 | ``` 52 | 53 | 理想的散列函数应当具有均匀性,即不相等的对象应当均匀分布到所有可能的散列值上。这就要求了散列函数要把所有域的值都考虑进来。可以将每个域都当成 R 进制的某一位,然后组成一个 R 进制的整数。R 一般取 31,因为它是一个奇素数,如果是偶数的话,当出现乘法溢出,信息就会丢失,因为与 2 相乘相当于向左移一位。 54 | 55 | 一个数与 31 相乘可以转换成移位和减法:`31*x == (x<<5)-x`,编译器会自动进行这个优化。 56 | 57 | ```java 58 | @Override 59 | public int hashCode() { 60 | int result = 17; 61 | result = 31 * result + x; 62 | result = 31 * result + y; 63 | result = 31 * result + z; 64 | return result; 65 | } 66 | ``` 67 | 68 | ## toString() 69 | 70 | 默认返回 ToStringExample@4554617c 这种形式,其中 @ 后面的数值为散列码的无符号十六进制表示。 71 | 72 | ```java 73 | public class ToStringExample { 74 | 75 | private int number; 76 | 77 | public ToStringExample(int number) { 78 | this.number = number; 79 | } 80 | } 81 | ToStringExample example = new ToStringExample(123); 82 | System.out.println(example.toString()); 83 | ToStringExample@4554617c 84 | ``` -------------------------------------------------------------------------------- /03 多线程和高并发/notes/线程状态.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1.Java线程状态有哪些?(酷家乐) 4 | 5 | 线程的六大状态:创建状态(new)、可运行(Runnable)、阻塞(Blocking)、终止(Terminated)、等待(waiting)、超时等待(Time_Waiting)。 6 | 7 | ## 2.Blocking状态和Waiting状态有什么区别?(酷家乐) 8 | 9 | 处于 blocked状态的线程**等待获取监视器锁**以期**进入同步代码块/方法中** 10 | 11 | 入口区**等待获取锁的线程状**态为Blocked,获取锁失败,然后线程就排队等待。 12 | 13 | 线程可以通过wait,join,LockSupport.park方式进入wating状态,进入wating状态的线程等待唤醒(notify或notifyAll)才有机会获取cpu的时间片段来继续执行。 14 | 15 | 等待区**等待被唤醒的线程状态**为Waiting(Time_Waiting) 16 | 17 | 阻塞和等待的区别在于,阻塞是**被动**的,它是在等待获取一个排它锁。而等待是**主动的**,通过调用 Thread.sleep() 和 Object.wait() 等方法进入。 18 | 19 | TIMED_WAITING 20 | 21 | “一个线程在**一个特定的等待时间**内等待另一个线程完成一个动作会在这个状态” 22 | 23 | 调用以下方法进入TIMED_WAITING 24 | 25 | - Thread#sleep() 26 | 27 | - Object#wait() 并加了超时参数 28 | 29 | - Thread#join() 并加了超时参数 30 | 31 | - LockSupport#parkNanos() 32 | 33 | - LockSupport#parkUntil() 34 | 35 | ### 真实生活例子 36 | 37 | https://segmentfault.com/a/1190000010973341?utm_source=tag-newest 38 | 39 | # 线程状态转换 40 | 41 | ![](https://raw.githubusercontent.com/wuqifan1098/picBed/master/%E7%BA%BF%E7%A8%8B%E7%8A%B6%E6%80%81.png) 42 | 43 | ## 新建(New) 44 | 45 | 创建后尚未启动。 46 | 47 | ## 可运行(Runnable) 48 | 49 | 可能正在运行,也可能正在等待 CPU 时间片。 50 | 51 | 包含了操作系统线程状态中的 **运行(Running ) 和 就绪(Ready)**。 52 | 53 | ## 阻塞(Blocking) 54 | 55 | 这个状态下,是在多个线程有同步操作的场景,比如正在等待另一个线程的 synchronized 块的执行释放,或者可重入的 synchronized 块里别人调用 wait() 方法,也就是线程在等待进入临界区。 56 | 57 | 阻塞可以分为:**等待阻塞,同步阻塞,其他阻塞** 58 | 59 | ## 无限期等待(Waiting) 60 | 61 | 等待其它**线程显式地唤醒**,否则不会被分配 CPU 时间片。 62 | 63 | ## 限期等待(Timed Waiting) 64 | 65 | 无需等待其它线程显式地唤醒,在一定时间之后会被系统**自动唤醒**。 66 | 67 | 调用 Thread.sleep() 方法使线程进入限期等待状态时,常常用 “使一个线程睡眠” 进行描述。 68 | 69 | 调用 Object.wait() 方法使线程进入限期等待或者无限期等待时,常常用 “挂起一个线程” 进行描述。 70 | 71 | 睡眠和挂起是用来描述行为,而阻塞和等待用来描述状态。 72 | 73 | 阻塞和等待的区别在于,阻塞是**被动**的,它是在等待获取一个排它锁。而等待是**主动的**,通过调用 Thread.sleep() 和 Object.wait() 等方法进入。 74 | 75 | ## 死亡(Terminated) 76 | 77 | - 线程因为 run 方法正常退出而自然死亡 78 | 79 | - 因为一个没有捕获的异常终止了 run 方法而意外死亡 80 | 81 | # Demo 82 | 83 | ```java 84 | public class ThreadState{ 85 | public static void main(String[] args){ 86 | new Thread(new TimeWaiting(), "TimeWaitingThread").start(); 87 | new Thread(new Waiting(), "WaitingThread").start(); 88 | //使用两个Blocked线程,一个获取锁成功,一个被阻塞 89 | new Thread(new Blocking(), "BlockingThread-1").start(); 90 | new Thread(new Blocking(), "BlockingThread-2").start(); 91 | } 92 | 93 | //该线程不断进行睡眠 94 | static class TimeWaiting implements Runnable{ 95 | @Override 96 | public void run(){ 97 | while(true){ 98 | SleepUtils.second(100); 99 | } 100 | } 101 | } 102 | 103 | } 104 | ``` 105 | 106 | -------------------------------------------------------------------------------- /01 JavaSe/02 IO/notes/IO模型.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1. java 提供了哪些IO方式 4 | 5 | - 阻塞IO模型 6 | - 非阻塞IO模型 7 | - 异步IO模型 8 | - 多路复用IO模型 9 | - 信号驱动IO模型 10 | 11 | https://blog.csdn.net/hejingyuan6/article/details/47679005 12 | 13 | ## 阻塞式IO模型 14 | 15 | 最传统的一种IO模型,即在读写数据过程中会发生阻塞现象。 16 | 17 | 当用户线程发出IO请求之后,内核会去查看数据是否就绪,如果没有就绪就会等待数据就绪,而用户线程就会处于阻塞状态,用户线程交出CPU。当数据就绪之后,内核会将数据拷贝到用户线程,并返回结果给用户线程,用户线程才解除block状态。 18 | 19 | 典型的阻塞IO模型的例子为: 20 | 21 | ``` 22 | data = socket.read(); 23 | ``` 24 | 25 | 如果数据没有就绪,就会一直阻塞在read方法。 26 | 27 | ## 非阻塞IO模型 28 | 29 | 当用户线程发起一个read操作后,并不需要等待,而是马上就得到了一个结果。如果结果是一个error时,它就知道数据还没有准备好,于是它可以再次发送read操作。一旦内核中的数据准备好了,并且又再次收到了用户线程的请求,那么它马上就将数据拷贝到了用户线程,然后返回。 30 | 31 | 所以事实上,在非阻塞IO模型中,用户线程需要**不断地询问内核数据是否就绪**,也就说非阻塞IO不会交出CPU,而会一直占用CPU。 32 | 33 | 典型的非阻塞IO模型一般如下: 34 | 35 | ``` 36 | while(true){ 37 | data = socket.read(); 38 | if(data!= error){ 39 | 处理数据 40 | break; 41 | } 42 | } 43 | ``` 44 | 45 | 但是对于非阻塞IO就有一个非常严重的问题,在while循环中需要不断地去询问内核数据是否就绪,这样会导致CPU占用率非常高,因此一般情况下很少使用while循环这种方式来读取数据。 46 | 47 | ## IO复用模型 48 | 49 | 多路复用IO模型是目前使用得比较多的模型。Java NIO实际上就是多路复用IO。 50 | 51 | 在多路复用IO模型中,会有一个线程不断去轮询多个socket的状态,只有当socket真正有读写事件时,才真正调用实际的IO读写操作。因为在多路复用IO模型中,只需要使用一个线程就可以管理多个socket,系统不需要建立新的进程或者线程,也不必维护这些线程和进程,并且只有在真正有socket读写事件进行时,才会使用IO资源,所以它大大减少了资源占用。 52 | 53 | 在Java NIO中,是通过selector.select()去查询每个通道是否有到达事件,如果没有事件,则一直阻塞在那里,因此这种方式会导致用户线程的阻塞。 54 | 55 | 也许有朋友会说,我可以采用 多线程+ 阻塞IO 达到类似的效果,但是由于在多线程 + 阻塞IO 中,每个socket对应一个线程,这样会造成很大的资源占用,并且尤其是对于长连接来说,线程的资源一直不会释放,如果后面陆续有很多连接的话,就会造成性能上的瓶颈。 56 | 57 | 而多路复用IO模式,通过一个线程就可以管理多个socket,只有当socket真正有读写事件发生才会占用资源来进行实际的读写操作。因此,多路复用IO比较适合连接数比较多的情况。 58 | 59 | 另外多路复用IO为何比非阻塞IO模型的效率高是因为在非阻塞IO中,不断地询问socket状态时通过用户线程去进行的,而在多路复用IO中,轮询每个socket状态是内核在进行的,这个效率要比用户线程要高的多。 60 | 61 | 不过要注意的是,多路复用IO模型是通过轮询的方式来检测是否有事件到达,并且对到达的事件逐一进行响应。因此对于多路复用IO模型来说,一旦事件响应体很大,那么就会导致后续的事件迟迟得不到处理,并且会影响新的事件轮询。 62 | 63 | ## 信号驱动IO模型 64 | 65 | 在信号驱动IO模型中,当用户线程发起一个IO请求操作,会给对应的socket注册一个信号函数,然后用户线程会继续执行,当内核数据就绪时会发送一个信号给用户线程,用户线程接收到信号之后,便在信号函数中调用IO读写操作来进行实际的IO请求操作。 66 | 67 | ## 异步IO模型 68 | 69 | 异步IO模型是比较理想的IO模型,在异步IO模型中,当用户线程发起read操作之后,立刻就可以开始去做其它的事。而另一方面,从内核的角度,当它受到一个asynchronous read之后,它会立刻返回,说明read请求已经成功发起了,因此不会对用户线程产生任何block。然后,内核会等待数据准备完成,然后将数据拷贝到用户线程,当这一切都完成之后,内核会给用户线程发送一个信号,告诉它read操作完成了。也就说用户线程完全不需要实际的整个IO操作是如何进行的,只需要先发起一个请求,当接收内核返回的成功信号时表示IO操作已经完成,可以直接去使用数据了。 70 | 71 | 也就说在异步IO模型中,IO操作的两个阶段都不会阻塞用户线程,这两个阶段都是由内核自动完成,然后发送一个信号告知用户线程操作已完成。用户线程中不需要再次调用IO函数进行具体的读写。这点是和信号驱动模型有所不同的,在信号驱动模型中,当用户线程接收到信号表示数据已经就绪,然后需要用户线程调用IO函数进行实际的读写操作;而在异步IO模型中,收到信号表示IO操作已经完成,不需要再在用户线程中调用iO函数进行实际的读写操作。 72 | 73 | 注意,异步IO是需要操作系统的底层支持,在Java 7中,提供了Asynchronous IO。 74 | 75 | 前面四种IO模型实际上都属于同步IO,只有最后一种是真正的异步IO,因为无论是多路复用IO还是信号驱动模型,IO操作的第2个阶段都会引起用户线程阻塞,也就是内核进行数据拷贝的过程都会让用户线程阻塞。 76 | 77 | 转载:https://github.com/hollischuang/toBeTopJavaer/blob/master/basics/java-basic/linux-io.md -------------------------------------------------------------------------------- /08 数据库/01 MySQL/notes/三大范式.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1. 说说三大范式 4 | 5 | 第一范式: **每个列都不可以再拆分**。强调的是**原子性**。 6 | 7 | 第二范式: 首先满足1NF,**非主键列完全依赖于主键**,而不能是依赖于主键的一部分。 8 | 9 | 第三范式: 首先满足2NF,**非主键列直接依赖于主键,不是通过传递关系依赖**。即不能存在:非主键列 A 依赖于非主键列 B, 10 | 11 | 非主键列 B 依赖于主键的情况。 12 | 13 | ## 2. 范式的存在有什么好处 14 | 15 | 范式可以**避免数据冗余,减少数据库的空间,减轻维护数据完整性的麻烦。** 16 | 17 | # 反范式 18 | 19 | 范式再给我们带来的上面的好处时,同时也伴随着一些不好的地方:按照范式的规范设计出来的表,等级越高的范式设计出来的表越多。如第一范式可能设计出来的表可能只有一张表而已,再按照第二范式去设计这张表时就可能出来两张或更多张表,如果再按第三范式或更高的范式去设计这张表会出现更多比第二范式多的表。表的数量越多,当我们去查询一些数据,必然要去多表中去查询数据,这样查询的时间要比在一张表中查询中所用的时间要高很多。 20 | 21 | 也就是说我们所用的范式越高,对数据操作的性能越低。所以我们在利用范式设计表的时候,要根据具体的需求再去权衡是否使用更高范式去设计表。在一般的项目中,我们用的最多也就是第三范式,第三范式也就可以满足我们的项目需求,性能好而且方便管理数据; 22 | 23 | 当我们的业务所涉及的表非常多,经常会有多表发生关系,并且我们对表的操作要时间上要尽量的快,这时可以考虑我们使用“反范式”。反范式,故名思义,跟范式所要求的正好相反,在反范式的设计模式,我们可以允许适当的数据的冗余,用这个冗余去取操作数据时间的缩短。也就是用空间来换取时间,把数据冗余在多个表中,当查询时可以减少或者是避免表之间的关联。 24 | 原文链接:https://blog.csdn.net/traceofsun/article/details/6411344 25 | 26 | # **第一范式** 27 | 28 | 1. 概念:列不可分。每一列都是不可分割的基本数据项。 29 | 2. 例子:假设我们有一个学生表,字段包括:id,name,age,contact,如下: 30 | 31 | ![img](https://user-gold-cdn.xitu.io/2019/6/26/16b915dc56615eec?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) 32 | 33 | 当我们需要根据QQ来查询学生的时候,就查询不出,所以以上的设计就不符合1NF。我们可以将contact字段拆分为phone和QQ,如下: 34 | 35 | ![img](https://user-gold-cdn.xitu.io/2019/6/26/16b915dcf2c8008f?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) 36 | 37 | 这样就满足1NF了。 38 | 39 | # **第二范式**    40 | 41 | 1. 概念:1NF的基础上面,非主属性完全依赖于主关键字。 42 | 2. 例子:学生表:(学号, 姓名, 年龄, 课程名称, 成绩, 学分) ,从字段可以看出,此表联合主键是(学号,课程名称)。 43 | 44 | 存在如下决定关系: 45 | 46 | 1. (学号, 课程名称) → (姓名, 年龄, 成绩, 学分) 47 | 2. (课程名称) → (学分) 48 | 3. (学号) → (姓名, 年龄) 49 | 50 | 其中,姓名、年龄、学分是部分依赖于主键的,而成绩是完全依赖于主键的,存在部分依赖关系,所以不满足第二范式。 51 | 52 | 这会造成如下问题: 53 | 54 | (1) 数据冗余: 55 | 56 |  同一门课程由n个学生选修,"学分"就重复n-1次;同一个学生选修了m门课程,姓名和年龄就重复了m-1次。 57 | 58 |   (2) 更新异常: 59 | 60 |  若调整了某门课程的学分,数据表中所有行的"学分"值都要更新,否则会出现同一门课程学分不同的情况。 61 | 62 |   (3) 插入异常: 63 | 64 |   假设要开设一门新的课程,暂时还没有人选修。这样,由于还没有"学号"关键字,课程名称和学分也无法记录入数据 库。 65 | 66 | ​ (4) 删除异常: 67 | 68 |   假设一批学生已经完成课程的选修,这些选修记录就应该从数据库表中删除。但是,与此同时,课程名称和学分信息也被删除了。很显然,这也会导致插入异常。 69 | 70 | 问题就在于存在非主属性对主键的部分依赖。 71 | 72 | 解决办法:把原表(学号, 姓名, 年龄, 课程名称, 成绩, 学分)分成三个表: 73 | 74 | - 学生:Student(学号, 姓名, 年龄); 75 | - 课程:Course(课程名称, 学分); 76 | - 选课关系:SelectCourse(学号, 课程名称, 成绩)。 77 | 78 | # **第三范式** 79 | 80 | 1. 概念:2NF的基础上,属性不依赖于其它非主属性 , 消除传递依赖。第三范式又可描述为:表中不存在可以确定其他非关键字的非关键字段。 81 | 2. 例子:学生表:(学号, 姓名, 年龄, 所在学院, 学院地点, 学院电话),主键必然是学号。 82 | 83 | 由于主键是单一属性,所以非主属性完全依赖于主键,所以必然满足第二范式。但是存在如下传递依赖: 84 | 85 | (学号) → (所在学院) → (学院地点, 学院电话), 86 | 87 | 学院地点 和 学院电话传递依赖于学号,而学院地点和学院电话都是非关键字段,即表中出现了“某一非关键字段可以确定出其它非关键字段”的情况,于是违反了第三范式。           88 | 89 | 解决办法: 90 | 91 | 把原表分成两个表: 92 | 93 | - 学生:(学号, 姓名, 年龄, 所在学院); 94 | - 学院:(学院, 地点, 电话)。 95 | 96 | 97 | 作者:码咖链接:https://juejin.im/post/5d12c825e51d4510664d1706 -------------------------------------------------------------------------------- /08 数据库/02 Redis/notes/数据一致性.md: -------------------------------------------------------------------------------- 1 | ### 对于读操作,流程是这样的 2 | 3 | 上面讲缓存穿透的时候也提到了:如果从数据库查不到数据则不写入缓存。 4 | 5 | 一般我们对**读操作**的时候有这么一个**固定的套路**: 6 | 7 | - 如果我们的数据在缓存里边有,那么就直接取缓存的。 8 | - 如果缓存里没有我们想要的数据,我们会先去查询数据库,然后**将数据库查出来的数据写到缓存中**。 9 | - 最后将数据返回给请求 10 | 11 | ### 什么是缓存与数据库双写一致问题 12 | 13 | 如果仅仅查询的话,缓存的数据和数据库的数据是没问题的。但是,当我们要**更新**时候呢?各种情况很可能就**造成数据库和缓存的数据不一致**了。 14 | 15 | - 这里不一致指的是:**数据库的数据跟缓存的数据不一致** 16 | 17 | ![](https://raw.githubusercontent.com/wuqifan1098/picBed/master/20190529210058.png) 18 | 19 | 从理论上说,只要我们设置了**键的过期时间**,我们就能保证缓存和数据库的数据**最终是一致**的。因为只要缓存数据过期了,就会被删除。随后读的时候,因为缓存里没有,就可以查数据库的数据,然后将数据库查出来的数据写入到缓存中。 20 | 21 | 除了设置过期时间,我们还需要做更多的措施来**尽量避免**数据库与缓存处于不一致的情况发生。 22 | 23 | ### 对于更新操作 24 | 25 | 一般来说,执行更新操作时,我们会有两种选择: 26 | 27 | - 先操作数据库,再操作缓存 28 | - 先操作缓存,再操作数据库 29 | 30 | 首先,要明确的是,无论我们选择哪个,我们都希望这**两个操作要么同时成功,要么同时失败**。所以,这会演变成一个**分布式事务**的问题。 31 | 32 | 所以,**如果原子性被破坏了**,可能会有以下的情况: 33 | 34 | - **操作数据库成功了,操作缓存失败了**。 35 | - **操作缓存成功了,操作数据库失败了**。 36 | 37 | 如果第一步已经失败了,我们直接返回Exception出去就好了,第二步根本不会执行。 38 | 39 | #### 1、操作缓存 40 | 41 | 操作缓存也有两种方案: 42 | 43 | - 更新缓存 44 | - 删除缓存 45 | 46 | 一般我们都是采取**删除缓存**缓存策略的,原因如下: 47 | 48 | 1. 高并发环境下,无论是先操作数据库还是后操作数据库而言,如果加上更新缓存,那就**更加容易**导致数据库与缓存数据不一致问题。(删除缓存**直接和简单**很多) 49 | 2. 如果每次更新了数据库,都要更新缓存【这里指的是频繁更新的场景,这会耗费一定的性能】,倒不如直接删除掉。等再次读取时,缓存里没有,那我到数据库找,在数据库找到再写到缓存里边(体现**懒加载**) 50 | 51 | 基于这两点,对于缓存在更新时而言,都是建议执行**删除**操作! 52 | 53 | #### 2、先更新数据库,再删除缓存 54 | 55 | 正常的情况是这样的: 56 | 57 | - 先操作数据库,成功; 58 | - 再删除缓存,也成功; 59 | 60 | 如果原子性被破坏了: 61 | 62 | - 第一步成功(操作数据库),第二步失败(删除缓存),会导致**数据库里是新数据,而缓存里是旧数据**。 63 | - 如果第一步(操作数据库)就失败了,我们可以直接返回错误(Exception),不会出现数据不一致。 64 | 65 | 如果在高并发的场景下,出现数据库与缓存数据不一致的**概率特别低**,也不是没有: 66 | 67 | - 缓存**刚好**失效 68 | - 线程A查询数据库,得一个旧值 69 | - 线程B将新值写入数据库 70 | - 线程B删除缓存 71 | - 线程A将查到的旧值写入缓存 72 | 73 | 要达成上述情况,还是说一句**概率特别低**: 74 | 75 | > 因为这个条件需要发生在读缓存时缓存失效,而且并发着有一个写操作。而实际上数据库的写操作会比读操作慢得多,而且还要锁表,**而读操作必需在写操作前进入数据库操作,而又要晚于写操作更新缓存**,所有的这些条件都具备的概率基本并不大。 76 | 77 | **删除缓存失败的解决思路**: 78 | 79 | - 将需要删除的key发送到消息队列中 80 | - 自己消费消息,获得需要删除的key 81 | - **不断重试删除操作,直到成功** 82 | 83 | #### **3、先删除缓存,再更新数据库** 84 | 85 | 正常情况是这样的: 86 | 87 | - 先删除缓存,成功; 88 | - 再更新数据库,也成功; 89 | 90 | 如果原子性被破坏了: 91 | 92 | - 第一步成功(删除缓存),第二步失败(更新数据库),数据库和缓存的数据还是一致的。 93 | - 如果第一步(删除缓存)就失败了,我们可以直接返回错误(Exception),数据库和缓存的数据还是一致的。 94 | 95 | 看起来是很美好,但是我们在并发场景下分析一下,就知道还是有问题的了: 96 | 97 | - 线程A删除了缓存 98 | - 线程B查询,发现缓存已不存在 99 | - 线程B去数据库查询得到旧值 100 | - 线程B将旧值写入缓存 101 | - 线程A将新值写入数据库 102 | 103 | 所以也会导致数据库和缓存不一致的问题。 104 | 105 | **并发下解决数据库与缓存不一致的思路**: 106 | 107 | - 将删除缓存、修改数据库、读取缓存等的操作积压到**队列**里边,实现**串行化**。 108 | 109 | #### 4、对比两种策略 110 | 111 | 我们可以发现,两种策略各自有优缺点: 112 | 113 | - 先删除缓存,再更新数据库 114 | 115 | - - 在高并发下表现不如意,在原子性被破坏时表现优异 116 | 117 | - 先更新数据库,再删除缓存(`Cache Aside Pattern`设计模式) 118 | 119 | - - 在高并发下表现优异,在原子性被破坏时表现不如意 -------------------------------------------------------------------------------- /08 数据库/01 MySQL/notes/主从复制与读写分离.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1.MySQL主从复制 4 | 5 | 主服务器上的任何修改都会保存到二进制日志Binary log里面,从服务器上启动一个I/O线程,连接到主服务器上面请求读取二进制日志,然后把读取到的二进制日志写到本地的Relay log中。从服务器上面开启一个SQL 线程定时检查Relay log,如果有有更改立即把更改的内容在本机上执行一遍。 6 | 7 | #### 一主多从 8 | 9 | 由一个master和一个slave组成复制系统是最简单的情况。Slave之间并不相互通信,只能与master进行通信。在实际应用场景中,MySQL复制90%以上都是**一个Master复制到一个或者多个Slave的架构模式,主要用于读压力比较大的应用的数据库端廉价扩展解决方案。** 10 | 11 | #### 主主复制 12 | 13 | [![MySQL主从复制原理及配置实现](https://segmentfault.com/img/remote/1460000008942626?w=212&h=108)](http://photo.blog.sina.com.cn/showpic.html#blogid=821512b50101hxod&url=http://album.sina.com.cn/pic/002nHcUtgy6GESHubtX6d) 14 | 15 | 上图中,Master-Master复制的两台服务器,既是master,又是另一台服务器的slave。这样,任何一方所做的变更,都会通过复制应用到另外一方的数据库中。在这种复制架构中,各自上运行的不是同一db,比如左边的是db1,右边的是db2,db1的从在右边反之db2的从在左边,两者互为主从,再辅助一些监控的服务还可以实现一定程度上的高可以用。 16 | 17 | # 主从复制 18 | 19 | 主要涉及三个线程:**binlog 线程、I/O 线程和 SQL 线程。** 20 | 21 | - binlog 线程 :负责将**主服务器上的数据更改写入二进制文件(binlog)中**。 22 | - I/O 线程 :负责从**主服务器上读取二进制日志文件,并写入从服务器的中继日志中**。 23 | - SQL 线程 :负责**读取中继日志并重放其中的 SQL 语句**。 24 | 25 | 1. binlog输出线程:每当有从库连接到主库的时候,**主库都会创建一个线程然后发送binlog内容到从库**。 26 | 27 | 在从库里,当复制开始的时候,从库就会创建两个线程进行处理: 28 | 29 | 1. 从库I/O线程:当START SLAVE语句在从库开始执行之后,**从库创建一个I/O线程,该线程连接到主库并请求主库发送binlog里面的更新记录到从库上。**从库I/O线程读取主库的binlog输出线程发送的更新并拷贝这些更新到本地文件,其中包括relay log文件。 30 | 31 | 1. 从库的SQL线程:从库创建一个SQL线程,这个线程读取从库I/O线程写到relay log的更新事件并执行。 32 | 33 | 复制主要有三个步骤: 34 | 35 | 1. 在主库上把数据更改记录到**二进制日志**(Binary Log)中。 36 | 1. 备库将主库上的日志复制到自己的**中继日志中**(Relay Log)。 37 | 1. 备库读取中继日志中的事件,将其重放在到**备库数据之上**。 38 | 39 | ![](https://raw.githubusercontent.com/wuqifan1098/picBed/master/master-slave.png) 40 | 41 | ## 主从复制的作用(好处,或者说为什么要做主从) 42 | 43 | 1. 做数据的热备,**作为后备数据库**,主数据库服务器故障后,可切换到从数据库继续工作,**避免数据丢失**。 44 | 45 | 1. 架构的扩展。业务量越来越大,I/O访问频率过高,单机无法满足,此时做多库的存储,**降低磁盘I/O访问的频率,提高单个机器的I/O性能**。 46 | 47 | 1. **读写分离,使数据库能支撑更大的并发。**在报表中尤其重要。由于部分报表sql语句非常的慢,导致锁表,影响前台服务。如果前台使用master,报表使用slave,那么报表sql将不会造成前台锁,保证了前台速度。 48 | 49 | ## 主从复制的原理(重中之重,面试必问) 50 | 51 | 1.数据库有个**bin-log二进制文件,记录了所有sql语句**。 52 | 53 | 2.我们的目标就是把主数据库的bin-log文件的sql语句复制过来。 54 | 55 | 3.让其在从数据的relay-log重做日志文件中再执行一次这些sql语句即可。 56 | 57 | 4.下面的主从配置就是围绕这个原理配置 58 | 59 | ## 服务器挂了怎么办 60 | 61 | 1.确保binlog全部传到从库 62 | 63 | 方案一:使用semi sync(半同步)方式,事务提交后,必须要传到slave,事务才能算结束。对性能影响很大,依赖网络适合小tps系统。 64 | 65 | 方案二:双写binlog,通过DBDR OS层的文件系统复制到备机,或者使用共享盘保存binlog日志。 66 | 67 | 方案三:在数据层做文章,比如保证数据库写成功后,再异步队列的方式写一份,部分业务可以借助设计和数据流解决。 68 | 69 | 2.保证数据最小化丢失 70 | 71 | 上面的方案设计及架构比较复杂,如果能容忍数据的丢失,可以考虑使用淘宝的TMHA复制管理工具。 72 | 73 | 当master宕机后,TMHA会选择一个binlog接收最大的slave作为master。当原master宕机恢复后,通过binlog的逆向应用,把原master上多执行的事务回退掉。 74 | 75 | https://blog.51cto.com/xxr007/1965600 76 | 77 | # 读写分离 78 | 79 | 主服务器用来处理写操作以及实时性要求比较高的读操作,而从服务器用来处理读操作。 80 | 81 | 读写分离常用代理方式来实现,代理服务器接收应用层传来的读写请求,然后决定转发到哪个服务器。 82 | 83 | MySQL 读写分离能提高性能的原因在于: 84 | 85 | - 主从服务器**负责各自的读和写,极大程度缓解了锁的争用**; 86 | - 从服务器可以配置 MyISAM 引擎,提升查询性能以及节约系统开销; 87 | - 增加冗余,**提高可用性**。 -------------------------------------------------------------------------------- /08 数据库/01 MySQL/notes/MVCC多版本并发控制.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1. MVCC和乐观锁的区别 4 | 5 | 多版本并发控制(MVCC)是一种用来**解决读-写冲突**的无锁并发控制,也就是为事务分配单向增长的时间戳,为每个修改保存一个版本,版本与事务时间戳关联,读操作**只读该事务开始前的数据库的快照**。 这样在读操作不用阻塞写操作,写操作不用阻塞读操作的同时,避免了脏读和不可重复读 6 | 7 | 乐观并发控制(OCC)是一种用来**解决写-写冲突**的无锁并发控制,认为事务间争用没有那么多,所以先进行修改,在提交事务前,检查一下事务开始后,有没有新提交改变,如果没有就提交,如果有就放弃并重试。乐观并发控制类似自选锁。乐观并发控制适用于低数据争用,写冲突比较少的环境。 8 | 9 | 多版本并发控制可以结合基于锁的并发控制来解决写-写冲突,即MVCC+2PL,也可以结合乐观并发控制来解决写-写冲突。 10 | 11 | https://www.zhihu.com/question/27876575 12 | 13 | ## 2. MVCC怎么实现的,解决什么问题 14 | 15 | **MVCC是通过保存数据在某个时间点的快照来实现的**. 16 | 17 | **InnoDB的MVCC,是通过在每行记录后面保存两个隐藏的列来实现的,这两个列,分别保存了这个行的创建时间,一个保存的是行的删除时间**。这里存储的并不是实际的时间值,而是系统版本号(可以理解为事务的ID),没开始一个新的事务,系统版本号就会自动递增,事务开始时刻的系统版本号会作为事务的ID 18 | 19 | https://www.cnblogs.com/shoshana-kong/p/11244612.html 20 | 21 | **在开启事务时,对操作记录加行锁,事务结束时释放锁。**但是这样加锁会降低事务的并发量,并且对线程的阻塞和恢复操作也会损耗性能。那种在事务中使用了select …… for update/ lock in share mode 的就是对记录使用了行锁,实现一致性锁定读。而对于未加锁的记录,在innodb中的repeatable read级别下会通过mvcc进行并发控制,实现一致性非锁定读。 22 | 23 | 原文链接:https://blog.csdn.net/zuhizo/article/details/80852423 24 | 25 | ## 3. 什么是当前读和快照读? 26 | 27 | - 当前读 28 | 29 | 像select lock in share mode(共享锁), select for update ; update, insert ,delete(排他锁)这些操作都是一种当前读,为什么叫当前读?就是它读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,**会对读取的记录进行加锁** 30 | 31 | - 快照读 32 | **像不加锁的select操作就是快照读,即不加锁的非阻塞读**;快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读;之所以出现快照读的情况,是基于提高并发性能的考虑,快照读的实现是基于多版本并发控制,即MVCC**,可以认为MVCC是行锁的一个变种,但它在很多情况下,避免了加锁操作,降低了开销;**既然是基于多版本,即快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本 33 | 34 | 原文链接:https://blog.csdn.net/SnailMann/article/details/94724197 35 | 36 | 37 | 38 | # MVCC能解决什么问题,好处是? 39 | 40 | 数据库并发场景有三种,分别为: 41 | 42 | 读-读:不存在任何问题,也不需要并发控制 43 | 读-写:有线程安全问题,可能会造成事务隔离性问题,可能遇到脏读,幻读,不可重复读 44 | 写-写:有线程安全问题,可能会存在更新丢失问题,比如第一类更新丢失,第二类更新丢失 45 | 46 | ## MVCC带来的好处是? 47 | 48 | 多版本并发控制(MVCC)是一种用来解决读-写冲突的无锁并发控制,也就是为事务分配单向增长的时间戳,为每个修改保存一个版本,版本与事务时间戳关联,读操作只读该事务开始前的数据库的快照。 所以MVCC可以为数据库解决以下问题 49 | 50 | - 在并发读写数据库时,可以**做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作**,提高了数据库**并发读写**的性能 51 | - 同时还可以解决脏读,幻读,不可重复读等事务隔离问题,但不能解决更新丢失问题 52 | 53 | ## 总结 54 | 55 | MVCC就是因为大牛们,不满意只让数据库采用悲观锁这样性能不佳的形式去解决读-写冲突问题,而提出的解决方案,所以在数据库中,因为有了MVCC,所以我们可以形成两个组合: 56 | 57 | - MVCC + 悲观锁 58 | 59 | MVCC解决读写冲突,悲观锁解决写写冲突 60 | 61 | - MVCC + 乐观锁 62 | 63 | MVCC解决读写冲突,乐观锁解决写写冲突 64 | 这种组合的方式就可以最大程度的提高数据库并发性能,并解决读写冲突,和写写冲突导致的问题 65 | 66 | # MVCC的实现原理 67 | 68 | MVCC的目的就是多版本并发控制,在数据库中的实现,就是为了解决读写冲突,它的实现原理主要是依赖记录中的 **3个隐式字段,undo日志 ,Read View** 来实现的。所以我们先来看看这个三个point的概念 69 | 70 | ## 隐式字段 71 | 72 | 每行记录除了我们自定义的字段外,还有数据库隐式定义的DB_TRX_ID,DB_ROLL_PTR,DB_ROW_ID等字段 73 | 74 | - DB_TRX_ID 75 | 76 | 6byte,最近修改(修改/插入)事务ID:记录创建这条记录/最后一次修改该记录的事务ID 77 | 78 | - DB_ROLL_PTR 79 | 80 | 7byte,回滚指针,指向这条记录的上一个版本(存储于rollback segment里) 81 | 82 | - DB_ROW_ID 83 | 6byte,隐含的自增ID(隐藏主键),如果数据表没有主键,InnoDB会自动以DB_ROW_ID产生一个聚簇索引 84 | 实际还有一个删除flag隐藏字段, 既记录被更新或删除并不代表真的删除,而是删除flag变了 85 | 86 | 原文链接:https://blog.csdn.net/SnailMann/article/details/94724197 -------------------------------------------------------------------------------- /08 数据库/02 Redis/notes/过期策略和淘汰策略.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1.怎么定制过期删除策略 4 | 5 | - **定时删除**:在设置键过去的时间同时,创建一个定时器,让定时器在键过期时间来临,立即执行对键的删除操作。 6 | - **惰性删除**:放任键过期不管,但是**每次从键空间获取键时,都会检查该键是否过期**,如果过期的话,就删除该键。 7 | - **定期删除**:**每隔一段时间,程序都要对数据库进行一次检查,删除里面的过期键**,至于要删除多少过期键,由算法而定。 8 | 9 | # redis 过期策略 10 | 11 | **1、定时删除** 12 | 13 | 设置键的过期时间,创建定时器,**一旦过期时间来临,就立即对键进行操作。** 14 | 15 | 这种对内存是友好的,但是对 CPU 的时间是最不友好的,特别是在业务繁忙,过期键很多的时候,删除过期键这个操作就会**占据很大一部分 CPU 的时间。** 16 | 17 | 要知道 Redis 是单线程操作,在内存不紧张而 CPU 紧张的时候,将 CPU 的时间浪费在与业务无关的删除过期键上面,会对 Redis 的服务器的响应时间和吞吐量造成影响。 18 | 19 | 另外,创建一个定时器需要用到 Redis 服务器中的时间事件,而当前时间事件的实现方式是无序链表,时间复杂度为 O(n),让服务器大量创建定时器去实现定时删除策略,会产生较大的性能影响 20 | 21 | 所以,定时删除并不是一种好的删除策略。 22 | 23 | **2、惰性删除** 24 | 25 | 与定时删除相反,惰性删除策略对 CPU 来说是最友好的,程序只有在取出键的时候才会进行检查,是一种被动的过程。 26 | 27 | 与此同时,惰性删除对内存来说又是最不友好的,一个键过期,只要不再被取出,这个过期键就不会被删除,它占用的内存也不会被释放。 28 | 29 | 很明显,惰性删除也不是一个很好的策略,Redis 是非常依赖内存和较好内存的,**如果一些长期键长期没有被访问,就会造成大量的内存垃圾,甚至会操成内存的泄漏。** 30 | 31 | 在对执行数据写入时,通过 expireIfNeeded 函数对写入的 Key 进行过期判断。 32 | 33 | 其中 expireIfNeeded 在内部做了三件事情,分别是: 34 | 35 | - 查看 Key 是否过期。 36 | - 向 Slave 节点传播执行过去 Key 的动作。 37 | - 删除过期 Key。 38 | 39 | **3、定期删除** 40 | 41 | 上面两种删除策略,无论是定时删除和惰性删除,这两种删除方式在单一的使用上都存在明显的缺陷,要么**占用太多 CPU 时间,要么浪费太多内存。** 42 | 43 | 定期删除策略是前两种策略的一个整合和折中: 44 | 45 | - 定期删除策略**每隔一段时间执行一次删除过期键操作**,并通过限制删除操作执行的时间和频率来减少删除操作对 CPU 时间的影响。 46 | - 通过合理的删除执行的时长和频率,来达到合理的删除过期键。 47 | 48 | # redis 内存淘汰机制 49 | 50 | redis提供了6种数据淘汰策略: 51 | 52 | - noeviction: 当内存不足以容纳新写入数据时,新写入操作会报错,这个一般没人用吧,实在是太恶心了。 53 | - allkeys-lru:当内存不足以容纳新写入数据时,**在键空间中,移除最近最少使用的 key**(这个是最常用的)。 54 | - allkeys-random:当内存不足以容纳新写入数据时,**在键空间中,随机移除某个 key**,这个一般没人用吧,为啥要随机,肯定是把最近最少使用的 key 给干掉啊。 55 | - volatile-lru:当内存不足以容纳新写入数据时,**在设置了过期时间的键空间中**,移除最近最少使用的 key(这个一般不太合适)。 56 | - volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个 key。 57 | - volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,**有更早过期时间的 key 优先移除**。 58 | 59 | # 手写一个LRU算法 60 | 61 | 利用LinkedHashMap实现 62 | linkedHashMap还可以实现按照访问顺序保存元素。 63 | 64 | ```java 65 | public class UseLinkedHashMapCache extends LinkedHashMap{ 66 | 67 | private int cacheSize; 68 | public UseLinkedHashMapCache(int cacheSize){ 69 | //构造函数一定要放在第一行 70 | super(16,0.75f,true); //那个f如果不加 就是double类型,然后该构造没有该类型的入参。 然后最为关键的就是那个入参 true 71 | this.cacheSize = cacheSize; 72 | } 73 | 74 | @Override 75 | protected boolean removeEldestEntry(Map.Entry eldest)} //重写LinkedHashMap原方法 76 | return size() > cacheSize; //临界条件不能有等于,否则会让缓存尺寸小1 77 | } 78 | ``` 79 | 80 | 关键点: 81 | 82 | 继承了LinkedHashMap并使用 83 | 84 | ```java 85 | public LinkedHashMap(int initialCapacity, 86 | float loadFactor, 87 | boolean accessOrder) { 88 | super(initialCapacity, loadFactor); 89 | this.accessOrder = accessOrder; 90 | } 91 | ``` 92 | 93 | 构造函数 94 | 95 | 重写了 96 | 97 | ```java 98 | protected boolean removeEldestEntry(Map.Entry eldest) { 99 | return false; 100 | } 101 | ``` 102 | 103 | -------------------------------------------------------------------------------- /01 JavaSe/01 集合框架/notes/Vector.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1. Vector线程安全问题 4 | 5 | 虽然源代码注释里面说这个是线程安全的,因为确实很多方法都加上了同步关键字synchronized,但是对于符合操作而言,只是同步方法并没有解决线程安全的问题。 6 | 7 | 要真正达成线程安全,还需要以vector对象为锁,来进行操作。 8 | 9 | 所以,如果是这样的话,那么用vector和ArrayList就没有区别了,所以,不推荐使用vector。 10 | 11 | 当然会有安全问题,比如说另一个线程持有一个迭代器对象,那么会导致迭代器状态无效。你有两个办法,一个是锁住向量变量,一个是查询的时候先复制一个vector的副本。关键看你对同步的要求和为读还是写优化(程序里查询的多还是修改的多) 12 | 13 | # Vector 14 | 15 | ## 概览 16 | 17 | 实现了**List接口,继承了AbstractList**。 18 | 19 | 实现了 **RandomAccess **接口,因此**支持随机访问**。Vector底层实现是**数组**。 20 | 21 | 实现了**Serializable**接口,因此它**支持序列化**。 22 | 23 | 实现了**Cloneable**接口,能被**克隆**。 24 | 25 | ```java 26 | public class Vector extends AbstractList 27 | implements List, RandomAccess, Cloneable, java.io.Serializable 28 | ``` 29 | 30 | ## 1.同步 31 | 32 | 它的实现与 ArrayList 类似,但是**使用了 synchronized 进行同步**,这就是Vector为什么是线程安全的原因。 33 | 这个类的线程安全,是建立在几乎**所有修改集合操作**的方法都加了synchronized关键字,例如: 34 | 35 | ```java 36 | public synchronized boolean add(E e) { 37 | modCount++; 38 | ensureCapacityHelper(elementCount + 1); 39 | elementData[elementCount++] = e; 40 | return true; 41 | } 42 | 43 | public synchronized E get(int index) { 44 | if (index >= elementCount) 45 | throw new ArrayIndexOutOfBoundsException(index); 46 | return elementData(index); 47 | } 48 | ``` 49 | 50 | ## 2.重要成员变量 51 | 52 | ```java 53 | protected Object[] elementData; //Object数组,说明Vector底层实现是数组 54 | protected int elementCount; //实际大小 55 | protected int capacityIncrement; //动态数组的增长系数,扩容时增加大小为capacityIncrement 56 | ``` 57 | 58 | capacityIncrement 是我们可控的一个参数,在构造方法中传入,即每次容量具体增加多少,如果我们在创建 Vector 对象是没有指定 capacityIncrement,则**默认每次把容量增加为原来的二倍**(不越界的情况下)。 59 | 60 | ## 3.扩容 61 | 62 | ```java 63 | private void ensureCapacityHelper(int minCapacity) { 64 | if (minCapacity - elementData.length > 0) 65 | grow(minCapacity); 66 | ``` 67 | 68 | 通过grow()方法扩容。 69 | 70 | ```java 71 | private void grow(int minCapacity) { 72 | int oldCapacity = elementData.length; 73 | int newCapacity = oldCapacity + ((capacityIncrement > 0) ? 74 | capacityIncrement : oldCapacity); 75 | if (newCapacity - minCapacity < 0) 76 | newCapacity = minCapacity; 77 | if (newCapacity - MAX_ARRAY_SIZE > 0) 78 | newCapacity = hugeCapacity(minCapacity); 79 | elementData = Arrays.copyOf(elementData, newCapacity); 80 | } 81 | ``` 82 | 83 | Vector与ArrayList比较明显不同就是grow方法数组容量的扩增算法,oldCapacity + ((capacityIncrement > 0) ?capacityIncrement : oldCapacity)。 84 | 85 |   如果是通过new Vector()实例化对象,**此时capacityIncrement变量的值就会默认为0,那每次容量就只是扩增一倍(100%)**。 86 |   如果是通过Vector(int initialCapacity, int capacityIncrement)实例化Vector,只要你传入的capacityIncrement不小于0,那么数组的容量就能按照你设置的值来扩增。其它代码部分与ArrayList差不多。 87 | 88 | 89 | ## 4.为什么是一个遗弃的类 90 | 91 | Vector中对**每一个独立操作都实现了同步**,这通常不是我们想要的做法。对单一操作实现同步通常不是线程安全的(举个例子,比如你想遍历一个Vector实例。你仍然需要申明一个锁来防止其他线程在同一时刻修改这个Vector实例。如果不添加锁的话通常会在遍历实例的这个线程中导致一个ConcurrentModificationException)同时这个操作也是十分慢的(在创建了一个锁就已经足够的前提下,为什么还需要重复的创建锁)当然,即使你不需要同步,Vector也是有锁的资源开销的。 92 | 93 | -------------------------------------------------------------------------------- /07 操作系统/notes/内存管理.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1.**操作系统中的虚拟内存了解吗?说一下它的作用** 4 | 5 | 虚拟内存的目的是**为了让物理内存扩充成更大的逻辑内存**,从而让程序获得更多的可用内存。 6 | 7 | https://juejin.im/post/5d7839076fb9a06b130f4dac 8 | 9 | # 虚拟内存 10 | 11 | 虚拟内存的目的是**为了让物理内存扩充成更大的逻辑内存**,从而让程序获得更多的可用内存。 12 | 13 | 为了更好的管理内存,操作系统将内存抽象成地址空间。每个程序拥有自己的地址空间,这个地址空间被分割成多个块,每一块称为一页。这些页被映射到物理内存,但不需要映射到连续的物理内存,也不需要所有页都必须在物理内存中。当程序引用到不在物理内存中的页时,由硬件执行必要的映射,将缺失的部分装入物理内存并重新执行失败的指令。 14 | 15 | 从上面的描述中可以看出,**虚拟内存允许程序不用将地址空间中的每一页都映射到物理内存,也就是说一个程序不需要全部调入内存就可以运行,这使得有限的内存运行大程序成为可能**。例如有一台计算机可以产生 16 位地址,那么一个程序的地址空间范围是 0~64K。该计算机只有 32KB 的物理内存,虚拟内存技术允许该计算机运行一个 64K 大小的程序。 16 | 17 | # 物理地址和虚拟地址分别指什么? 18 | 19 | 物理地址:就是**内存中实际存在的地址**,也就是我们电脑中内存条中所表示的地址。 20 | 21 | 虚拟地址:被分成虚拟页号(高位)和偏移量(低位)是一种虚拟化的地址,**是由程序产生的地址**。虚拟地址与物理地址不是一一对应关系,它们之间存在映射关系。而转换就是通过MMU(其中MMU(内存管理单元):作用为把虚拟地址映射为物理内存地址)来进行。 22 | 23 | # 页面置换算法 24 | 25 | 在程序运行过程中,如果要访问的页面不在内存中,就发生缺页中断从而将该页调入内存中。此时如果内存已无空闲空间,系统必须从内存中调出一个页面到磁盘对换区中来腾出空间。 26 | 27 | 页面置换算法和缓存淘汰策略类似,可以将内存看成磁盘的缓存。在缓存系统中,缓存的大小有限,当有新的缓存到达时,需要淘汰一部分已经存在的缓存,这样才有空间存放新的缓存数据。 28 | 29 | 页面置换算法的主要目标是使页面置换频率最低(也可以说缺页率最低)。 30 | 31 | ## 1. 最佳 32 | 33 | > OPT, Optimal replacement algorithm 34 | 35 | 所选择的被换出的页面将是最长时间内不再被访问,通常可以保证获得最低的缺页率。 36 | 37 | 是一种理论上的算法,因为无法知道一个页面多长时间不再被访问。 38 | 39 | 举例:一个系统为某进程分配了三个物理块,并有如下页面引用序列: 40 | 41 | ```html 42 | 7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1Copy to clipboardErrorCopied 43 | ``` 44 | 45 | 开始运行时,先将 7, 0, 1 三个页面装入内存。当进程要访问页面 2 时,产生缺页中断,会将页面 7 换出,因为页面 7 再次被访问的时间最长。 46 | 47 | ## 2. 最近最久未使用 48 | 49 | > LRU, Least Recently Used 50 | 51 | 虽然无法知道将来要使用的页面情况,但是可以知道过去使用页面的情况。LRU 将最近最久未使用的页面换出。 52 | 53 | 为了实现 LRU,需要在内存中维护一个所有页面的链表。当一个页面被访问时,将这个页面移到链表表头。这样就能保证链表表尾的页面是最近最久未访问的。 54 | 55 | 因为每次访问都需要更新链表,因此这种方式实现的 LRU 代价很高。 56 | 57 | ```html 58 | 4,7,0,7,1,0,1,2,1,2,6Copy to clipboardErrorCopied 59 | ``` 60 | 61 | ![img](https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/eb859228-c0f2-4bce-910d-d9f76929352b.png) 62 | 63 | ## 3. 最近未使用 64 | 65 | > NRU, Not Recently Used 66 | 67 | 每个页面都有两个状态位:R 与 M,当页面被访问时设置页面的 R=1,当页面被修改时设置 M=1。其中 R 位会定时被清零。可以将页面分成以下四类: 68 | 69 | - R=0,M=0 70 | - R=0,M=1 71 | - R=1,M=0 72 | - R=1,M=1 73 | 74 | 当发生缺页中断时,NRU 算法随机地从类编号最小的非空类中挑选一个页面将它换出。 75 | 76 | NRU 优先换出已经被修改的脏页面(R=0,M=1),而不是被频繁使用的干净页面(R=1,M=0)。 77 | 78 | ## 4. 先进先出 79 | 80 | > FIFO, First In First Out 81 | 82 | 选择换出的页面是最先进入的页面。 83 | 84 | 该算法会将那些经常被访问的页面也被换出,从而使缺页率升高。 85 | 86 | ## 5. 第二次机会算法 87 | 88 | FIFO 算法可能会把经常使用的页面置换出去,为了避免这一问题,对该算法做一个简单的修改: 89 | 90 | 当页面被访问 (读或写) 时设置该页面的 R 位为 1。需要替换的时候,检查最老页面的 R 位。如果 R 位是 0,那么这个页面既老又没有被使用,可以立刻置换掉;如果是 1,就将 R 位清 0,并把该页面放到链表的尾端,修改它的装入时间使它就像刚装入的一样,然后继续从链表的头部开始搜索。 91 | 92 | ![img](https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/ecf8ad5d-5403-48b9-b6e7-f2e20ffe8fca.png) 93 | 94 | ## 6. 时钟 95 | 96 | > Clock 97 | 98 | 第二次机会算法需要在链表中移动页面,降低了效率。时钟算法使用环形链表将页面连接起来,再使用一个指针指向最老的页面。 99 | 100 | ![img](https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/5f5ef0b6-98ea-497c-a007-f6c55288eab1.png) -------------------------------------------------------------------------------- /01 JavaSe/03 基础概念/notes/值传递和引用传递.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1. 为什么说Java中只有值传递 4 | 5 | https://github.com/hollischuang/toBeTopJavaer/blob/master/basics/java-basic/java-pass-by.md 6 | 7 | # 值传递和引用传递(不是引用类型的传递) 8 | 9 | ![img](https://images2015.cnblogs.com/blog/701142/201706/701142-20170613200934978-745949138.png) 10 | 11 | **值传递**:方法调用时,实际参数把它的值传递给对应的形式参数,方法执行中形式参数值的改变**不影响实际参数的值**。 12 | **引用传递**:也称为传地址。方法调用时,实际参数的引用(地址,而不是参数的值)被传递给方法中相对应的形式参数,在方法执行中,对**形式参数的操作实际上就是对实际参数的操作**,方法执行中形式参数值的改变将会影响实际参数的值。 13 | 14 | 而在JAVA中只有值传递,**基本类型传递的是值的副本,引用类型传递(不是上面说的引用传递)的是引用的副本。**下面来看几个例子: 15 | 16 | 1.在函数中传递基本数据类型 17 | 18 | ```java 19 | public class TestValue { 20 | public static void main(String[] args) { 21 | int i = 3; 22 | int j = 4; 23 | change(i,j); 24 | System.out.println(i); 25 | System.out.println(j); 26 | } 27 | public static void change(int i,int j){ 28 | int temp = i; 29 | i = j; 30 | j = temp; 31 | } 32 | } 33 | ``` 34 | 35 | 结果显示i和j并没有发生交换。因为参数中传递的是**基本数据类型i和j的副本**,在函数中交换的也是副本的值而不是数据本身! 36 | 37 | 2.在函数中传递引用数据类型 38 | 39 | ```java 40 | public class TestValue1 { 41 | public static void change(int[] count){ 42 | count[0] =10; 43 | } 44 | public static void main(String[] args) { 45 | int[] count = {1,2,3,4,5}; 46 | change(count); 47 | System.out.println(count[0]); 48 | } 49 | } 50 | ``` 51 | 52 | 结果count[0]发生了变化,等于10。在方法中传递的是int数组,实际上传递的是其**引用count的副本**,他们都指向数组对象,即对备份所调用的方法更改的是同一个对象。 53 | 54 | 3.重点来看看下面这个例子(转) 55 | 56 | ```java 57 | class Student{ 58 |   private float score; 59 |   public Student(float score) { 60 | this.score = score; 61 | } 62 | public void setScore(float score) { 63 | this.score = score; 64 | } 65 | public float getScore() { 66 | return score; 67 | } 68 | } 69 | public class ParamTest { 70 | public static void main(String[] args) { 71 | Student a = new Student(0); 72 | Student b = new Student(100); 73 | System.out.println("交换前:"); 74 | System.out.println("a的分数:" + a.getScore() + "--- b的分数:" + b.getScore()); 75 | 76 | swap(a, b); 77 | 78 | System.out.println("交换后:"); 79 | System.out.println("a的分数:" + a.getScore() + "--- b的分数:" + b.getScore()); 80 | } 81 | public static void swap(Student x, Student y) { 82 | Student temp = x; 83 | x = y; 84 | y = temp; 85 | } 86 | } 87 | ``` 88 | 89 | 【运行结果】:交换前:a的分数:0.0--- b的分数:100.0 90 | 交换后:a的分数:0.0--- b的分数:100.0 91 | 92 | 可以看出,两者并没有实现交换。这是为何?接下来一步一步看看swap调用的过程: 93 | 94 | 1. 1. 将对象a,b的拷贝(**还是值传递**)分别赋值给x,y,此时a和x指向同一对象,b和y指向同一对象 95 | 2. swap方法体完成x,y的的交换,此时a,b并没有变化 96 | 3. 方法执行完成,x和y不再使用,a依旧指向new Student(0),b指向new Student(100) 97 | 98 | **本质是a和b分别指向了两个不同的堆内存空间。** 99 | 100 | 参考: 101 | 102 | https://www.cnblogs.com/volcan1/p/7003440.html -------------------------------------------------------------------------------- /17 中间件/01 消息队列/notes/消息持久化.md: -------------------------------------------------------------------------------- 1 | 问题:消息被投递到RabbitMQ的内存中, 还没投递到消费者实例之前宕机了, 消息不就丢失了? 2 | 3 | 为了消息传输的可靠性传输,RabbitMQ提供了多种途径的消息持久化保证:**Exchange持久化、Queue持久化及Message的持久化等。**以保证RabbitMQ在重启或Crash等异常情况下,消息不会丢失。RabbitMQ提供了简单的参数配置来实现持久化操作。 这样, RabbitMQ重启时, 会把持久化的Exchange、queue和message从硬盘重新加载出来, 重新投递消息。 4 | 5 | ## **Exchange的持久化** 6 | 7 | 声明交换机时指定持久化参数为`true`即可 8 | 9 | ```java 10 | @Bean 11 | public DirectExchange logUserExchange() { 12 | return new DirectExchange("log.user.exchange", true, false); 13 | } 14 | ``` 15 | 16 | 第二个参数`durable`: 是否持久化, 第三个参数`autoDelete`: 当所有绑定队列都不再使用时, 是否自动删除交换器, true: 删除, false: 不删除 17 | 18 | ## **Queue的持久化** 19 | 20 | 声明队列时指定持久化参数为`true`即可 21 | 22 | ```java 23 | @Bean 24 | public Queue logUserQueue() { 25 | return new Queue("log.user.queue.name", true); 26 | } 27 | ``` 28 | 29 | 第二个参数`durable`, 是否持久化 30 | 31 | ## **Message的持久化** 32 | 33 | 通过配置`deliveryMode`实现的, 生产者投递时, 指定`deliveryMode`为`MessageDeliveryMode.PERSISTENT`即可实现消息的持久化, 投递和消费都需要通过`Message`对象进行交互, 为了不每次都写配置转换的代码, 我们写一个消息帮助类`MessageHelper`: 34 | 35 | ```java 36 | public class MessageHelper { 37 | 38 | public static Message objToMsg(Object obj) { 39 | if (null == obj) { 40 | return null; 41 | } 42 | 43 | Message message = MessageBuilder.withBody(JsonUtil.objToStr(obj).getBytes()).build(); 44 | message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);// 消息持久化 45 | message.getMessageProperties().setContentType(MessageProperties.CONTENT_TYPE_JSON); 46 | 47 | return message; 48 | } 49 | 50 | public static T msgToObj(Message message, Class clazz) { 51 | if (null == message || null == clazz) { 52 | return null; 53 | } 54 | 55 | String str = new String(message.getBody()); 56 | T obj = JsonUtil.strToObj(str, clazz); 57 | 58 | return obj; 59 | } 60 | 61 | } 62 | ``` 63 | 64 | 消息投递时: 65 | 66 | ```java 67 | rabbitTemplate.convertAndSend("log.user.exchange.name", "log.user.routing.key.name", MessageHelper.objToMsg(userLog)); 68 | ``` 69 | 70 | 消息消费时(参考`五、消息接收确认`): 71 | 72 | ``` 73 | UserLog userLog = MessageHelper.msgToObj(message, UserLog.class); 74 | ``` 75 | 76 | 如果不需要消息持久化, 则不需要通过Message进行转换, 可以直接通过字符串或者对象投递和消费 77 | 78 | 作者:wangzaiplus 79 | 80 | 链接:https://www.jianshu.com/p/cc3d2017e7b3 81 | 82 | ## 总结 83 | 84 | RabbitMQ要实现发布订阅持久化,按照消息的传输流程,可以分成三类: 85 | 86 | Exchange 持久化:如果不设定Exchange持久化,那么在RabbitMQ由于某些异常等原因重启之后,Exchange会丢失。Exchange丢失, 会影响发送端发送消息到RabbitMQ。 87 | 88 | Queue持久化:发送端将消息发送至Exchange,Exchange将消息转发至关联的Queue。如果Queue不设置持久化,那么在RabbitMQ重启之后,Queue信息会丢失。导致消息发送至Exchange,但Exchange不知道需要将该消息发送至哪些具体的队列。 89 | 90 | Message持久化:发送端将消息发送至Exchange,Exchange将消息转发至关联的Queue,消息存储于具体的Queue中。如果RabbitMQ重启之后,由于Message未设置持久化,那么消息会在重启之后丢失。 91 | 92 | **为了保证发布订阅的持久化,必须设置Exchange、Queue、Message的持久化,才可以保证消息最终不会丢失。** 93 | 94 | 虽然持久化会造成性能损耗,但为了生产环境的数据一致性,这是我们必须做出的选择。但我们可以通过设置消息过期时间、降低发送消息大小等其他方式来尽可能的降低MQ性能的降低。 95 | 96 | -------------------------------------------------------------------------------- /06 计算机网络/notes/GET和POST.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1.GET和POST的区别 4 | 5 | “1. GET使用URL或Cookie传参,而POST将数据放在BODY中”,这个是因为HTTP协议用法的约定。并非它们的本身区别。 6 | 7 | “2. GET方式提交的数据有长度限制,则POST的数据则可以非常大”,这个是因为它们**使用的操作系统和浏览器设置**的不同引起的区别。也不是GET和POST本身的区别。 8 | 9 | “3. POST比GET安全,因为数据在地址栏上不可见”,**如果没有加密,他们安全级别都是一样的**,随便一个监听器都可以把所有的数据监听到。 10 | 11 | 4.幂等性 GET请求是幂等性的,POST请求不是 12 | 13 | https://www.jianshu.com/p/fd67b576365d 14 | 15 | # HTTP幂等性 16 | 17 | HTTP GET方法**用于获取资源,不应有副作用,所以是幂等的。**比如:GET http://www.bank.com/account/123456,不会改变资源的状态,不论调用一次还是N次都没有副作用。请注意,这里强调的是**一次和N次具有相同的副作用,而不是每次GET的结果相同。**GET http://www.news.com/latest-news这个HTTP请求可能会每次得到不同的结果,但它本身并没有产生任何副作用,因而是满足幂等性的。 18 | 19 | HTTP DELETE方法用于删除资源,有副作用,但它应该满足幂等性。比如:DELETE http://www.forum.com/article/4231,调用一次和N次对系统**产生的副作用是相同的**,即删掉id为4231的帖子;因此,调用者可以多次调用或刷新页面而不必担心引起错误。 20 | 21 | POST所对应的URI并非创建的资源本身,而是资源的接收者。比如:POST http://www.forum.com/articles的语义是在http://www.forum.com/articles下创建一篇帖子,HTTP响应中应包含帖子的创建状态以及帖子的URI。两次相同的POST请求会在服务器端创建两份资源,它们具有不同的URI;所以,POST方法不具备幂等性。而PUT所对应的URI是要创建或更新的资源本身。比如:PUT http://www.forum/articles/4231的语义是创建或更新ID为4231的帖子。对同一URI进行多次PUT的副作用和一次PUT是相同的;因此,PUT方法具有幂等性。 22 | 23 | https://www.cnblogs.com/weidagang2046/archive/2011/06/04/idempotence.html?from=singlemessage&isappinstalled=0 24 | 25 | # GET和POST的区别 26 | 27 | - GET 被强制服务器支持 28 | 29 | - 浏览器对URL的长度有限制,所以GET请求不能代替POST请求发送大量数据 30 | 31 | - GET请求发送数据更小 32 | 33 | - GET请求是**不安全的** 34 | 35 | - GET请求是**幂等的** 36 | 37 | - 幂等的意味着对同一URL的多个请求应该返回同样的结果 38 | 39 | - POST请求不能被缓存 40 | 41 | - POST请求相对GET请求是「安全」的 42 | 43 | - 这里安全的含义仅仅是指是非修改信息 44 | 45 | - GET用于信息获取,而且是安全的和幂等的 46 | 47 | - 所谓安全的意味着该操作用于获取信息而非修改信息。换句话说,GET 请求一般不应产生副作用。就是说,它仅仅是获取资源信息,就像数据库查询一样,不会修改,增加数据,不会影响资源的状态。 48 | 49 | - POST是用于修改服务器上的资源的请求 50 | 51 | - 发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠 52 | 53 | 我们从表面上来看看GET和POST的区别: 54 | 55 | - GET是从服务器上**获取数据**,POST是向服务器**传送数据**。 GET和 POST只是一种传递数据的方式,GET也可以把数据传到服务器,他们的本质都是发送请求和接收结果。只是组织格式和数据量上面有差别,http协议里面有介绍 56 | 57 | - GET是把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一一对应,在URL中可以看到。POST是通过HTTP POST机制,将表单内各个字段与其内容放置在HTML HEADER内一起传送到ACTION属性所指的URL地址。用户看不到这个过程。 因为GET设计成传输小数据,而且最好是不修改服务器的数据,所以浏览器一般都在地址栏里面可以看到,但POST一般都用来传递大数据,或比较隐私的数据,所以在地址栏看不到,能不能看到不是协议规定,是浏览器规定的。 58 | 59 | - 对于GET方式,服务器端用Request.QueryString获取变量的值,对于POST方式,服务器端用Request.Form获取提交的数据。 没明白,怎么获得变量和你的服务器有关,和GET或POST无关,服务器都对这些请求做了封装 60 | 61 | - GET传送的**数据量较小**,不能大于2KB。POST传送的数据量较大,一般被默认为不受限制。但理论上,IIS4中最大量为80KB,IIS5中为100KB。 - POST**基本没有限制**,我想大家都上传过文件,都是用POST方式的。只不过要修改form里面的那个type参数 62 | 63 | - GET**安全性非常低**,POST**安全性较高**。 如果没有加密,他们安全级别都是一样的,随便一个监听器都可以把所有的数据监听到。 64 | https://www.nowcoder.com/discuss/216466?type=2 65 | 66 | | Post一般用于更新或者添加资源信息 | Get一般用于查询操作,而且应该是安全和幂等的 | 67 | | -------------------------------- | ------------------------------------------- | 68 | | Post更加安全 | Get会把请求的信息放到URL的后面 | 69 | | Post传输量一般无大小限制 | Get不能大于2KB | 70 | | Post执行效率低 | Get执行效率略高 | 71 | 72 | # 为什么POST效率低,Get效率高 73 | 74 | - Get将参数拼成URL,放到header消息头里传递 75 | - Post直接以键值对的形式放到消息体中传递。 76 | - 但两者的效率差距很小很小 -------------------------------------------------------------------------------- /11 分布式与微服务/02 分布式/notes/CAP定理.md: -------------------------------------------------------------------------------- 1 | # CAP定理 2 | 3 | CAP原则又称CAP定理,指的是在一个分布式系统中,Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性)这三个基本需求,最多只能同时满足其中的2个。 4 | 5 | ![img](https://user-gold-cdn.xitu.io/2018/6/17/1640df3c315644fc?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) 6 | 7 | ## 1. CAP原则简介 8 | 9 | | 选项 | 描述 | 10 | | :-------------------------------- | :----------------------------------------------------------- | 11 | | Consistency(一致性) | 指数据在多个副本之间能够保持一致的特性(严格的一致性) | 12 | | Availability(可用性) | 指系统提供的服务必须一直处于可用的状态,每次请求都能获取到非错的响应(不保证获取的数据为最新数据) | 13 | | Partition tolerance(分区容错性) | 分布式系统在遇到任何网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务,除非整个网络环境都发生了故障 | 14 | 15 | **什么是分区?** 16 | 17 | > 在分布式系统中,不同的节点分布在不同的子网络中,由于一些特殊的原因,这些子节点之间出现了网络不通的状态,但他们的内部子网络是正常的。从而导致了整个系统的环境被切分成了若干个孤立的区域,这就是分区。 18 | 19 | ## 2. CAP原则论证 20 | 21 | 如图所示,是我们证明CAP的基本场景,网络中有两个节点N1和N2,可以简单的理解N1和N2分别是两台计算机,他们之间网络可以连通,N1中有一个应用程序A,和一个数据库V,N2也有一个应用程序B和一个数据库V。现在,A和B是分布式系统的两个部分,V是分布式系统的数据存储的两个子数据库。 22 | 23 | ![img](https://user-gold-cdn.xitu.io/2018/6/17/1640df3c2d444337?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) 24 | 25 | - 在满足一致性的时候,N1和N2中的数据是一样的,V0=V0。 26 | - 在满足可用性的时候,用户不管是请求N1或者N2,都会得到立即响应。 27 | - 在满足分区容错性的情况下,N1和N2有任何一方宕机,或者网络不通的时候,都不会影响N1和N2彼此之间的正常运作。 28 | 29 | 如图所示,这是分布式系统正常运转的流程,用户向N1机器请求数据更新,程序A更新数据库V0为V1。分布式系统将数据进行同步操作M,将V1同步的N2中V0,使得N2中的数据V0也更新为V1,N2中的数据再响应N2的请求。 30 | 31 | ![img](https://user-gold-cdn.xitu.io/2018/6/17/1640df3c2f36ed7b?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) 32 | 33 | 根据CAP原则定义,系统的一致性、可用性和分区容错性细分如下: 34 | 35 | - 一致性:N1和N2的数据库V之间的数据是否完全一样。 36 | - 可用性:N1和N2的对外部的请求能否做出正常的响应。 37 | - 分区容错性:N1和N2之间的网络是否互通。 38 | 39 | 这是正常运作的场景,也是理想的场景。作为一个分布式系统,它和单机系统的最大区别,就在于网络。现在假设一种极端情况,N1和N2之间的网络断开了,我们要支持这种网络异常。相当于要满足分区容错性,能不能同时满足一致性和可用性呢?还是说要对他们进行取舍? 40 | 41 | ![img](https://user-gold-cdn.xitu.io/2018/6/17/1640df3c34d553cf?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) 42 | 43 | 假设在N1和N2之间网络断开的时候,有用户向N1发送数据更新请求,那N1中的数据V0将被更新为V1。由于网络是断开的,所以分布式系统同步操作M,所以N2中的数据依旧是V0。这个时候,有用户向N2发送数据读取请求,由于数据还没有进行同步,应用程序没办法立即给用户返回最新的数据V1,怎么办呢? 44 | 45 | 这里有两种选择: 46 | 47 | - 第一:牺牲数据一致性,保证可用性。响应旧的数据V0给用户。 48 | - 第二:牺牲可用性,保证数据一致性。阻塞等待,直到网络连接恢复,数据更新操作M完成之后,再给用户响应最新的数据V1。 49 | 50 | 这个过程,证明了要满足分区容错性的分布式系统,只能在一致性和可用性两者中,选择其中一个。 51 | 52 | ## 3. CAP原则权衡 53 | 54 | 通过CAP理论,我们知道无法同时满足一致性、可用性和分区容错性这三个特性,那要舍弃哪个呢? 55 | 56 | ### 3.1. CA without P 57 | 58 | 如果不要求P(不允许分区),则C(强一致性)和A(可用性)是可以保证的。但其实分区不是你想不想的问题,而是始终会存在,因此CA的系统更多的是允许分区后各子系统依然保持CA。 59 | 60 | ### 3.2. CP without A 61 | 62 | 如果不要求A(可用),相当于每个请求都需要在Server之间强一致,而P(分区)会导致同步时间无限延长,如此CP也是可以保证的。很多传统的数据库分布式事务都属于这种模式。 63 | 64 | ### 3.3. AP wihtout C 65 | 66 | 要高可用并允许分区,则需放弃一致性。一旦分区发生,节点之间可能会失去联系,为了高可用,每个节点只能用本地数据提供服务,而这样会导致全局数据的不一致性。现在众多的NoSQL都属于此类。 67 | 68 | # 小结 69 | 70 | 对于多数大型互联网应用的场景,主机众多、部署分散。而且现在的集群规模越来越大,所以节点故障、网络故障是常态。这种应用一般要保证服务可用性达到N个9,即保证P和A,只有舍弃C(退而求其次保证最终一致性)。虽然某些地方会影响客户体验,但没达到造成用户流程的严重程度。 71 | 72 | 对于涉及到钱财这样不能有一丝让步的场景,C必须保证。网络发生故障宁可停止服务,这是保证CA,舍弃P。貌似这几年国内银行业发生了不下10起事故,但影响面不大,报到也不多,广大群众知道的少。还有一种是保证CP,舍弃A,例如网络故障时只读不写。 73 | 74 | 孰优孰劣,没有定论,只能根据场景定夺,适合的才是最好的。 -------------------------------------------------------------------------------- /06 计算机网络/notes/各层协议.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ## 1.FTP在那一层? 4 | 5 | 应用层 6 | 7 | ## 2. IP层和数据链路层什么作用讲一下(字节) 8 | 9 | - **网络层** :为主机提供数据传输服务。而传输层协议是为主机中的进程提供数据传输服务。**网络层把传输层传递下来的报文段或者用户数据报封装成分组。** 10 | - **数据链路层** :网络层针对的还是主机之间的数据传输服务,而主机之间可以有很多链路,链路层协议就是为同一链路的主机提供数据传输服务。数据链路层**把网络层传下来的分组封装成帧。** 11 | 12 | # 一、OSI七层模型 13 | 14 | OSI七层协议模型主要是:应用层(Application)、表示层(Presentation)、会话层(Session)、传输层(Transport)、网络层(Network)、数据链路层(Data Link)、物理层(Physical)。 15 | 16 | “物联网输会示用” 17 | 18 | # 二、五层体系结构 19 | 20 | 五层体系结构包括:应用层、运输层、网络层、数据链路层和物理层。 21 | 22 | 五层协议只是OSI和TCP/IP的综合,实际应用还是TCP/IP的四层结构。为了方便可以把下两层称为网络接口层。 23 | 24 | # 三、对应网络协议 25 | 26 | 应用层:Telnet、**FTP、HTTP**、SNMP、SMTP 27 | 28 | 传输层:TCP、UDP 29 | 30 | 网络层:IP、ARP、RARP、ICMP、IGMP 31 | 32 | 数据链路层:网络接口协议 33 | 34 | 物理层: 35 | 36 | # 四、各层的作用 37 | 38 | ## 物理层(Physical Layer) 39 | 40 | 激活、维持、关闭通信端点之间的机械特性、电气特性、功能特性以及过程特性。**该层为上层协议提供了一个传输数据的可靠的物理媒体。简单的说,物理层确保原始的数据可在各种物理媒体上传输。**物理层记住两个重要的设备名称,中继器(Repeater,也叫放大器)和集线器。 41 | 42 | ## 数据链路层(Data Link Layer) 43 | 44 | 数据链路层在物理层提供的服务的基础上向网络层提供服务,其最基本的服务是将源自网络层来的数据可靠地传输到相邻节点的目标机网络层。为达到这一目的,数据链路必须具备一系列相应的功能,主要有:如何将数据组合成数据块,在数据链路层中称这种数据块为帧(frame),帧是数据链路层的传送单位;如何控制帧在物理信道上的传输,包括如何处理传输差错,如何调节发送速率以使与接收方相匹配;以及在两个网络实体之间提供数据链路通路的建立、维持和释放的管理。数据链路层在不可靠的物理介质上提供可靠的传输。该层的作用包括:**物理地址寻址、数据的成帧、流量控制、数据的检错、重发等**。 45 | 46 | 有关数据链路层的重要知识点: 47 | 48 | - 数据链路层为网络层提供可靠的数据传输; 49 | 50 | - 基本数据单位为帧; 51 | 52 | - 主要的协议:以太网协议; 53 | 54 | - 两个重要设备名称:**网桥和交换机**。 55 | 56 | ## 网络层(Network Layer) 57 | 58 | 网络层的目的是**实现两个端系统之间的数据透明传送**,具体功能包括寻址和路由选择、连接的建立、保持和终止等。它提供的服务使传输层不需要了解网络中的数据传输和交换技术。如果您想用尽量少的词来记住网络层,那就是“路径选择、路由及逻辑寻址”。 59 | 60 | 网络层中涉及众多的协议,其中包括最重要的协议,也是TCP/IP的核心协议——IP协议。IP协议非常简单,仅仅提供不可靠、无连接的传送服务。IP协议的主要功能有:无连接数据报传输、数据报路由选择和差错控制。与IP协议配套使用实现其功能的还有地址解析协议ARP、逆地址解析协议RARP、因特网报文协议ICMP、因特网组管理协议IGMP。具体的协议我们会在接下来的部分进行总结,有关网络层的重点为: 61 | 62 | - 1> 网络层负责对子网间的数据包进行路由选择。此外,网络层还可以实现拥塞控制、网际互连等功能; 63 | 64 | - 2> 基本数据单位为IP数据报; 65 | 66 | - 3> 包含的主要协议: 67 | 68 | - IP协议(Internet Protocol,因特网互联协议); 69 | 70 | - ICMP协议(Internet Control Message Protocol,因特网控制报文协议); 71 | 72 | - ARP协议(Address Resolution Protocol,地址解析协议); 73 | 74 | - RARP协议(Reverse Address Resolution Protocol,逆地址解析协议)。 75 | 76 | - 4> 重要的设备:**路由器**。 77 | 78 | ## 传输层(Transport Layer) 79 | 80 | **第一个端到端,即主机到主机的层次**。传输层负责将上层数据分段并提供端到端的、可靠的或不可靠的传输。此外,传输层还要处理端到端的差错控制和流量控制问题。 81 | 82 | 传输层的任务是根据通信子网的特性,最佳的利用网络资源,为两个端系统的会话层之间,提供建立、维护和取消传输连接的功能,负责端到端的可靠数据传输。在这一层,信息传送的协议数据单元称为段或报文。 83 | 网络层只是根据网络地址将源结点发出的数据包传送到目的结点,而传输层则负责将数据可靠地传送到相应的端口。 84 | 有关网络层的重点: 85 | 86 | - 传输层负责将上层数据分段并提供端到端的、可靠的或不可靠的传输以及端到端的差错控制和流量控制问题; 87 | - 包含的主要协议:TCP协议(Transmission Control Protocol,传输控制协议)、UDP协议(User Datagram Protocol,用户数据报协议); 88 | 89 | ## 会话层 90 | 91 |   会话层管理**主机之间的会话进程**,即负责建立、管理、终止进程之间的会话。会话层还利用在数据中插入校验点来实现数据的同步。 92 | 93 | ## 表示层 94 | 95 |   表示层**对上层数据或信息进行变换**以保证一个主机应用层信息可以被另一个主机的应用程序理解。表示层的数据转换包括**数据的加密、压缩、格式转换等**。 96 | 97 | ## 应用层 98 | 99 |   为操作系统或网络应用程序提供访问网络服务的接口。 100 | 101 |   会话层、表示层和应用层重点: 102 | 103 |   1> 数据传输基本单位为报文; 104 | 105 |   2> 包含的主要协议:FTP(文件传送协议)、Telnet(远程登录协议)、DNS(域名解析协议)、SMTP(邮件传送协议),POP3协议(邮局协议),HTTP协议(Hyper Text Transfer Protocol)。 -------------------------------------------------------------------------------- /12 HR常问/HR常问.md: -------------------------------------------------------------------------------- 1 | # HR常问问题 2 | 3 | 作者:我不想做题了 4 | https://www.nowcoder.com/discuss/249452?type=2&order=0&pos=7&page=1来源:牛客网 5 | 6 | **1.自我介绍** 7 | 8 | **ans:**本环节无需过多赘述,三段论:1.专业背景、研究方向。2.有说服力的项目/竞赛(几句话带过,意在让面试官知道你的优势,同时也可以引导面试官对你擅长的项目进行提问)。3.说明投此岗位原因。 9 | 10 | **2.为什么来我们公司?** 11 | 12 | **ans:**主要两点: 1.理念一致; 2.平台的优越性。 13 | 14 | **3.如何看待公司文化/怎么看待公司?** 15 | 16 | **ans:**要有自己独到的理解,不要随便百度百科。以华为为例子:不要动不动就狼性文化,面试官想听的是奋斗者文化。 17 | 18 | **4.你觉得你凭什么能进入我们公司?** 19 | 20 | **ans:**应聘者最好站在招聘单位的角度来回答。*例如说明自己满足公司哪些招聘要求,能为公司做出哪些贡献,最后说明自己的学习能力等。 21 | 22 | **5.如何看待加班?** 23 | 24 | **ans:**经典问题。不要不经大脑就说自己愿意加班。面试官有时候(尤其是综合面),不仅仅是要看你的态度,更要看你的思维方式。因此问道效率,可以提一嘴自己的工作效率,表明自己会准时完成任务的决心等等,最后再表明一下态度。 25 | 26 | **6.你的职业规划?** 27 | 28 | **ans:**三段论:1.说明自己感兴趣的岗位方向、阐明自己的优势所在,表明会认真对待这个岗位。2.近期规划,尽量不要高谈阔论说几年内当主管这种话。这段应表明你五年内会虚心继续学习,继续提升自己(让面试官看出你是个能踏踏实实的稳定分子)。3.长期的规划,表明自己目光长远一些的想法,当然,如果没有想法,可以说“我会根据环境的变化,工作内容的变化,以及我自身能力的变化,不断进行调整的”等等。 29 | 30 | **7.最近在看些书?** 31 | 32 | **ans:**尽量不要瞎编,因为面试官一般都会继续追问下去。 33 | 34 | **8.你觉得你的优点是什么?** 35 | 36 | **ans:**实话实说就行。但不要把某些明显的优点说成是缺点,会让面试官反感,例如我这个人太注重完美,太有责任心之类的。 37 | 38 | **9.说说你的缺点?** 39 | 40 | **ans:**可以圆滑回答。先稍微提一嘴自己的优点,中间加一些小缺点,然后再把问题回到优点上。面试官喜欢聪明的求职者。(切勿说自己性格有问题,一般是说自己经验不足等等) 41 | 42 | **10.除技术之外的兴趣爱好?** 43 | 44 | **ans:**自由发挥即可。 45 | 46 | **11.人生道路上受过的挫折?有什么收获?** 47 | 48 | **ans:**宜谈工作上的挫折。切勿谈什么失恋啊什么的,面试官的深层意思是知道你的抗压能力和恢复能力以及自我反省能力。 49 | 50 | **12.项目中碰到的最困难的事情是什么?怎么解决的?** 51 | 52 | **ans:**结合自身情况说就行了。 53 | 54 | **13.平时如何给自己解压的?** 55 | 56 | **ans:**结合自身情况说明即可。 57 | 58 | **14.你最崇拜谁?** 59 | 60 | **ans:**不必无脑舔。最好是业内的牛X人物,不过就算不是业内的问题也不大。只要别说我的偶像是CXK就行哈哈哈哈哈哈。 61 | 62 | **15.你的座右铭?** 63 | 64 | **ans:**自由发挥。 65 | 66 | **16.对于这项工作,你有哪些可预见的困难?** 67 | 68 | **ans:**尽量提前调研好这个工作所要具备的能力,以及岗位主要业务,对症下药。 69 | 70 | **17.如果我录用你,你将怎样开展工作?** 71 | 72 | **ans:**如果清楚进去之后的主要业务,可就着业务展开来讲。如果实在不清楚业务,问题不大,可以说“在正式进入公司之前我会提前学习以后岗位上需要用到的相关知识,在正式进入公司之后我最开始会先听领导的指示,然后结合相关情况进行更加具体的安排”等等。 73 | 74 | **18.与上级意见不一致,你将怎么办?** 75 | 76 | **ans:**跟面试官表达你会先给上级一些必要的解释和提醒,然后服从上级的安排。(切勿越级汇报,因为很多企业里很忌讳越级汇报)。 77 | 78 | **19.你能为我们做什么?** 79 | 80 | **ans:**这个可以站在招聘者的角度来想,结合所投的岗位,加以阐释。还可以暗示面试官,自己会尽快适应环境,融入团队等信息。 81 | 82 | **20.你是应届毕业生,缺乏经验,如何胜任这份工作?** 83 | 84 | **ans:**首先要大方承认应届生经验不足,但是可以跟面试官表明自己有较强的责任心、学习能力。暗示自己比较勤奋,让面试官相信你能胜任。 85 | 86 | **21.你希望与什么样的上级共事?** 87 | 88 | **ans:**这个问题是大坑,千万别信口就说自己对上级的要求。面试官问这个问题是想知道应聘者到底有没有“自知之明”。所以,比较合适的回答,可以说:“作为刚步入社会新人,我应该多要求自己尽快熟悉环境、适应环境,而不应该对环境提出什么要求,只要能发挥我的专长就可以了。” 89 | 90 | **22.是否有女/男朋友,目前在哪?** 91 | 92 | **ans:**这个问题隐层的深意是,如果你有对象,而且工作后可能是异地恋的话,你极有可能会跳槽,是个不稳定的因素,极可能被毙。所以,多斟酌。 93 | 94 | **23.从事过哪些社会活动/校园活动,为什么要参加,从中学到了什么?** 95 | 96 | **ans:**这个因人而异,自己可以好好思考一下。最好给出的理由是积极的,出于公益、学习、历练的目的。 97 | 98 | **24.如何看待BAT?** 99 | 100 | **ans:**.......你懂的...... 101 | 102 | **25.简单介绍你的家庭情况?** 103 | 104 | **ans:**自由发挥。面试官问这个问题,是想从侧面了解你的性格,比如从小家庭和睦,就会觉得你性格因该很不错。如果从小家庭就不和睦,面试官就会认为你性格上可能会存在问题。还有另一方面就是,面试官想知道你是不是娇生惯养,不适合奋斗拼搏。诸位看官多斟酌。 105 | 106 | **26.还有什么问题要问吗?** 107 | 108 | **ans:**这里有个必杀技,**放第一条**。剩下的自由发挥23333。**1.诚恳询问面试官,如果自己有幸能加入公司,需要提前学习哪些内容(这个会让面试官觉得这个学生很用心,很上进,很好学,pass概率飙升...**)。2.具体了解一下,面试岗位未来的发展状况是什么样的;3.进入公司以后,公司的培训体系将如何安排等等,自由发挥。 --------------------------------------------------------------------------------