├── 计算机网络 ├── P2P.md ├── IP.md ├── 无线传感器网络.md ├── Socket.md ├── 物联网.md ├── UDP.md ├── IPv6.md ├── 无线网.md └── 路由算法.md ├── zookeeper └── zookeeper.md ├── 调优 ├── .DS_Store ├── HeapAnalyzer.md └── Arthas.md ├── node-red └── node-red.md ├── 面试 ├── 国双科技.md ├── 京东数科.md ├── 平安金融壹账通.md ├── 猫眼.md ├── 网易考拉.md ├── 百度.md ├── 华为面经.md ├── 思必驰.md ├── ebay.md ├── 深信服.md ├── 拼多多.md ├── 神舟信息.md ├── 今日头条.md ├── 投资银行.md ├── 阿里.md ├── 小米.md ├── 爱奇艺.md ├── 腾讯.md └── 阿里菜鸟.md ├── nginx └── nginx.md ├── Java ├── JNI.md ├── 红黑树.md ├── java数据类型.md ├── Maven.md ├── 内部类.md ├── 抽象类和接口.md ├── JUC包.md ├── java动态代理.md ├── jsp.md ├── Java并发编程[MT].md ├── String.md ├── 泛型.md ├── java性能调优.md ├── Java反射.md ├── Java异常.md └── java基础.md ├── 数据库 ├── Hibernate.md ├── MongoDB.md ├── MySQL索引原理和优化.md ├── couchbase.md ├── mybatis.md └── MySql.md ├── spring ├── springboot │ ├── springboot优化.md │ └── springboot面试.md ├── springmvc.md ├── Servlet.md └── springcloud.md ├── 前端 ├── vue.md ├── vue教程.md ├── js.md └── jsp.md ├── spark ├── spark.md ├── kafka.md └── 算法.md ├── git └── git.md ├── ssh └── ssh.md ├── README.md ├── RPC └── RPC.md ├── hadoop ├── HDFS.md ├── Hive.md ├── MapReduce.md ├── YARN.md ├── HBase.md └── hadoop.md ├── MQ ├── RabbitMQ基础.md ├── Kafka.md ├── MQ.md └── RocketMQ.md ├── Kafka └── Kafka.md ├── JVM ├── ClassLoader.md └── Java垃圾回收.md ├── 数据结构 └── 排序 │ └── 排序.md ├── elasticsearch └── elasticsearch.md ├── linux └── linux.md ├── Docker └── docker基础.md └── 设计模式 └── 设计模式.md /计算机网络/P2P.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /zookeeper/zookeeper.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /调优/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sotowang/bigdata/HEAD/调优/.DS_Store -------------------------------------------------------------------------------- /node-red/node-red.md: -------------------------------------------------------------------------------- 1 | # 教程 2 | 3 | > Node Red里的消息传递都是json 4 | 5 | * inject<时间戳> -------------------------------------------------------------------------------- /面试/国双科技.md: -------------------------------------------------------------------------------- 1 | # 类和类之间多对一,一对多和多对多关系怎么维护 2 | 3 | # 堆排序 4 | 5 | 快速排序 6 | 7 | 海量数据处理 8 | 9 | -------------------------------------------------------------------------------- /nginx/nginx.md: -------------------------------------------------------------------------------- 1 | # nginx常用命令 2 | 3 | * 启动 4 | 5 | > nginx 6 | 7 | * 修改配置后重新加载生效 8 | 9 | > nginx -s reload 10 | 11 | * 重新打开日志文件 12 | 13 | > nginx -s reopen 14 | 15 | * 关闭nginx 16 | 17 | > nginx -s stop 18 | 19 | * 完整有序地停止nginx 20 | 21 | > nginx -s quit -------------------------------------------------------------------------------- /面试/京东数科.md: -------------------------------------------------------------------------------- 1 | * 说一下 Java 里面的数据结构 2 | 3 | - 说一下 ArrayList 和 LinkedList 的区别 4 | - 说一下 ArrayList 的底层 5 | - ArrayList 是线程安全的吗? 怎么解决 ArrayList 线程不安全的问题 6 | - 在 Java 中如何实现一个线程? 7 | - 设计模式了解吗? 8 | - 说一下什么是设计模式 9 | - 说一下单例模式及其应用场景 10 | - 了解哪些数据库? 11 | - 说一下 Redis 12 | - Redis 是数据库吗? 13 | - 如何优化查询性能? 14 | - 如果是全表扫描,如何优化? 15 | - 一般看哪些博客或者逛哪些网站? -------------------------------------------------------------------------------- /Java/JNI.md: -------------------------------------------------------------------------------- 1 | # 什么是JNI 2 | 3 | * Java原生接口,允许Java调用C/C++代码,也允许在C/C++中调用Java的代码 4 | 5 | * JNI是一个介于Java层和Native层的接口,而Native层是C/C++层 6 | 7 | # 为什么使用JNI? 8 | 9 | * 可重复使用现成的,具有相同功能的C/C++代码 10 | * C/C++偏底层,使用C/C++更加高效,使得Java能访问操作系统的一些特性 11 | 12 | # 如何使用JNI 13 | 14 | * Java定义一个类,在该类中声明一个native方法 15 | * 使用C/C++来实现这个方法的方法体 16 | * 生成动态库文件 17 | * 使用生成的动态库文件 -------------------------------------------------------------------------------- /面试/平安金融壹账通.md: -------------------------------------------------------------------------------- 1 | # 平安金融壹账通 2 | 3 | ## 一面 4 | 5 | * ConcurrentHashMap与HashTable的联系与区别 6 | * Kafka工作方式 7 | * JVM中堆 8 | * Spark项目 9 | * Hive 10 | * Hbase 11 | 12 | ## 二面 13 | 14 | * yarn工作原理 15 | 16 | * spark何时给container分配资源,如何分配的 17 | 18 | * 讲一下Spark项目 19 | 20 | * 使用Maven还是Gradle 21 | 22 | * Maven生命周期 23 | 24 | * 常使用的Maven命令 25 | 26 | * yarn和Mesos的区别 27 | 28 | -------------------------------------------------------------------------------- /面试/猫眼.md: -------------------------------------------------------------------------------- 1 | # jvm虚拟机 2 | 3 | # 线程 4 | 5 | # 锁 6 | 7 | # hashmap底层实现 8 | 9 | # 写一个单例模式程序 10 | 11 | # 一个快排程序 12 | 13 | 14 | 15 | # hive窗口函数 16 | 17 | 18 | 19 | # hbase问了结构,原理还有存储。 20 | 21 | * HBase Table组成 22 | 23 | Table = RowKey + Family+Column+Timestamp+value 24 | 25 | * 数据存储模式 26 | 27 | (Table,Rowkey,Family。Column,Timestamp)-> Value 28 | 29 | * 数据存储流程 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /面试/网易考拉.md: -------------------------------------------------------------------------------- 1 | # 网易考拉(offer) 2 | 3 | ## 一面: 4 | 5 | ``` 6 | 1、sql题:学生成绩表,把每科最高分前三名统计出来 7 | 2、算法题:二维数组中的查找 8 | 3、kafka如何保证高吞吐的,了不了解kafka零拷贝,具体怎么做的 9 | 4、sql有几种join,map join了解过没 10 | 5、hbase中row key该怎么设计 11 | 6、hdfs文件上传流程,hdfs的容错机制 12 | 7、怎么解决hive数据倾斜问题 13 | ``` 14 | 15 | ## 二面(全程写写写): 16 | 17 | ``` 18 | 1、算法题:二维矩阵相乘 19 | 2、算法题:链表中环的入口 20 | 3、写一下mysql binlog的数据格式,怎么进行数据清洗的 21 | 4、写一个正则表达式进行手机号匹配 22 | 5、讲一下数据仓库层级的划分,每层的作用 23 | ``` 24 | 25 | -------------------------------------------------------------------------------- /数据库/Hibernate.md: -------------------------------------------------------------------------------- 1 | # Hibernate中默认采用延迟加载的情况 2 | 3 | * 当调用session上的load()加载一个实体时,会采用延迟加载。 4 | * 当session加载某个实体时,会对这个实体中的集合属性值采用延迟加载 5 | * 当session加载某个实体时,会对这个实体所有单端关联的另一个实体对象采用延迟加载。 6 | 7 | 8 | 9 | # Hibernate 中 get()和load() 的区别 10 | 11 | * get()采用立即加载方式,而load()采用 延迟加载 12 | * get()方法执行的时候,会立即向数据库发出查询语句, 而load()方法返回的是一个代理(此代理中只有一个id属性,只有等真正使用该对象属性的时候,才会发出 sql语句 13 | * 如果数据库中没有对应的记录,get()方法返回的是null.而load()方法出现异常ObjectNotFoundException 14 | 15 | -------------------------------------------------------------------------------- /计算机网络/IP.md: -------------------------------------------------------------------------------- 1 | # IP地址分类 2 | 3 | * 地址格式 4 | 5 | * IP地址 = 网络地址+ 子网地址+主机地址 6 | 7 | * 地址类型 8 | 9 | * A类 10 | 11 | * 由1字节网络地址和3字节主机地址组成 12 | * `1.0.0.0` - `126.255.255.255` 13 | 14 | * B类 15 | 16 | * 由2个字节网络地址和2个字节主机地址 17 | * `128.0.0.0` -`191.255.255.255` 18 | 19 | * C类 20 | 21 | * 由3个字节网络地址和1个字节主机地址 22 | * `192.0.0.0`-`223.255.255.255` 23 | 24 | * D类 25 | 26 | * 多用于多点广播 27 | 28 | * E类 29 | 30 | * 保留地址 31 | 32 | -------------------------------------------------------------------------------- /spring/springboot/springboot优化.md: -------------------------------------------------------------------------------- 1 | # 性能优化 2 | 3 | * @SpringBootApplication注解 4 | * 会自动获取配置信息 5 | * 触发自动配置(auto-configuration)和组件扫描(component scanning) 6 | * 与使用@configuration,@EnableAutoConfiguration和@ComponentScan三个注解的作用是一样的 7 | * [组件自动扫描问题](http://blog.oneapm.com/apm-tech/385.html) 8 | * 会导致项目启动时间变长。当启动一个大的应用程序,或将做大量的集成测试启动应用程序时,影响会特别明显。 9 | * 会加载一些不需要的多余的实例(beans) 10 | * 会增加 CPU 消耗。 11 | * 解决方案 12 | * 移除 @SpringBootApplication 和 @ComponentScan 两个注解来禁用组件自动扫描 13 | * 在需要的 bean 上进行显式配置 14 | 15 | -------------------------------------------------------------------------------- /面试/百度.md: -------------------------------------------------------------------------------- 1 | # 2020-08-03 2 | 3 | AOP原理 4 | 5 | * JDK和CGLIB区别 6 | * Spring默认使用哪个 7 | 8 | Stack和LinkedList区别 9 | 10 | ArrayList和LinkedList的区别 11 | 12 | 锁的种类 13 | 14 | ReentryLock原理 15 | 16 | * 锁被释放后如何被唤醒 17 | 18 | `String a = "a" + "b"`生成几个对象 19 | 20 | String StringBuilder StringBuffer的区别 21 | 22 | 线程的状态 23 | 24 | * 阻塞和等待的区别 25 | * 如何get到第一个执行完线程的结果 26 | 27 | 线程池参数 28 | 29 | 红黑树了解,哪些地方用了红黑树 30 | 31 | ConcurrentHashMap的应用场景 32 | 33 | HashMap头部死循环的操作 34 | 35 | LinkedHashMap大小是一定的么 36 | 37 | SQL中between id的效率 -------------------------------------------------------------------------------- /面试/华为面经.md: -------------------------------------------------------------------------------- 1 | # 公共开发部 2 | 3 | ## 一面 4 | 5 | 1. 什么是多态 6 | 2. Java中这什么是单继承 7 | 3. String name = “a”+“b”+“c”生成了几个对象 8 | 4. Integer缓存 9 | 5. 类加载原理 10 | 6. 讲一下SpringBoot 11 | 7. 为何转专业,成绩如何,印象深刻的课程 12 | 8. TCP三次握手 13 | 9. 冒泡排序 14 | 10. 小朋友糖果分配(leetcode原题) 15 | 11. 如何将10棵树排成5列 16 | 12. 有什么要问的 17 | 18 | ## 二面 19 | 20 | 1. 为何转专业 21 | 2. AOP原理 22 | 3. Spring Boot启动 23 | 4. 实习项目介绍 24 | 5. 为什么从爱奇艺离职 25 | 6. 个人优缺点,有烦恼的事情 26 | 7. 有什么爱好 27 | 8. 你很紧张么,当你紧张时会怎么办 28 | 9. 智力题:一个村庄100个人,男人说真话,女人说假话.一个人来到村庄问村子里有多少个人,得到了1,2,...,100,问村子里有多少男人 29 | 10. 家是哪里的,以后有什么打算 -------------------------------------------------------------------------------- /面试/思必驰.md: -------------------------------------------------------------------------------- 1 | # 进程 2 | 3 | # 线程 4 | 5 | # 面向对象 6 | 7 | # 多态 8 | 9 | # 分布式 10 | 11 | # 多线程 12 | 13 | # 堆排序 14 | 15 | # 拓扑排序 16 | 17 | # 并发 18 | 19 | # synchronized 20 | 21 | # reentrantlock 22 | 23 | # threadlocal 24 | 25 | # jmm 26 | 27 | # 实际项目中遇到的并发访问问题 28 | 29 | # TCP/IP协议 30 | 31 | # 三次握手 32 | 33 | # 四次挥手 34 | 35 | # JVM调优 36 | 37 | # JVM调优原则 38 | 39 | # xml转换成嵌套map的代码 40 | 41 | # 如何保证分布式事务 42 | 43 | # zk跟eurake的区别 44 | 45 | # zab的选举过程 46 | 47 | # mysql分表策略 48 | 49 | # 日志怎么处理 50 | 51 | # 什么情况下用索引 52 | 53 | # 如何查看索引 -------------------------------------------------------------------------------- /前端/vue.md: -------------------------------------------------------------------------------- 1 | # MVVM框架 2 | 3 | * 概念 4 | * view(视图) 5 | * 负责显示 6 | * ViewModel(逻辑控制) 7 | * 将view和Model双向同步 8 | * Model(数据) 9 | * 用纯JavaScript对象表示 10 | 11 | # Vue数据绑定 12 | 13 | * Observer 14 | * 对数据对象所有属性进行监听,若有变动则拿到最新值并通知订阅者 15 | * Compile 16 | * 对每个元素的指令扫描,解析,根据指令模板替换数据,绑定相应的更新函数 17 | * Watcher 18 | * 连接Observer和Complie桥梁,订阅并收到每个属性变动的通知 ,执行绑定的相应回调函数,从而更新视图 19 | 20 | # Vue核心思想 21 | 22 | * 数据驱动 23 | * 组件化 24 | * 扩展HTML元素,封装可重用代码 25 | * 组件设计原则 26 | * 页面上每个独立的可视/可交互区域视为一个组件 27 | * 每个组件对应一个工程目录,组件所需要的各种资源在这个目录下就近维护 28 | * 页面不过是组件的容器,组件可以 嵌套自由组合形成完整的页面 -------------------------------------------------------------------------------- /spark/spark.md: -------------------------------------------------------------------------------- 1 | # Spark程序的调度过程 2 | 3 | * 用户用spark-submit提交程序 4 | * spark-submit在同一节点(客户端模式)或集群(集群模式)启动驱动并调用用户main() 5 | * 6 | 7 | 8 | 9 | * 驱动进程联系集群管理器,根据提供的配置参数来请求启动执行进程JVM所需的资源。 10 | * 集群管理器在工作机节点上启动执行进程JVM 11 | * 驱动进程扫描用户应用程序。根据程序中的RDD动作和变换,Spark会创建一个运算图。 12 | * 当调用一个动作(如collect)时,图会被提交到一个有向无环图(DAG)调度程序。DAG调度程序将运算图划分成一些阶段。 13 | * 一个阶段由基于输入数据分区的任务组成。DAG调度程序会通过流水线把运算符连一起,从而优化运算图。例如,很多映射(map)运算符可以调度到一个阶段中。为种优化对Spark的性能是很关键的。DAG调度程序的最终结果是一组阶段。 14 | * 这些阶段会被传递到任务调度程序。任务调度程序通过集群管理器(Spark Srandalone/Yarn/Mesos)启动任务。任务调度器并不知道阶段之间的依赖性。 15 | * 任务在执行进程上运行,从而计算和保存结果。 16 | * 如果驱动进程的main退出,或者它调用了SparkContext.stop(),它就会终止执行进程并从集群管理器释放资源。 -------------------------------------------------------------------------------- /Java/红黑树.md: -------------------------------------------------------------------------------- 1 | # 红黑树 2 | 3 | * 什么是红黑树 4 | * 本质为二叉查找树+标记(颜色),具有一定规则,该规则使树平衡,插入删除查找最坏时间复杂度O(logn) 5 | * 不是真正的AVL树,但性能好于AVL树 6 | * 应用 7 | * HashMap,TreeMap,TreeSet 8 | * 概念 9 | * 黑色高度 10 | * 根结节至叶结点黑色结点个数 11 | 12 | - 特性 13 | - 根,叶(Null)节点为黑 14 | - 红结点子结点为黑 15 | - 任一节点至其子树的叶节点,黑结点数相同 16 | 17 | ![](https://img-blog.csdn.net/20161123195416588) 18 | 19 | 20 | 21 | # [红黑树(RB-tree)比AVL树的优势](https://blog.csdn.net/mmshixing/article/details/51692892) 22 | 23 | * 首先红黑树是**不符合AVL树的平衡条件**的,即每个节点的左子树和右子树的高度最多差1的二叉查找树。但是提出了为节点增加颜色,红黑是用非严格的平衡来换取增删节点时候旋转次数的降低,**任何不平衡都会在三次旋转之内解决**,而AVL是严格平衡树,因此在增加或者删除节点的时候,根据不同情况,旋转的次数比红黑树要多。所以红黑树的插入效率更高 24 | 25 | -------------------------------------------------------------------------------- /git/git.md: -------------------------------------------------------------------------------- 1 | # GitHub常用操作 2 | 3 | * 查询关键词 4 | 5 | * `keyword in:name,readme,description` 6 | 7 | * 范围查询 8 | * 按点赞数`springboot starts:>=5000` 9 | * 按forks数`springboot forks:>=500` 10 | * 组合使用`springboot forks:100..200 stars:80..100` 11 | * 加增搜索 12 | * `awesome redis` 13 | * 关键代码高亮 14 | * `URL+#L13-L23`13-23行高亮显示 15 | * 项目内搜索 16 | * `t` 17 | 18 | # rebase(变基) 19 | 20 | > 在当前分支外另一点上重新应用当前分支的提交历史 21 | 22 | ![img](https://segmentfault.com/img/remote/1460000005937418) 23 | 24 | > 在对feature分支rebase,等价于创建了新的提交,并且老的提交也没有被销毁,只是不再被访问或使用 25 | 26 | * rebase会改变server端的commit历史 27 | 28 | 29 | 30 | # reset 31 | 32 | > git reset --hard HEAD^^^^^^ 33 | 34 | -------------------------------------------------------------------------------- /数据库/MongoDB.md: -------------------------------------------------------------------------------- 1 | # MongoDB分片(Sharding)技术 2 | 3 | * 分片目的 4 | * 分片是MongoDB将大型集合分割至不同服务器(或一个集群)上所采用的方法。 5 | * 与MySQL分区方案相比,MongoDB能几乎自动完成分片 6 | * 垂直扩展 7 | * 增加更多的CPU和存储资源来扩展容量 8 | * 水平扩展 9 | * 将数据集分布在多个服务器上,即分片 10 | 11 | * 分片思想 12 | 13 | * 减少了每个分片存储的数据 14 | 15 | * 插入数据时,只需要访问数据所在分片 16 | 17 | ![img](https://images2017.cnblogs.com/blog/1190037/201801/1190037-20180106150209471-1233466151.png) 18 | 19 | * 分片优势 20 | 21 | * 对集群进行抽象,让集群不可见 22 | * 自带mongos路由进程,将客户端请求准确路由到一个或一组服务器上,同时将收到的响应拼起来发到客户端 23 | * 保证集群总是可读写 24 | * 将MongoDB的分片和复制功能结合使用,确保数据在分片到多台服务器时,每份数据进行了备份,一台服务器坏掉后,其他库可接替 25 | * 使集群易扩展 26 | * 当系统需要更多的空间和资源时,可按需扩充容量 -------------------------------------------------------------------------------- /计算机网络/无线传感器网络.md: -------------------------------------------------------------------------------- 1 | 无线传感器网络(Wireless Sensor Networks, WSN)是一种分布式传感网络,它的末梢是可以感知和检查外部世界的传感器。WSN中的传感器通过无线方式通信,因此网络设置灵活,设备位置可以随时更改,还可以跟互联网进行有线或无线方式的连接。通过无线通信方式形成的一个[多跳](https://baike.baidu.com/item/%E5%A4%9A%E8%B7%B3/5932947)[自组织网络](https://baike.baidu.com/item/%E8%87%AA%E7%BB%84%E7%BB%87%E7%BD%91%E7%BB%9C)。 2 | 3 | WSN的发展得益于[微机电系统](https://baike.baidu.com/item/%E5%BE%AE%E6%9C%BA%E7%94%B5%E7%B3%BB%E7%BB%9F)(Micro-Electro-Mechanism System, MEMS)、[片上系统](https://baike.baidu.com/item/%E7%89%87%E4%B8%8A%E7%B3%BB%E7%BB%9F)(System on Chip, SoC)、无线通信和低功耗[嵌入式技术](https://baike.baidu.com/item/%E5%B5%8C%E5%85%A5%E5%BC%8F%E6%8A%80%E6%9C%AF/11025546)的飞速发展。 4 | 5 | WSN广泛应用于军事、智能交通、环境监控、医疗卫生等多个领域。 -------------------------------------------------------------------------------- /调优/HeapAnalyzer.md: -------------------------------------------------------------------------------- 1 | # [分析 Java heap dump工具之IBM HeapAnalyzer](https://www.cnblogs.com/winner-0715/p/8632755.html) 2 | 3 | 我们使用下面的代码来生成堆转储快照文件 4 | 5 | ![img](https://images2018.cnblogs.com/blog/824490/201803/824490-20180323223352968-847891786.png) 6 | 7 | JVM参数为: 8 | 9 | ``` 10 | -verbose:gc -Xms10M -Xmx10M -XX:+HeapDumpOnOutOfMemoryError 11 | ``` 12 | 13 | 生成文件名为java_pid5192.hprof的堆转储文件。 14 | 15 | 运行命令打开HeapAnalyzer 16 | 17 | ``` 18 | java –Xmx[heapsize] –jar ha456.jar 19 | ``` 20 | 21 | 打开堆转储文件java_pid5192.hprof 22 | 23 | ![img](https://i.loli.net/2020/07/24/AloUydpfeHwsL3a.png) 24 | 25 | 可以看到,堆内存的96.64%的空间被Test$OOMObject占用。 26 | 27 | 占用内存的对象找到了,就到代码中分析就可以了。 -------------------------------------------------------------------------------- /spring/springmvc.md: -------------------------------------------------------------------------------- 1 | # 什么是Spring MVC 2 | 3 | * 基于MVC架构的用来简化web应用程序开发的框架。是Spring的一个模块 4 | * 和Struts2一样属于表现层的框架,通过把Model,View,Controller分离,把较为复杂的web应用分成逻辑清晰的几部分,方便开发人员配合 5 | 6 | # [Spring MVC的原理](https://mp.weixin.qq.com/s/wcK2qsZxKDJTLIGqEIyaNg) 7 | 8 | * 用户发出请求,请求到达前端控制器(**DispatcherServlet**) 9 | * 前端控制器根据用户的url请求处理器映射器(**HandlerMapping**)查找匹配该url的handler,并返回一个执行链 10 | * 前端控制器再请求处理器适配器(**HandlerAdapter**)调用相应的handler进行处理并返回给前端控制器一个modelAndView 11 | * 前端控制器再请求视图解析器(**ViewReslover**)对返回的逻辑视图进行解析 12 | * 最后前端控制器将返回的视图进行渲染并把数据装入到request域,返回给用户。 13 | 14 | ![img](https://uploadfiles.nowcoder.com/images/20171010/163192_1507646670364_7216367DD4FDC0CC274F999B0D00CFE5) 15 | 16 | # SpringMVC加载流程 17 | 18 | * Servlet加载(监听器之后执行)Servlet的init() 19 | * 加载配置文件 20 | * 从ServletContext拿到Spring初始化springmvc相关对象 21 | * 加入servletContext -------------------------------------------------------------------------------- /ssh/ssh.md: -------------------------------------------------------------------------------- 1 | # SSH运行过程 2 | 3 | * Client向Server发起SSH连接请求 4 | * Server向Client发起版本协商 5 | * 服务器比较客户端发来的版本号,决定是否能同客户端工作,能则进入下一阶段,不能则断开链接 6 | * 算法协商阶段 7 | * Client和Server向对方发送一个自己支持的公钥算法列表,加密算法列表,消息验证码算法列表,压缩算法列表,确定使用的算法 8 | * 然后使用DH交换算法,利用主机密钥对等参数,生成会话密钥和会话ID 9 | * 认证阶段,从此以后所有通信均加密 10 | * 用户密码 11 | * 客户端获取用户密码后使用服务器公钥进行加密并发给服务器,服务器用自己私钥解密 12 | * 公钥认证(免密码登陆) 13 | * 将客户端公钥手动复制到服务器的authorized_keys文件,相当于服务器获取了客户端公钥 14 | * Server用Client公钥加密一个256位随机字符串,客户端接收后使用私钥解密,将字符串和会话id合并,对其用MD5散列函数并把散列值返回给服务器,服务器进行相同散列处理,若客户端与该值匹配,则谁成功,允许登陆 15 | * 交互阶段 16 | 17 | # 中间人攻击 18 | 19 | * 如果首次连接没有中间人,则之后的连接不用担心中间人,因中间人与服务端公钥相同的可能性几乎可以忽略 20 | 21 | # RSA算法原理 22 | 23 | * 对称加密算法 24 | * 甲方必须把加密规则告诉给乙方,否则无法解密 25 | * 保存和传递密钥成为最大问题 26 | * 非对称加密算法(RSA) 27 | * 非对称加密算法(DH算法) 28 | * 乙方生成公钥和私钥,公钥公开,私钥保密 29 | * 甲方获取乙方的公钥,然后用它信息加密 30 | * 乙方得到加密信息。用私钥解密 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | * [bigdata面试](https://github.com/sotowang/bigdata/blob/master/%E9%9D%A2%E8%AF%95/bigdata%E9%9D%A2%E8%AF%95.md) 3 | * [JVM](https://github.com/sotowang/bigdata/tree/master/JVM) 4 | * [spring](https://github.com/sotowang/bigdata/blob/master/spring/spring.md) 5 | * 书目 6 | * 《**Java编程思想**》 7 | 8 | * **《Mybatis从入门到精通》** 9 | 10 | * **《深入分析Java Web技术内幕》** 11 | 12 | * 《Java设计模式》 13 | 14 | * **《Java EE 框架技术》** 15 | 16 | * 《自顶向下方法》 17 | 18 | * 《Spark机器学习进阶实战》 19 | 20 | * **《Java并发编程从入门到精通》** 21 | 22 | * 《**Hadoop权威指南**》 23 | 24 | * **《Hadoop大数据挖掘从入门到进阶实战》** 25 | 26 | * 《**Spark与Hadoop大数据分析**》 27 | 28 | * **《Java网络编程案例教程》** 29 | 30 | * **《剑指offer》** 31 | 32 | * **《Java程序员面试宝典》** 33 | 34 | * 《**Spring Data JPA从入门到精通**》 35 | 36 | * 《**Spring Boot 企业级应用开发实战**》 37 | 38 | * 《RocketMQ实战与原理解析》 39 | 40 | ​ 41 | 42 | -------------------------------------------------------------------------------- /Java/java数据类型.md: -------------------------------------------------------------------------------- 1 | # 装箱和拆箱 2 | 3 | * new Integer(2) == 2? 4 | * true 5 | * 自动拆箱了 6 | * new Integer(2 ) == new Integer(2)? 7 | * false 8 | * 比较的是两个箱子 9 | * Integer.valueOf(2) == Integer.valueOf(2)? 10 | * 不确定 11 | * 在-128-127之间,系统会缓存,此时相等 12 | * 在其他数字,系统随机缓存,此时不确定 13 | * Integer.valueOf(2).intValue() == 2? 14 | * true 15 | * intValue()拆箱 16 | * new Integer(2).equals(new Integer(2))? 17 | * true 18 | * equals 判断值是否相等 19 | * 自动装箱 20 | * 调用 `Integer.valueOf()` 21 | * 缓冲池大小`-128-127`,上界可通过`-XX:AutoBoxCacheMax=`调整 22 | 23 | # 基本数据类型 24 | 25 | | | | | 26 | | ---- | ------- | ----- | 27 | | 1 | int | 4字节 | 28 | | 2 | char | 2字节 | 29 | | 3 | byte | 1字节 | 30 | | 4 | short | 2字节 | 31 | | 5 | long | 8字节 | 32 | | 6 | double | 8字节 | 33 | | 7 | float | 4字节 | 34 | | 8 | boolean | 1字节 | 35 | 36 | -------------------------------------------------------------------------------- /面试/ebay.md: -------------------------------------------------------------------------------- 1 | # synchronized的作用 2 | 3 | # object的方法有哪些 4 | 5 | * getClass() 6 | * hashCode() 7 | * equals() 8 | * toString() 9 | * notify() 10 | * notifyAll() 11 | * waIt() 12 | 13 | # HashMap与HashTable的区别 14 | 15 | # 数据库中group by的用法 16 | 17 | # List种类 18 | 19 | LinkedList,ArrayList,Vector 20 | 21 | # List公共api 22 | 23 | 添加方法是:.add(e);   24 | 25 | 获取方法是:.get(index);   26 | 27 | 删除方法是:.remove(index); 按照索引删除; 28 | 29 | 按照元素内容删除; 30 | 31 | .remove(Object o); 32 | 33 | 方法:.contains(Object o); 返回true或者false 34 | 35 | # Map中key类型 36 | 37 | # 不使用锁,达到锁的功能 38 | 39 | # String a = "hello world" a在哪,“hello world”在哪? 40 | 41 | # Integer 和 int 区别 42 | 43 | # 工厂模式 44 | 45 | # 单例模式 46 | 47 | # Junit单元测试 48 | 49 | # Array和ArrayList的区别 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /面试/深信服.md: -------------------------------------------------------------------------------- 1 | https://www.nowcoder.com/discuss/172229 2 | 3 | # 一面 4 | 5 | 3算法,跳台阶,斐波那契数列和dp方式都说了。 6 | 7 | ## tcp的四次挥手中的time_wait状态何时出现,有什么意义。 8 | 9 | 1. 防止最后ack丢失,丢失后会重传 10 | 2. 在time-wait时间内关闭所有连接,防止新连接使用旧连接传输 11 | 12 | ## 操作系统的fork进程返回什么 13 | 14 | fork系统调用的作用是复制一个进程。当一个进程调用它,完成后就出现两个几乎一模一样的进程,我们也由此得到了一个新进程。 15 | 16 | 1. 在父进程中,fork返回新创建子进程的进程ID; 17 | 2. 在子进程中,fork返回0; 18 | 3. 如果出现错误,fork返回一个负值; 19 | 20 | # 二面 21 | 22 | ## hadoop的组件 23 | 24 | HDFS ,Hive,HBase,YARN,Zookeeper,Kafka,Spark,Mahout,Flume 25 | 26 | ## hdfs的写入过程 27 | 28 | ## 讲一下如何设计一个高并发的秒杀系统 29 | 30 | ## 讲一下线程和协程 31 | 32 | 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。线程间通信主要通过共享内存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据。 33 | 34 | **协程是一种用户态的轻量级线程,**协程的调度完全由用户控制。**协程拥有自己的寄存器上下文和栈**。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则**基本没有内核切换的开销**,可以不加锁的访问全局变量,所以上下文的切换非常快。 35 | 36 | ## 协程和线程适用场景的区别。 37 | 38 | 1) 一个线程可以多个协程,一个进程也可以单独拥有多个协程,这样python中则能使用多核CPU。 39 | 40 | 2) 线程进程都是同步机制,而协程则是异步 41 | 42 | 3) 协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态 -------------------------------------------------------------------------------- /Java/Maven.md: -------------------------------------------------------------------------------- 1 | # Maven生命周期 2 | 3 | Maven 的内部有三个构建生命周期,分别是 clean, default, site 4 | 5 | 1、**clean 周期**:主要用于清理上一次构建产生的文件,可以理解为删除target目录 6 | 7 | 2、**默认周期**, 8 | 主要阶段包含: 9 | 10 | process-resources 默认处理src/test/resources/下的文件,将其输出到测试的classpath目录中, 11 | compile 编译src/main/java下的java文件,产生对应的class, 12 | process-test-resources 默认处理src/test/resources/下的文件,将其输出到测试的classpath目录中, 13 | test-compile 编译src/test/java下的java文件,产生对应的class, 14 | test 运行测试用例, 15 | package 打包构件,即生成对应的jar, war等, 16 | install将构件部署到本地仓库, 17 | deploy 部署构件到远程仓库 18 | 3、**site周期** 19 | 20 | 主要阶段包含 21 | 22 | site 产生项目的站点文档 23 | site-deploy 将项目的站点文档部署到服务器 24 | 25 | 26 | 27 | # Maven常见的依赖范围有哪些? 28 | 29 | **compile**:编译依赖,默认的依赖方式,在编译(编译项目和编译测试用例),运行测试用例,运行(项目实际运行)三个阶段都有效,典型地有spring-core等jar。 30 | 31 | **test**:测试依赖,只在编译测试用例和运行测试用例有效,典型地有JUnit。 32 | 33 | **provided**:对于编译和测试有效,不会打包进发布包中,典型的例子为servlet-api,一般的web工程运行时都使用容器的servlet-api。 34 | 35 | **runtime**:只在运行测试用例和实际运行时有效,典型地是jdbc驱动jar包。 36 | 37 | **system**: 不从maven仓库获取该jar,而是通过systemPath指定该jar的路径。 38 | 39 | **import**: 用于一个dependencyManagement对另一个dependencyManagement的继承。 40 | 41 | -------------------------------------------------------------------------------- /RPC/RPC.md: -------------------------------------------------------------------------------- 1 | # [RPC架构组件](https://juejin.im/post/5cd28d1ee51d453aa44ad6d8) 2 | 3 | 一个基本的RPC架构里面应该至少包含以下4个组件: 4 | 5 | 1. **客户端** (Client):服务调用方(服务消费者) 6 | 2. **客户端存根** (Client Stub):存放服务端地址信息,将客户端的请求参数数据信息打包成网络消息,再通过网络传输发送给服务端 7 | 3. **服务端存根** (Server Stub):接收客户端发送过来的请求消息并进行解包,然后再调用本地服务进行处理 8 | 4. **服务端** (Server):服务的真正提供者 9 | 10 | # [RPC使用了哪些关键技术](https://juejin.im/post/5cd28d1ee51d453aa44ad6d8) 11 | 12 | **1、动态代理** 13 | 14 | * 生成Client Stub(客户端存根)和Server Stub(服务端存根)的时候需要用到Java动态代理技术,可以使用JDK提供的原生的动态代理机制,也可以使用开源的:CGLib代理,Javassist字节码生成技术。 15 | 16 | **2、序列化和反序列化** 17 | 18 | * 在网络中,所有的数据都将会被转化为字节进行传送,所以为了能够使参数对象在网络中进行传输,需要对这些参数进行序列化和反序列化操作。 19 | * 目前比较高效的开源序列化框架:如Kryo、FastJson和Protobuf等。 20 | 21 | **3、NIO通信** 22 | 23 | * 出于并发性能的考虑,传统的阻塞式 IO 显然不太合适,因此我们需要异步的 IO,即 NIO。Java 提供了 NIO 的解决方案,Java 7 也提供了更优秀的 NIO.2 支持。可以选择Netty或者MINA来解决NIO数据传输的问题。 24 | 25 | **4、服务注册中心** 26 | 27 | * 可选:Redis、Zookeeper、Consul 、Etcd。一般使用ZooKeeper提供服务注册与发现功能,解决单点故障以及分布式部署的问题(注册中心)。 28 | 29 | # 原理架构图 30 | 31 | ![image](https://user-gold-cdn.xitu.io/2019/5/8/16a967782dea01f1?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) 32 | 33 | ![image](https://user-gold-cdn.xitu.io/2019/5/8/16a96777705bab4b?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) -------------------------------------------------------------------------------- /计算机网络/Socket.md: -------------------------------------------------------------------------------- 1 | # [socket协议位于哪一层](https://bbs.csdn.net/topics/340056488) 2 | 3 | * SOCKET 应该算不上是个协议,应该是应用层与传输层间的一个抽象层,是个编程接口。 4 | 5 | 6 | 7 | # Socket相关面试题 8 | 9 | 编写一个网络应用程序,有客户端与服务器端,客户端向服务器发送一个字符串,服务器收到该字符串后将其打印到命令行上,然后向客户端返回该字符串的长度,最后,客户端输出服务器端返回的该字符串的长度,分别用TCP和UDP两种方式去实现. 10 | 11 | * TCP 12 | 13 | * TCPServer.java 14 | 15 | ```java 16 | public class TCPServer{ 17 | ServerSocket ss = new ServerSocket(65000); 18 | while(true){ 19 | Socket socket = ss.accept(); 20 | //业务逻辑类 21 | new LengthCalculator(socket).start(); 22 | } 23 | } 24 | ``` 25 | 26 | * TCPClient.java 27 | 28 | ```java 29 | public class TCPClient{ 30 | public static void main(String[] args) throws Exception{ 31 | Socket socket = new Socket("127.0.0.1",65000); 32 | OutputStream os = socket.getOutputStrean(); 33 | InputStream is = socket.getInputStream(); 34 | os.write(new String("hello world").getBytes()); 35 | int ch = 0; 36 | byte[] buff = new byte[1024]; 37 | ch = is.read(buff); 38 | String content = new String(buff,0,ch); 39 | System.out.println(content); 40 | 41 | is.close(); 42 | os.close(); 43 | socket.close(); 44 | } 45 | } 46 | ``` 47 | 48 | -------------------------------------------------------------------------------- /hadoop/HDFS.md: -------------------------------------------------------------------------------- 1 | # HDFS的存储机制 2 | 3 | ## 写详细步骤 4 | 5 | 1. 客户端向NameNode发出写文件请求。 6 | 7 | 2. 检查是否已存在文件、检查权限。若通过检查,直接先将操作写入EditLog,并返回输出流对象。 8 | 9 | (注:WAL,write ahead log**,先写Log,再写内存**,因为EditLog记录的是最新的HDFS客户端执行所有的写操作。如果后续真实写操作失败了,由于在真实写操作之前,操作就被写入EditLog中了,故EditLog中仍会有记录,我们不用担心后续client读不到相应的数据块,因为在第5步中DataNode收到块后会有一返回确认信息,若没写成功,发送端没收到确认信息,会一直重试,直到成功) 10 | 11 | 3. **client端按128MB的块切分文件**。 12 | 13 | 4. client将NameNode返回的分配的可写的DataNode列表和Data数据一同发送给最近的第一个DataNode节点,此后client端和NameNode分配的多个DataNode构成pipeline管道,client端向输出流对象中写数据。client每向第一个DataNode写入一个packet,这个packet便会直接在pipeline里传给第二个、第三个…DataNode。 14 | 15 | **客户端给DataNode发数据实际上是以Packet的形式发送的,Packet一般只有64KB左右** 16 | 17 | (注:并不是写好一个块或一整个文件后才向后分发) 18 | 19 | 5. 每个DataNode写完一个块后,会返回确认信息。 20 | 21 | (注:并不是每写完一个packet后就返回确认信息,个人觉得因为packet中的每个chunk都携带校验信息,没必要每写一个就汇报一下,这样效率太慢。正确的做法是写完一个block块后,对校验信息进行汇总分析,就能得出是否有块写错的情况发生) 22 | 23 | 6. 写完数据,关闭输输出流。 24 | 25 | 7. 发送完成信号给NameNode。 26 | 27 | (注:发送完成信号的时机取决于集群是**强一致性还是最终一致性**,强一致性则需要所有DataNode写完后才向NameNode汇报。最终一致性则其中任意一个DataNode写完后就能单独向NameNode汇报,HDFS一般情况下都是强调强一致性) 28 | 29 | ## 读详细步骤 30 | 31 | 1)客户端向namenode请求下载文件,namenode通过查询元数据,找到文件块所在的datanode地址。 32 | 33 | 2)挑选一台datanode(就近原则,然后随机)服务器,请求读取数据。 34 | 35 | 3)datanode开始传输数据给客户端(从磁盘里面读取数据放入流,**以packet为单位来做校验**)。 36 | 37 | 4)客户端以packet为单位接收,**先在本地缓存,然后写入目标文件**。 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /计算机网络/物联网.md: -------------------------------------------------------------------------------- 1 | # 射频识别技术(RFID) 2 | 3 | [射频识别](https://baike.baidu.com/item/%E5%B0%84%E9%A2%91%E8%AF%86%E5%88%AB/2510798),[RFID](https://baike.baidu.com/item/RFID)(Radio Frequency Identification)技术,又称[无线射频识别](https://baike.baidu.com/item/%E6%97%A0%E7%BA%BF%E5%B0%84%E9%A2%91%E8%AF%86%E5%88%AB/12219243),是一种[通信技术](https://baike.baidu.com/item/%E9%80%9A%E4%BF%A1%E6%8A%80%E6%9C%AF/2865397),可通过无线电讯号识别特定目标并读写相关数据,而无需识别系统与特定目标之间建立机械或光学接触。 4 | 5 | 射频的话,一般是微波,1-100GHz,适用于短距离识别通信。 6 | 7 | [RFID读写器](https://baike.baidu.com/item/RFID%E8%AF%BB%E5%86%99%E5%99%A8)也分移动式的和固定式的,目前RFID技术应用很广,如:图书馆,[门禁系统](https://baike.baidu.com/item/%E9%97%A8%E7%A6%81%E7%B3%BB%E7%BB%9F/2959386),食品安全溯源等。 8 | 9 | 10 | 11 | ## 组成部分 12 | 13 | [应答器](https://baike.baidu.com/item/%E5%BA%94%E7%AD%94%E5%99%A8):由天线,耦合元件及芯片组成,一般来说都是用[标签](https://baike.baidu.com/item/%E6%A0%87%E7%AD%BE)作为应答器,每个标签具有唯一的电子编码,附着在物体上标识目标对象。 14 | 15 | [阅读器](https://baike.baidu.com/item/%E9%98%85%E8%AF%BB%E5%99%A8):由天线,[耦合](https://baike.baidu.com/item/%E8%80%A6%E5%90%88)元件,芯片组成,读取(有时还可以写入)标签信息的设备,可设计为手持式rfid读写器或固定式读写器。 16 | 17 | 应用软件系统 :是应用层软件,主要是把收集的数据进一步处理,并为人们所使用。 18 | 19 | 20 | 21 | # 射频技术 22 | 23 | [射频识别系统](https://baike.baidu.com/item/%E5%B0%84%E9%A2%91%E8%AF%86%E5%88%AB%E7%B3%BB%E7%BB%9F)最重要的优点是非接触识别,它能穿透雪、雾、冰、[涂料](https://baike.baidu.com/item/%E6%B6%82%E6%96%99)、[尘垢](https://baike.baidu.com/item/%E5%B0%98%E5%9E%A2)和条形码无法使用的恶劣环境阅读标签,并且阅读速度极快,大多数情况下不到100毫秒。有源式射频识别系统的速写能力也是重要的优点。可用于流程跟踪和维修跟踪等交互式业务。 24 | 25 | -------------------------------------------------------------------------------- /hadoop/Hive.md: -------------------------------------------------------------------------------- 1 | # 什么是Hive 2 | 3 | * 构建在Hadoop上的数据仓库,殷SQL查询转为一系列Hadoop集群中运行的MapReduce作业,是MapReduce更高层次的抽象 4 | * Hive将数据组织为表,使HDFS上的数据有了结构,元数据即表的模式,都存储在名为metastore的数据库中 5 | 6 | # 什么是UDF 7 | 8 | * Hive提供的函数功能满足不了业务的需要,需要写UDF辅助完成 9 | * UDF是执行过程是地Hive转换成mapreduce程序后,执行Java方法,类似于像Mapreduce执行过程中加入一个插件,方便扩展 10 | * UDF只能实现一进一出的操作,若实现多进一出,则需要UDAF 11 | 12 | # UDF类型 13 | 14 | * UDF 15 | * 操作单个数据行,产生单个数据行 16 | * UDAF 17 | * 操作多个数据行,产生一个数据行 18 | * UDTF 19 | * 操作一个数据行,产生多个数据行一个表作为输出 20 | 21 | # 如何构建UDF 22 | 23 | * 步骤 24 | * 继承UDF或者UDAF或者UDTF,实现特定方法 25 | * 将写好的类打包为jar 26 | * 进扩到Hive外壳环境.利用add jar xxx.jar 注册jar文件 27 | * 将该类起一个别名 28 | * `create temporary function mylength as 'com.xxx.StringLength';`这里注意UDF只是为这个Hive会话临时定义 29 | * 在select 中使用mylength() 30 | * 注意 31 | * UDF 32 | * UDF必须继承`org.apache.hadoop.hive.ql.exec.UDF` 33 | * 必须包含有`evaluate()`方法,但该方法并不存在于UDF中,`evaluate`的参数由用户自定义,使用时Hive会调用UDF的`evaluate()`方法 34 | * UDAF 35 | * UDAF必须继承`org.apache.hadoop.hive.ql.exec.UDAF` 36 | * 必须包含至少一个实现了`org.apache.hadoop.hive.ql.exec`的静态类,如常见的实现了`UDAFEvaluator` 37 | * 一个计算函数须实现5个方法 38 | * `Init()`负责初始化计算函数并重设其内部状态,一般是重设内部字段,一般在静态类中定义一个内部字段存放最终结果 39 | * `iterate()`每一次对一个新值进行聚集计算时会调用该方法,计算函数会根据聚焦计算结果更新内部状态,当输入值合法或正确计算了则返回true 40 | * `terminatePartia()`Hive需要部分聚集结果的时候会调用该方法,必须返回一个封装了聚集计算当前状态的对象 41 | * `merge()`Hive进行合并一个部分聚集和另一个部分聚集的时候会调用该方法 42 | * `terminate()`Hive最终聚集结果的时候会调用该方法,计算函数需要把状态作为一个值返回给用户 43 | * 部分聚集结果的数据类型和最终结果的数据类型可以不同 -------------------------------------------------------------------------------- /Java/内部类.md: -------------------------------------------------------------------------------- 1 | # 内部类 2 | 3 | ![img](https://uploadfiles.nowcoder.com/images/20170830/5248791_1504089837512_39944D8036786CB820F9D9873950ABA5) 4 | 5 | * 静态内部类 6 | * 只能访问外部类静态成员 7 | * 外部类访问内部类非静态成员:实例化内部类即可 8 | * 静态内部类本身可以访问外部的静态资源,包括静态私有资源。但是不能访问非静态资源,可以不依赖外部类实例而实例化。 9 | * 成员内部类 10 | * 成员内部类本身可以访问外部的所有资源,但是自身不能定义静态资源,因为其实例化本身就还依赖着外部类。 11 | * 局部内部类 12 | * 局部内部类就像一个局部方法,不能被访问修饰符修饰,也不能被static修饰。 13 | * 局部内部类只能访问所在代码块或者方法中被定义为final的局部变量。 14 | 15 | * 匿名内部类 16 | 17 | * 没有类名的内部类,不能使用class,extends和implements,没有构造方法。 18 | * 多用于GUI中的事件处理。 19 | * 不能定义静态资源 20 | * 只能创建一个匿名内部类实例。 21 | * 一个匿名内部类一定是在new后面的,这个匿名类必须继承一个父类或者实现一个接口。 22 | * 匿名内部类是局部内部类的特殊形式,所以局部内部类的所有限制对匿名内部类也有效。 23 | 24 | # 静态内部类与普通内部类 25 | 26 | * 普通内部类对象隐含地保存了一个引用, 指向创建它的外部类对象 27 | * 静态内部类可以有静态成员,而非静态内部类不能有静态成员 28 | * 非静态内部类的非静态成员可以访问外部类的非静态变量 29 | * 静态内部类的非静态成员可以访问外部类的静态变量,而不可言问外部类的非静态变量 30 | * 普通内部类不可以声明静态成员,一般的普通内部类可以随意访问外部类的成员变量与方法,即使是private型 31 | 32 | # Java为什么用内部类 33 | 34 | - 提供一种方法把只在一个地方用的类逻辑分组 35 | - 增强封装(可以理解一种类似“多重继承”) 36 | - 容易维护 37 | 38 | 为什么说内部类可以实现类似的多重继承,Java是不需要class多重继承的, 想要实现类似多重继承的效果可以用内部类,比如Class B 已经继承了Class C 就没有办法继承Class A, 但是把B设计成A的内部类,就可以访问A的内部变量和方法了,就像是也继承了A。 39 | 40 | # 匿名类 41 | 42 | * 没有名字的内部类就是匿名内部类,在声明的时候实例化,用来重写一个类的方法,或者实现一个接口 43 | * 不能定义任何静态成员,方法 44 | * 方法不能是抽象的,必须实现接口或抽象父类的所有抽象方法 45 | * 访问的外部类成员变量或成员方法必须用static修饰 46 | * 不能定义构造器 47 | 48 | ![img](https://uploadfiles.nowcoder.com/images/20180701/3807435_1530425536125_D49BCBCCF82CF58C566E12F1E3130070) 49 | 50 | 51 | 52 | 53 | 54 | ![img](https://uploadfiles.nowcoder.com/images/20190109/242025553_1547012774538_BA9669C5826A238ACEC0BD86755FA5DB) 55 | 56 | -------------------------------------------------------------------------------- /计算机网络/UDP.md: -------------------------------------------------------------------------------- 1 | # UDP的特点 2 | 3 | * 面向非连接 4 | * 不维护连接状态,支持同时向多个客户端传输相同信息 5 | * 数据包报头只有8个字节,额外开销较小 6 | * 吞吐量只受限于数据生成速率,传输速率以及以及机器性能 7 | * 尽最大努力交付,不保证可靠交付,不需要维持复杂的链接状态表 8 | * 面向报文,不对应用程序提交的报文信息进行拆分或者合并 9 | 10 | # TCP和UDP的区别 11 | 12 | | | TCP | UDP | 13 | | ---------- | -------------- | ---------- | 14 | | 是否连接 | 面向连接 | 面向非连接 | 15 | | 传输可靠性 | 可靠的 | 不可靠的 | 16 | | 应用场合 | 传输大量的数据 | 少量数据 | 17 | | 速度 | 慢 | 快 | 18 | 19 | - TCP协议在传送数据段的时候要给段标号;UDP协议不 20 | - TCP协议可靠;UDP协议不可靠 21 | - TCP协议是面向连接;UDP协议采用无连接 22 | - TCP协议负载较高,采用虚电路;UDP采用无连接 23 | - TCP协议的发送方要确认接收方是否收到数据段(3次握手协议) 24 | - TCP协议采用窗口技术和流控制 25 | - TCP基于字节流,太大的数据会被切分,UDP基于数据报 26 | 27 | # [UDP实现可靠性传输](https://www.jianshu.com/p/6c73a4585eba) 28 | 29 | * UDP不属于连接协议,具有资源消耗少,处理速度快的优点,所以通常音频,视频和普通数据在传送时,使用UDP较多,因为即使丢失少量的包,也不会对接受结果产生较大的影响。 30 | 31 | * 传输层无法保证数据的可靠传输,只能通过应用层来实现了。实现的方式可以参照tcp可靠性传输的方式,只是实现不在传输层,实现转移到了应用层。 32 | 33 | 最简单的方式是在应用层模仿传输层TCP的可靠性传输。下面不考虑拥塞处理,可靠UDP的简单设计。 34 | 35 | - 1、添加seq/ack机制,确保数据发送到对端 36 | - 2、添加发送和接收缓冲区,主要是用户超时重传。 37 | - 3、添加超时重传机制。 38 | 39 | 详细说明:送端发送数据时,生成一个随机seq=x,然后每一片按照数据大小分配seq。数据到达接收端后接收端放入缓存,并发送一个ack=x的包,表示对方已经收到了数据。发送端收到了ack包后,删除缓冲区对应的数据。时间到后,定时任务检查是否需要重传数据。 40 | 41 | 目前有如下开源程序利用udp实现了可靠的数据传输。分别为***RUDP、RTP、UDT\***。 42 | 43 | # [UDP的头部](https://blog.csdn.net/dangzhangjing97/article/details/80991965) 44 | 45 | ![这里写图片描述](https://i.loli.net/2020/08/18/SHyDfXUhJ98zY6E.png) 46 | 47 | `source port`: 源端口号,占16位,2个字节 48 | `dest port`: 目的端口号,占16位,2个字节 49 | `length`: 此字段标记了整个数据报(UDP的首部+UDP数据)的最大长度 50 | `checksum`: 检验和,此字段用处是用来检查收到地数据的对错的 51 | **ps:如果校验和出错,就会直接丢弃** 52 | `Application data`: 数据部分(如果有的话) -------------------------------------------------------------------------------- /前端/vue教程.md: -------------------------------------------------------------------------------- 1 | # vue新建项目 2 | 3 | > vue init webpack sell 4 | > 5 | > cd sell 6 | > 7 | > npm install 8 | > 9 | > npm run dev 10 | 11 | Vue项目结构 12 | 13 | ![结构.png](https://i.loli.net/2019/09/28/w3BTioVp8zqtv9L.png) 14 | 15 | 16 | 17 | * components 18 | * 写前端页面具体内容 19 | * router 20 | * 配置页面跟url的对应 21 | 22 | # Vue组件重要选项 23 | 24 | ```vue 25 | new Vue({ 26 | data:{ 27 | a:1, 28 | b:[] 29 | }, 30 | methods:{ 31 | dosomething:function(){ 32 | this.a ++ 33 | } 34 | }, 35 | watch:{ 36 | 'a':function(val,oldVal){ 37 | console.log(val,oldVal) 38 | } 39 | } 40 | }) 41 | ``` 42 | 43 | * `data` 44 | * `methods` 45 | * `watch`监听 46 | 47 | # 模板指令 48 | 49 | * 数据渲染 50 | * `v-text` 51 | * `{{}}` 简写 52 | * `v-html` 53 | 54 | * 控制模块隐藏 55 | * v-if 56 | * v-show 57 | 58 | * 循环列表 59 | 60 | * `v-for` 61 | 62 | ```vue 63 | 68 | data:{ 69 | items:[ 70 | { 71 | label:'apple' 72 | }, 73 | { 74 | label:'banana' 75 | } 76 | ] 77 | }, 78 | ``` 79 | 80 | * 事件绑定 81 | 82 | * `v-on` 83 | 84 | ```vue 85 | 86 | //简写 87 | 88 | 89 | methods:{ 90 | doThis:function(someThinf){} 91 | } 92 | ``` 93 | 94 | * 属性绑定 95 | 96 | * `v-bind` 97 | 98 | ```vue 99 | 100 |
101 | 102 |
103 | ``` 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /数据库/MySQL索引原理和优化.md: -------------------------------------------------------------------------------- 1 | # MySQL索引原理和优化 2 | 3 | ## MySQL索引原理 4 | 5 | ### 哈希索引 6 | 7 | * 利用Hash存储的话需要将所有的数据文件添加到内存,比较耗费内存空间 8 | * 如果所有的查询都是等值查询,hash确实很快,实际应用中范围查找数据的场景多 9 | 10 | ### InnoDB引擎 11 | 12 | * 索引组织表 13 | 14 | ### MYISAM引擎 15 | 16 | * 堆表 17 | 18 | ### 主键索引和二级索引 19 | 20 | * 回表包含二级索引(SecondaryIndex)的查询,回到主键索引(PK)进行数据查找的过程叫做回表 21 | 22 | * 每一次索引上的查询都对应数据库的一次IO操作 23 | 24 | * 主键会出现在所有聚簇索引上和二级索引上所以尺寸要小数据也(Page)的大小是固定的,每个字段占用的空间越少,每个page就可以存放尽量多的行 25 | 26 | * 写入时,主键最好有序,否则容易造成页面分裂,引起额外的IO操作 27 | 28 | * 推荐使用没有业务意义的自增主键,举例: 29 | 30 | > id INT(11) **unsigned** NOT NULL AUTO_INCREMENT COMMENT '主键id’ 31 | > 32 | > unsigined将会过滤掉负值 33 | 34 | ## 索引优化原则 35 | 36 | * 查询 `SELECT * FROM demo WHERE number = 10` 37 | * UK_number(number上有唯一索引) 38 | * 二级索引上搜索到number=10,去主键上取数据,返回 39 | * IX_number(number上有非唯一索引) 40 | * 二级索引上搜索到number=10,去主键上取数据,返回,判断下一个值是不是10 41 | * 更新 `INSERT INTO demo(number) SELECT 10` 42 | * UK_number(number上有唯一索引) 43 | * 数据在内存里,判断唯一性,写入值 44 | * 数据不在内存里,读入内存,判断唯一性,写入值,结束 45 | * IX_number(number上有非唯一索引) 46 | * 数据在内存里,写入值 47 | * 数据不在内存时需,读入内存,写入值,写入change buffer,结束 48 | 49 | * 二级索引中,普通索引和唯一索引怎么选? 50 | 51 | * 归档业务 52 | 53 | * 非唯一索引优于唯一索引 54 | * 写完就查的业务 55 | * 唯一索引优于非唯一索引 56 | * 大多数情况下,一个简单的SQL只能用到一个索引 57 | * 业务逻辑中用到的SQL尽可能通过索引的方式访问数据,是否用到索引,可以通过EXPLAIN判断 58 | * 特殊意义的字段,建议加上索引 59 | * create_time:记录创建时间 60 | * update_time:记录修改时间 61 | * 慢查询中的SQL,先判断是否可以通过添加索引或者调整索引结构解决 62 | * 如何建立合适的索引? 63 | * 区分度较高的列 64 | * 尽量使用字段长度小的列作为索引 65 | * 造作NOT NULL的列 66 | * 含有空值的列很难进行查询优化 67 | * 尽量扩展索引,不要新建索引 68 | * 防止隐式转换 69 | * 如何用好索引 70 | * 禁止在where条件的列名上使用函数 71 | * 禁止使用存储过程、存储函数、触发器和视图 72 | * 尽量不要在数据库里做运算 73 | * 尽量不要做%前缀模糊查询,如like '%name' 74 | * 不要使用大领衔量的limit分页 75 | * update/delete尽量根据主键进行操作 76 | 77 | ## 索引优化案例 78 | 79 | -------------------------------------------------------------------------------- /MQ/RabbitMQ基础.md: -------------------------------------------------------------------------------- 1 | # 消息服务中间件 2 | 3 | * 大多应用中可通过消息服务中间件来提升系统异步通信,扩展解耦能力 4 | * 消息服务中两个重要概念 5 | * 消息代理(message broked) 6 | * 目的地(destination) 7 | * 点对点式 8 | * 消息发送者发送消息,消息代理将其放入一个队列中,消息接收者从队列中获取消息内容,消息读取后被移出队列 9 | * 消息只有唯一的发送者和接受者,但并不是说只有一个接收者 10 | * 发布订阅式 11 | * 发送者发送消息到主题,多个接收者(订阅者)监听(订阅为个主题),在消息到达时同时收到消息 12 | * JMS(Java Message Service) JAVA消息服务 13 | * 基于JVM消息代理的规范 14 | * ActiveMQ,HornetMQ是JMS实现 15 | * AMQP(Advanced Message Queuing Protocol) 16 | * 高级消息队列协议,消息代理规范 17 | * RabbitMQ 18 | 19 | 20 | 21 | # RabbitMQ 22 | 23 | * Message 24 | * 由Properties和Body组成 25 | * Properties对消息修饰(消息优先级,延迟等) 26 | * Body 消息体内容 27 | * Publisher 28 | * Exchange 29 | 30 | * direct(单播) 31 | * 根据路由键将消息派发给指定队列 32 | * fanout(广播) 33 | * 每个消息都会分到所有绑定队列上去 34 | * fanout类型转发消息是最快的 35 | * 像子网传播,每台子网内的主机都获得了一份复制消息 36 | * topic(有选择广播) 37 | * 通过模式匹配分配消息的路由键属性 38 | * #匹配0个或多个单词,*匹配一个单词,单词之间用点隔开 39 | * headers 40 | * Queue 41 | * 保存消息并转发给消费者 42 | * Binding 43 | * Exchange和Queue之间的虚拟连接 44 | * Binding中可以包含Routingkey 45 | * Connection 46 | * 连接,应用程序与Broker连接 47 | * Channel 信道 48 | * 进行消息读写的通道 49 | * 客户端可以建立多个Channel 50 | * Consumer 51 | * Virtual Host 52 | * 虚拟主机,用于逻辑隔离,最上层消息路由 53 | * 一个Virtual Host里面可以有若干个Exchange和Queue 54 | * 同一个Virtual Host里面不能有相同名称的Exchange或Queue 55 | * Broker 56 | * 接受客户端的连接,实现AMQP实体服务 57 | 58 | 59 | 60 | ## RabbitMQ 运行 61 | 62 | > docker run -d -p 5672:5672 -p 15672:15672 --name myrabbitmq 3f92e6354d11 63 | 64 | > sudo rabbitmq-server start 65 | 66 | * 使用插件 67 | 68 | > rabbitmq-plugins enable rabbitmq_management 69 | 70 | 71 | 72 | 自动配置 73 | 74 | * RabbitAutoConfiguration 75 | * 有自动配置了连接工厂ConnectionFactory 76 | * RabbitProperties 封装了 RabbitMQ的配置 77 | * RabbitTemplate:给RabbitMQ发送和接收消息 78 | * AmqpAdmin RabbitMQ系统管理组件 79 | 80 | -------------------------------------------------------------------------------- /前端/js.md: -------------------------------------------------------------------------------- 1 | # JS中内置对象 2 | 3 | * Number 4 | 5 | ```javascript 6 | var myNumber = new Number(numeric value); 7 | ``` 8 | 9 | * 属性 10 | * MAX_VALUE 11 | * MIN_VALUE 12 | * NEGATIVE_INFINITY 13 | * POSITIVE_INFINITY 14 | * 方法 15 | * toExponential 16 | * toFixed 17 | * toPrecision 18 | * toString 19 | * valueOf 20 | 21 | * Boolean 22 | 23 | ```javascript 24 | var myBoolean = true; 25 | ``` 26 | 27 | * String 28 | 29 | ```javascript 30 | var myString = "My string"; 31 | ``` 32 | 33 | * 属性 34 | * length 35 | * 方法 36 | * `charAt` 37 | * `charCodeAt` 38 | * `concat` 39 | * `fromCharCode` 40 | * `indexOf` 41 | * `lastIndexOf` 42 | * `match` 43 | * `replace` 44 | * `search` 45 | * `slice` 46 | * `split` 47 | * `substr` 48 | * `substring` 49 | * `toLowerCase` 50 | * `toUpperCase` 51 | 52 | * Date 53 | 54 | ```javascript 55 | var myDate = new Date(); 56 | var myDate = new Date(dateString); 57 | var myDate = new Date(milliseconds); 58 | var myDate = new Date(year, month, day, hours, minutes, seconds, milliseconds); 59 | ``` 60 | 61 | * 方法 62 | * `getDate` 63 | * `getDay` 64 | * `getFullYear` 65 | * `getHours` 66 | * `getMilliseconds` 67 | * `getMinutes` 68 | * `getMonth` 69 | * `getSeconds` 70 | * `getTime` 71 | * `getTimezoneOffset` 72 | * `setDate` 73 | * `setFullYear` 74 | * `setHours` 75 | * `setMilliseconds` 76 | * `setMinutes` 77 | * `setMonth` 78 | * `setSeconds` 79 | * `setTime` 80 | 81 | * Array 82 | 83 | ```javascript 84 | var myArray = new Array(1, 2, 3); 85 | for(var i=0; i的页面才可以使用,在一般的jsp页面中使用该对象将无法编译文件 38 | 39 | 9、pageContext 40 | 41 | pageContext页面上下文对象,可以获取任何范围的参数,对象的创建和初始化都是由容器来完成的,在jsp页面中直接使用pageContext对象 42 | 43 | 44 | 45 | # **Forword(请求转发)与Redirect(重定向)** 46 | 47 | 1、从数据共享上 48 | 49 | ​ Forword是一个请求的延续,可以共享request的数据 50 | 51 | ​ Redirect开启一个新的请求,不可以共享request的数据 52 | 53 | 2、从地址栏 54 | 55 | ​ Forword转发地址栏不发生变化 56 | 57 | ​ Redirect转发地址栏发生变化 58 | 59 | # 报错的状态码 60 | 61 | 301 永久重定向 62 | 63 | 302 临时重定向 64 | 65 | 304 服务端 未改变 66 | 67 | 403 访问无权限 68 | 69 | 200 正常 70 | 71 | 404 路径 72 | 73 | 500 内部错误 74 | 75 | # get 与 post的区别? 76 | 77 | 1.GET请求的数据会附在URL之后,以?分割URL和传输数据,参数之间以&相连, 78 | 79 | POST把提交的数据则放置在是HTTP包的包体中。 80 | 81 | 2.GET的长度受限于url的长度,而url的长度限制是特定的浏览器和服务器设置的,理论上GET的长度可以无限长。 82 | 83 | 3.POST是没有大小限制的,HTTP协议规范也没有进行大小限制,起限制作用的是服务器的处理程序的处理能力 84 | 85 | 4.在ASP中,服务端获取GET请求参数用Request.QueryString,获取POST请求参数用Request.Form。 86 | 87 | 5.POST的安全性要比GET的安全性高 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /Java/java动态代理.md: -------------------------------------------------------------------------------- 1 | # [Java 动态代理作用是什么?](https://www.zhihu.com/question/20794107) 2 | 3 | * 实现无侵入式的代码扩展,也就是方法增强,在不修改源码情况下,增强一些方法 4 | 5 | # Java动态代理实现的两种方法 6 | 7 | ## [JDK动态代理](https://blog.csdn.net/xlgen157387/article/details/82497594?utm_medium=distribute.pc_relevant.none-task-blog-searchFromBaidu-5.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-searchFromBaidu-5.channel_param) 8 | 9 | * JDK动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是`InvocationHandler`接口和Proxy类。 10 | * 通过Proxy来生成代理类实例,而这个代理实例通过调用处理器`InvocationHandler`接收不同的参数灵活调用真实对象的方法。 11 | * `InvocationHandler`是一个接口,可以通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态地将横切逻辑和业务逻辑贬值在一起。 12 | * 目标类方法都要在接口中声明 13 | * 如果目标类没有实现接口,那么Spring AOP会选择使用**CGLIB**来动态代理目标类。 14 | 15 | ## CGLIB动态代理 16 | 17 | * CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意,CGLIB是通过继承的方式做的动态代理,因此**如果某个类被标记为final,那么它是无法使用CGLIB做动态代理**的。 18 | 19 | * 借助asm来实现,在生成类之后的相关执行过程中比较高效(可通过将asm生成的类进行缓存解决asm生成类过程低效问题) 20 | 21 | * CGLib可以为一个类创建一个子类,可以实现运行期动态扩展java类,Spring在运行期间通过 CGlib继承要被动态代理的类,重写父类的方法,实现AOP面向切面编程 22 | 23 | 24 | ## [CGLIB与JDK区别](https://blog.csdn.net/xlgen157387/article/details/82497594?utm_medium=distribute.pc_relevant.none-task-blog-searchFromBaidu-5.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-searchFromBaidu-5.channel_param) 25 | 26 | * Spring通过Java的反射机制生产被代理接口的新的匿名实现类,重写了其中AOP的增强方法。 27 | 28 | * JDK **动态代理类和委托类需要都实现同一个接口**。也就是说只有实现了某个接口的类可以使用Java动态代理机制. 29 | * 但是,事实上使用中并不是遇到的所有类都会给你实现一个接口。因此,**对于没有实现接口的类,就不能使用该机制。而CGLIB则可以实现对类的动态代理**。 30 | 31 | ## [性能对比](https://blog.csdn.net/xlgen157387/article/details/82497594?utm_medium=distribute.pc_relevant.none-task-blog-searchFromBaidu-5.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-searchFromBaidu-5.channel_param) 32 | 33 | 1、CGLib所创建的动态代理对象在实际运行时候的性能要比JDK动态代理高不少,有研究表明,大概要高10倍; 34 | 35 | 2、但是CGLib在创建对象的时候所花费的时间却比JDK动态代理要多很多,有研究表明,大概有8倍的差距; 36 | 37 | 3、因此,对于singleton的代理对象或者具有实例池的代理,因为无需频繁的创建代理对象,所以比较适合采用CGLib动态代理,反正,则比较适用JDK动态代理。 38 | 39 | 在JDK1.8的时候,**JDK动态代理的速度已经比CGLib动态代理的速度快很多了** 40 | 41 | # [JDK动态代理为什么必须用接口](https://juejin.im/post/5d8a0799f265da5b7a752e7c) 42 | 43 | * 因为Java中不支持多继承,而JDK的动态代理在创建代理对象时,默认让代理对象继承了Proxy类,所以JDK只能通过接口去实现动态代理。 -------------------------------------------------------------------------------- /Java/jsp.md: -------------------------------------------------------------------------------- 1 | # jsp的9大内置对象 2 | 3 | 1、request对象 4 | 5 | request对象表示了从客端发过来的请求,主要用于接收客户端穿过来的数据,其作用域为一次请求 6 | 7 | 2、response对象 8 | 9 | response对象表示服务端向客户端返回的响应,主要将jsp处理过的对象传回到客户端,response对象的作用域只在jsp页面有效; 10 | 11 | 3、session对象 12 | 13 | Session对象是用来分别保存每一个用户信息的对象,以便于跟踪用户的操作状态.它保存在服务端,Session的ID保存在客户机的Cookie中. 14 | 15 | 4、application 16 | 17 | Application可以将数据保存到服务器中,直到服务器关闭,否则Application中保存的数据在整个应用中都有效,application的声明周期相较于session、request、response较长。 18 | 19 | application对象在服务器启动时就创建了,Application是一个单例的,多个用户共享这一个对象。 20 | 21 | 5、out对象 22 | 23 | 动态的向JSP页面输出字符流,从而把动态的内容转化成HTML形式来展示,这个对象在任何JSP页面中都可以任意访问。 24 | 25 | 6、page对象 26 | 27 | page对象表示jsp本身,作用范围在jsp页面才是合法的 28 | 29 | 7、config对象 30 | 31 | config对象代表当前JSP配置信息,实质上是ServletConfig的一个实例,常用来获取Servlet的初始化参数。 32 | 33 | 8、exception 34 | 35 | Exception对象的作用是显示异常信息,只有使用了<%@page isErrorPage="true"%>的页面才可以使用,在一般的jsp页面中使用该对象将无法编译文件 36 | 37 | 9、pageContext 38 | 39 | pageContext页面上下文对象,可以获取任何范围的参数,对象的创建和初始化都是由容器来完成的,在jsp页面中直接使用pageContext对象 40 | 41 | 42 | 43 | # **Forword(请求转发)与Redirect(重定向)** 44 | 45 | 1、从数据共享上 46 | 47 | ​ Forword是一个请求的延续,可以共享request的数据 48 | 49 | ​ Redirect开启一个新的请求,不可以共享request的数据 50 | 51 | 2、从地址栏 52 | 53 | ​ Forword转发地址栏不发生变化 54 | 55 | ​ Redirect转发地址栏发生变化 56 | 57 | # 报错的状态码 58 | 59 | 301 永久重定向 60 | 61 | 302 临时重定向 62 | 63 | 304 服务端 未改变 64 | 65 | 403 访问无权限 66 | 67 | 200 正常 68 | 69 | 404 路径 70 | 71 | 500 内部错误 72 | 73 | # get 与 post的区别? 74 | 75 | * GET请求的数据会附在URL之后,以?分割URL和传输数据,参数之间以&相连,POST把提交的数据则放置在是HTTP包的包体中。 76 | * GET的长度受限于url的长度,而url的长度限制是特定的浏览器和服务器设置的,理论上GET的长度可以无限长。 77 | * POST是没有大小限制的,HTTP协议规范也没有进行大小限制,起限制作用的是服务器的处理程序的处理能力 78 | * 在ASP中,服务端获取GET请求参数用Request.QueryString,获取POST请求参数用Request.Form。 79 | * POST的安全性要比GET的安全性高 80 | 81 | # Jsp有哪些动作?作用是什么? 82 | 83 | * jsp:include 84 | * 在页面被请求的时候引入一个文件 85 | * jsp:useBean 86 | * 寻找或者实例化一个JavaBean 87 | * jsp:setProperty 88 | * 设置JavaBean的属性 89 | * jsp:getProperty 90 | * 输出某个JavaBean的属性 91 | * jsp:forward 92 | * 殷请求转到一个新的页面 93 | * jsp:plugin 94 | * 根据浏览器类型为Java插件生成OBJECT或EMBED标记 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /spring/Servlet.md: -------------------------------------------------------------------------------- 1 | # Servlet生命周期 2 | 3 | ![img](https://uploadfiles.nowcoder.com/images/20170823/3252049_1503478423363_D9B23E5A78E8071F0BB0D7E0E456058E) 4 | 5 | # ServletContext 6 | 7 | * 使用ServletContext注册web组件(Servlet,Filter,Listener) 8 | * 使用编码方式,在项目启动的时候给ServletContext里面添加组件 9 | * ServletContainerInitializer得到的ServletContext 10 | * ServletContextListener提到的ServletContext 11 | 12 | 13 | 14 | # Session机制 15 | 16 | HttpServletResponse 接口提供了重写 URL 的方法: 17 | 18 | ```java 19 | public java.lang.String encodeURL(java.lang.String url) 20 | ``` 21 | 22 | 该方法的实现机制为: 23 | 24 | ​ ● 先判断当前的 Web 组件是否启用 Session,如果没有启用 Session,直接返回参数 url。 25 | 26 | ​ ● 再判断客户端浏览器是否支持 Cookie,如果支持 Cookie,直接返回参数 url;如果不支持 Cookie,就在参数 url 中加入 Session ID 信息,然后返回修改后的 url。 27 | 28 | # [ Servlet如何处理多个请求访问](https://www.jianshu.com/p/abb2221fc6e7) 29 | 30 | * Servlet容器默认是采用单实例多线程的方式处理多个请求的: 31 | * 1.当web服务器启动的时候(或客户端发送请求到服务器时),Servlet就被加载并实例化(只存在一个Servlet实例); 32 | * 2.容器初始化化Servlet主要就是读取配置文件(例如tomcat,可以通过servlet.xml的设置线程池中线程数目,初始化线程池通过web.xml,初始化每个参数值等等。 33 | * 3.当请求到达时,Servlet容器通过调度线程(Dispatchaer Thread) 调度它管理下线程池中等待执行的线程(Worker Thread)给请求者; 34 | * 4.线程执行Servlet的service方法; 35 | * 5.请求结束,放回线程池,等待被调用; 36 | 37 | (注意:避免使用实例变量(成员变量),因为如果存在成员变量,可能发生多线程同时访问该资源时,都来操作它,照成数据的不一致,因此产生线程安全问题) 38 | 39 | # [如何控制Servlet的线程安全性](https://www.jianshu.com/p/82a2a4fcd0c9) 40 | 41 | ## 变量的线程安全 42 | 43 | * 我们知道当没有实例变量的时候,就基本不存在线程不安全的问题了,所以**不使用实例变量是一种方法**。 44 | 45 | ## 属性的线程安全 46 | 47 | - ServletContext,不是线程安全的,多线程可以同时读写。使用时要注意。 48 | - HttpSession,不是线程安全的,比如用户打开多个浏览器窗口时候就会产生多个请求针对同一个session的操作。使用时要注意。 49 | - ServletRequest,线程安全的,它对应着一个request请求,所以说是线程安全的。 50 | 51 | # [DispatcherServlet的线程安全性](https://www.jianshu.com/p/82a2a4fcd0c9) 52 | 53 | * 在应用启动的时候,就会根据web.xml中配置的有关Spring和SpringMVC的配置启动初始化,**对于SpringMVC初始化的是DispatcherServlet**,对于Servlet初始化只会进行一次,并且只有一个实例,所以DispatcherServlet只会存在一个。 54 | 55 | * 但是当多线程同时访问DispatcherServlet的时候是线程安全的,因为**DispatcherServlet中的内部属性都不会影响线程安全,所以DispatcherServlet可以忽略线程安全的问题**。 56 | 57 | * 虽然DispatcherServlet可以认为是线程安全的,但是SpringMVC中的Controller不是。Controller也是单例的,每个请求对应一个Controller中的方法,方法如果没有使用实例变量,可以认为是线程安全的,但是如果有实例变量就要考虑线程安全的问题了 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /Java/Java并发编程[MT].md: -------------------------------------------------------------------------------- 1 | # Java内存模型(JMM) 2 | 3 | ## 缓存行 cache line 4 | 5 | * 对齐 6 | 7 | ## 原子性 8 | 9 | ## 可见性 10 | 11 | * Java中可见性措施 12 | * 被final修饰的字段初始化完成能确保可见性 13 | * volatile 14 | * synchronized 15 | * 符合happens-befor次序法则的可见性 16 | 17 | ## 有序性 18 | 19 | * 概念 20 | * 程序执行的jdyc按照代码的顺序执行 21 | * Java中有序性的措施 22 | * volatile 23 | * synchronized 24 | * Happens-before法则 25 | 26 | ## 代码重排 27 | 28 | * 为了使处理器内部的去运算单元充分利用 29 | * 编译期重排 30 | * 编译器依据上下文分析,对指令进行重排序,以更适合cpu运行 31 | * 运行期重排 32 | 33 | ## 内存屏障 34 | 35 | * 阻止屏障两边的指令重排 36 | 37 | ### volatile 38 | 39 | * 轻量同步,不会进行线程阻塞 40 | * 读写直接作用于主内存 41 | * 保证变量可见性,不保证原子性 42 | 43 | # JUC框架 44 | 45 | ## 锁 46 | 47 | ### 乐观锁CAS(compare and swap) 48 | 49 | * ABA问题 50 | * 通过版本号机制解决 51 | 52 | ### 悲观锁 53 | 54 | * synchronized 55 | * 对象锁 56 | * 类锁 57 | * 非公平锁 58 | * 基于JVM实现 59 | * 偏向锁(CAS) 60 | * 轻量级锁 61 | * 重量级锁 62 | * wait/notify 63 | * notify唤醒锁之后需要等该代码块执行完才会释放锁 64 | * reentryLock 65 | * 基于代码层面实现 66 | * Unlock()操作必须放到finally块中 67 | * 底层基于AQS的独占锁实现 68 | * 可重入,通过AQS的同步状态来保存锁重入次数 69 | * AQS 70 | * 线程管理队列-->双向node 71 | * 尾部CAS入队 72 | * 头部释放锁出队的时候唤醒next节点 73 | * Condition 74 | * 用于线程间的协作 75 | * 读写锁ReadWriteLock 76 | * 基于AQS 77 | * 高16位读锁次数 78 | * 低16位写锁次数 79 | * 闭锁CountdownLatch 80 | * 基于AQS,一次性的 81 | * 一个线程等待别一个线程结束(countDown(),await()) 82 | 83 | * 栅栏CyclicBarrier 84 | 85 | * 基于condition-await/SignalAll 86 | * 一种计数方式,可重用 87 | * 等待n个线程一起开始业务 88 | 89 | * 信号量 90 | 91 | * 基于AQS共享锁的实现 92 | * 同步状态state表示当前计数 93 | * 当计数<=0时,阻塞;大于0时解除阻塞 94 | 95 | * 分布式锁 96 | 97 | * > 找到一个单点,锁状态持久化 98 | 99 | * 基于数据库 100 | 101 | * 基于redis 102 | 103 | * RedLock算法 104 | * 在N个节点下,获取到>=N/2+1,就算获取锁 105 | 106 | * 基于zookeeper 107 | 108 | * QPS高时不要使用 109 | 110 | # 并发容器 111 | 112 | * ConcurrentHashMap 113 | * CopyOnWriteArrayList 114 | * 写时复制,引发young gc 115 | * 阻塞队列 116 | * 基于数组结构实现的有界队列 117 | 118 | # 线程池 119 | 120 | * 拒绝策略 121 | 122 | # 协程 123 | 124 | * 轻量级线程 125 | * 创建和切换开销小 126 | * 协程高度在用户态完成 127 | 128 | # 缓存失效解决 129 | 130 | * 双写 131 | * 缓存失效后,单机只用其中一个请求线程去db捞取 132 | * 缓存失效前,单机去db捞取 -------------------------------------------------------------------------------- /Kafka/Kafka.md: -------------------------------------------------------------------------------- 1 | # **请说明Kafka相对传统技术有什么优势?** 2 | 3 | 快速:单一的Kafka代理可以处理成千上万的客户端,每秒处理数兆字节的读写操作。 4 | 5 | 可伸缩:在一组机器上对数据进行分区和简化,以支持更大的数据 6 | 7 | 持久:消息是持久性的,并在集群中进行复制,以防止数据丢失。 8 | 9 | 设计:它提供了容错保证和持久性 10 | 11 | * 概念 12 | 13 | * Topic 14 | * 一个主题类似新闻中的体育,娱乐,教育等分类概念,在实际工程中通常一个业务一个主题 15 | * Partition 16 | * Topic物理上的分组,一个topic可以分为多个partition,每个partition是一个先进先出的有序队列。partition中的每条消息都会被分配一个有序的id(offset)。 17 | * Message 18 | * 消息,是通信的基本单位,每个producer可以向一个topic(主题)发布一些消息。 19 | * Producers 20 | * 消息和数据生产者,向Kafka的一个topic发布消息的过程叫做producers。 21 | * Consumers 22 | * 消息和数据消费者,订阅topics并处理其发布的消息的过程叫做consumers。 23 | * Broker 24 | * 缓存代理,Kafka集群中的一台或多台服务器统称为broker。 25 | 26 | * 负载均衡原理 27 | 28 | producer根据用户指定的算法,将消息发送到指定的partition 29 | 30 | 存在多个partiiton,每个partition有自己的replica,每个replica分布在不同的Broker节点上 31 | 32 | 多个partition需要选取出lead partition,lead partition负责读写,并由zookeeper负责fail over 33 | 34 | 通过zookeeper管理broker与consumer的动态加入与离开 35 | 36 | 37 | 38 | # Kafka主要特点? 39 | 40 | * 同时为发布和订阅提供高吞吐量。据了解,Kafka每秒可以生产约25万消息(50 MB),每秒处理55万消息(110 MB)。 41 | * 可进行持久化操作。将消息持久化到磁盘,因此可用于批量消费,例如ETL,以及实时应用程序。通过将数据持久化到硬盘以及replication防止数据丢失。 42 | * 分布式系统,易于向外扩展。所有的producer、broker和consumer都会有多个,均为分布式的。无需停机即可扩展机器。 43 | * 消息被处理的状态是在consumer端维护,而不是由server端维护。当失败时能自动平衡。 44 | * 支持online和offline的场景。 45 | 46 | # Consumer端数据丢失怎么办 47 | 48 | * consumer端丢失消息的情形比较简单: 49 | * 如果在消息处理完成前就提交了offset,那么就有可能造成数据的丢失。由于Kafka consumer默认是自动提交位移的,所以在后台提交位移前一定要保证消息被正常处理了,因此不建议采用很重的处理逻辑,如果处理耗时很长,则建议把逻辑放到另一个线程中去做。为了避免数据丢失, 50 | * 现给出两点建议: 51 | * `enable.auto.commit=false` 关闭自动提交位移,在消息被完整处理之后再手动提交位移 52 | 53 | # Kafka的应用场景 54 | 55 | 1、消息队列 56 | 2、行为跟踪:跟踪用户浏览页面、搜索及其他行为,以发布-订阅的模式实时记录到对应的topic里 57 | 3、元信息监控:运维性质的数据监控 58 | 4、日志收集 59 | 5、流处理 60 | 6、事件源 61 | 7、持久性日志(commit log) 62 | 63 | # Kafka消费者编程模型 64 | 65 | * 分区消费模型 66 | * 一个partition对应一个consumer 67 | * 组消费模型 68 | * 一个partition可被不同组中的一个Consumer消费 69 | * 两种消费模型对比 70 | * 分区消费模型更加灵活,但: 71 | * 需要自己处理各种异常情况 72 | * 需要自己管理offset(以实现消息传递的其他语义) 73 | * 组消费模型更加简单,但是不灵活 74 | * 不需要自己处理异常情况,不需要自己管理offset 75 | * 只能实现Kafka默认的最少一次消息传递语义 76 | 77 | # Kafka生产者编程模型 78 | 79 | * 同步生产模型 80 | * 低消息丢失率 81 | * 高消息重复率(由于网络原因,回复确认未收到) 82 | * 高延迟 83 | * 异步生产模型 84 | * 低延迟 85 | * 高发送性能 86 | * 高消息丢失率(无确认机制,发送端队列满) 87 | * 两种生产模型对比 88 | 89 | -------------------------------------------------------------------------------- /Java/String.md: -------------------------------------------------------------------------------- 1 | # String、StringBuffer、StringBuilder的区别 2 | 3 | * 可变与不可变 4 | * String使用字符数组保存字符串,用final 修饰`private final char value[]`.String对象不可变(指向字符串的指针不可变) 5 | * Java1.9之后使用`private final byte[] value` 6 | * StringBuilder与StringBuffer都继承自AbstractStringBuilder类 7 | * AbstractStringBuilder中也使用字符数组保存字符串`char[] value;` 8 | * AbstractStringBuilder公共方法 9 | * expandCapacity 10 | * append 11 | * insert 12 | * indexOf 13 | * 都是final类,不允许被继承 14 | * 线程安全 15 | * String对象不可变.线程安全 16 | * StringBuffer对方法加了同步锁或者调用的方法加了同步锁.线程安全 17 | * StringBuilder非线程安全 18 | * StringBuffer与StringBuilder共同点 19 | * 公共父类AbstractStringBuilder 20 | * 有公共方法,StringBuffer会在方法上加Synchronized关键字同步 21 | * 如果程序不是多线程,StringBuilder效率更高 22 | * String与StringBuffer的区别 23 | * String修改时等同于创建一个新的String对象,经常改变字符内容最好不要用String 24 | * StringBuffer修改时会修改对象自身 25 | 26 | # String类为什么要设计成final 27 | 28 | * 可以缓存hash值 29 | * String的hash值经常被使用,如String用做HashMap的key,只需计算 一次 30 | * 常量池需要 31 | * 若String对象已被创建过,会从常量池取得引用,只有不可变才能使用常量池 32 | * 安全性 33 | 34 | # String不变性的理解 35 | 36 | * String被final修饰,无法被继承 37 | * 用+连接字符串时会创建新的字符串 38 | * `String s = new String(“Hello world”)`可能创建两个对象,也可能创建一个 39 | * 若常量池中有"Hello world"字符串常量对象,则仅仅在堆中创建一个对象 40 | * 若常量池中没有"Hello world"对象,则堆上和常量池中都要创建对象 41 | * 通过使用`+`连接字符串时,实际上底层会转成通过`StringBuilder`实例的`append()`方法来实现 42 | 43 | # String Pool 44 | 45 | * 保存着所有字符串字面量,可通过`intern()`方法将字符串添加入常量池 46 | * 当字符串调用`intern()`方法 47 | * 若String pool已存在该值,则返回String Pool中引用 48 | * 若不存在池中,则添加并返回池中引用 49 | 50 | # final好处 51 | 52 | * 提高了性能,JVM和Java应用都会缓存final变量 53 | * 可以安全地在多线程环境下进行共享,而不需要额外的同步开销 54 | * 使用final关键字,JVM会对方法,变量及类进行优化 55 | 56 | # [关于String创建几个对象](https://juejin.im/post/6844904129752465416) 57 | 58 | ## `String s1 = new String("Java");` 59 | 60 | * 可能创建 1 个或 2 个对象,new String 会先去常量池中判断有没有此字符串,如果有则只在堆上创建一个字符串并且指向常量池中的字符串,如果常量池中没有此字符串,则会创建 2 个对象,先在常量池中新建此字符串,然后把此引用返回给堆上的对象,如下图所示: 61 | 62 | ![new 字符串常量池.png](https://user-gold-cdn.xitu.io/2020/4/17/17185b71e45e6c16?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) 63 | 64 | ## [`String a="a"+"b"+"c"`](https://www.zhihu.com/question/38733755) 65 | 66 | * 通过编译器优化后,得到的效果是 67 | 68 | ```text 69 | String a="abc" 70 | ``` 71 | 72 | * 如果字符串常量池中存在abc,则该语句并不会创建对象,只是讲字符串常量池中的引用返回而已。 73 | * 如果字符串常量池中不存在abc,则会创建并放入字符串常量池,并返回引用,此时会有一个对象进行创建。 -------------------------------------------------------------------------------- /spring/springcloud.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ![img](https://user-gold-cdn.xitu.io/2018/11/7/166ec006b1536f43?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) 4 | 5 | # 服务治理 Eureka 6 | 7 | 提供服务注册和服务发现功能 8 | 9 | * 服务治理核心 10 | * 服务提供者 11 | * 服务消费者 12 | * 注册中心 13 | * Eureka Server 14 | * 注册中心 15 | * Euraka Client 16 | * 所有要进行注册的微服务通过Euraka Client 连接到Euraka Server,完成注册 17 | * @EnableEurekaServer 18 | * @EnableEurekaClient 19 | 20 | ## RestTemplate 21 | 22 | * 什么是RestTemplate? 23 | 24 | RestTemplate是Spring 框架提供基于REST的服务组件,底层是对HTTP请求及响应进行了封装,提供了很多访问REST服务的方法,可以简化代码开发。 25 | 26 | * 如何使用RestTemplate? 27 | 28 | 29 | 30 | 31 | 32 | # 负载均衡 Ribbon 33 | 34 | * 什么是Ribbon? 35 | * 基于Netflix Ribbon实现的,是一个用于对HTTP请求进行控制的负载均衡客户端 36 | * Ribbon基于负载均衡算法自动帮助服务消费者调用接口 37 | * 轮询 38 | * 随机 39 | * 加权轮询 40 | * 加权随机 41 | * 自定义 42 | * @LoadBalanced 43 | * 声明一个基于Ribbon的负载均衡服务 44 | 45 | # 负载均衡 Feign 46 | 47 | * 什么是Feign 48 | 49 | * 一个声明式,模板化的Web Service客户端,简化了开发者编写Web服务客户端的操作 50 | * 开发者可以通过简单的接口和注解来调用Http API 51 | * 整合了Ribbon和Hystrix 52 | * 可插拔,基于注解,负载均衡,服务熔断 53 | 54 | * @EnableFeignClients 55 | 56 | * @FeignClient(value=“provider”,fallback=FeignError.class) 57 | 58 | * 修饰接口 59 | 60 | * 服务熔断 61 | 62 | * feign.nystrix.enabled = true 63 | 64 | 65 | 66 | # 服务网关 Zuul 67 | 68 | * 什么是Zuul 69 | * Netflix提供的开源API网关服务器 70 | * 客户端和网站所有请求的中间层,对外开放一个API 71 | * 将所有请求导入统一的入口,屏蔽了服务端的具体实现逻辑 72 | * Zuul可以实现反向代理的功能,在网关内部实现动态路由,身份谁,IP过滤,数据监控 73 | * Zuul自带了负载均衡功能,修改provider的代码 74 | 75 | 76 | 77 | # 服务容错 Hystrix 78 | 79 | 在不改变各个微服务调用关系的前题下,针对错误情况进行预先处理 80 | 81 | * 设计原则 82 | * 服务隔离机制 83 | * 服务降级机制 84 | * 熔断机制 85 | * 实时的监控的报警功能 86 | * 需要结合Actuator使用 87 | * 实时的配置修改功能 88 | * @EnableFeignClients 89 | * @EnableCircuitBreaker 90 | * 声明启用数据监控 91 | * @EnableHystrixDashboard 92 | * 声明启用可视化的数据监控 93 | 94 | # 服务配置 Config 95 | 96 | 通过服务端为多个客户端提供配置服务 97 | 98 | * 本地配置 99 | * 远程配置 100 | * @EnableConfigServer 101 | * 声明配置中心 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | # 服务监控 Actuator 110 | 111 | # 服务跟踪 Zipkin 112 | 113 | @EnableZipkinServer 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /JVM/ClassLoader.md: -------------------------------------------------------------------------------- 1 | # 谈谈ClassLoader 2 | 3 | * ClassLoader在Java中有着非常重要的作用,它主要工作在Class装载的加载阶段,其主要作用是从系统外部获得Class二进制数据流。 4 | 5 | * 它是Java的核心组件,所有的Class都是由ClassLoader进行加载的,ClassLoader负责通过将Class文件里的二进制数据流装载进系统,然后交给Java虚拟机进行连接,初始化等操作。 6 | 7 | # ClassLoader的种类 8 | 9 | * 启动类加载器`BootStrapClassLoader` 10 | * C++编写,加载核心库 java.* 11 | * 扩展类加载器`ExtClassLoader` 12 | * Java编写,加载扩展库javax.* 13 | * 应用程序类加载器`AppClassLoader` 14 | * Java编写,加载程序所在目录 15 | * 自定义ClassLoader 16 | * Java编写,定制化加载 17 | 18 | 19 | 20 | # 双亲委派机制加载类 21 | 22 | * 避免多份同样字节码的加载 23 | 24 | * 工作过程 25 | 26 | * 类加载器将类加载请求转发到父类加载器,父类无法完成时自己加载 27 | 28 | 29 | 30 | # 类加载方式 31 | 32 | * 隐匿加载 33 | * new 34 | * 显式加载 35 | * loadClass 36 | * forName 37 | 38 | # [类的加载过程/生命周期](https://zhuanlan.zhihu.com/p/33509426) 39 | 40 | ![img](https://i.loli.net/2020/08/01/CD1TkAag5B2wQGi.jpg) 41 | 42 | ## 加载 43 | 44 | * 通过ClassLoader加载class文件字节码,生成class对象 45 | 46 | ## 链接 47 | 48 | * 校验 49 | 50 | * 检查加载的class的正确性和安全性 51 | * 准备 52 | * 主要是为类变量(注意,不是实例变量)分配内存,并且赋予**初值**。 53 | 54 | 特别需要注意,**初值,不是代码中具体写的初始化的值**,而是Java虚拟机根据不同变量类型的默认初始值。 55 | 56 | 比如8种**基本类型**的初值,默认为0;**引用类型**的初值则为null;**常量**的初值即为代码中设置的值,final static tmp = 456, 那么该阶段tmp的初值就是456 57 | * 解析 58 | 59 | * JVM将常量池内的符号引用转换为直接引用 60 | * **符号引用**。即一个字符串,但是这个字符串给出了一些能够唯一性识别一个方法,一个变量,一个类的相关信息。 61 | * **直接引用**。可以理解为一个内存地址,或者一个偏移量。比如**类方法,类变量**的直接引用是指向方法区的**指针**;而**实例方法,实例变量**的直接引用则是从实例的头指针开始算起到这个实例变量位置的**偏移量** 62 | 63 | ## 初始化 64 | 65 | * 在准备阶段,类变量已被赋过系统默认值,该阶段根据程序赋值 66 | 67 | * 时机 68 | 69 | * 主动引用 70 | 71 | * `new` `getstatic` `putstatic` `invokestatic` 72 | * 反射调用且类没被初始化 73 | * 初始化类时,父类未初始化 74 | * 虚拟机启动时会初始化一个主类(main) 75 | 76 | * 被动引用 (被动引用不触发初始化) 77 | 78 | * 子类引用父类静态字段 79 | 80 | * 数组定义引用类,会对数组类初始化 81 | 82 | * 常量类不会初始化 83 | 84 | 85 | 86 | ## 使用 87 | 88 | ## [卸载](https://www.jianshu.com/p/d6d75590128c) 89 | 90 | * **由Java虚拟机自带的类加载器所加载的类,在虚拟机的生命周期中,始终不会被卸载。** 91 | * Java虚拟机**自带的类加载器**包括**根类加载器**、**扩展类加载器**和**系统类加载器** 92 | * Java虚拟机本身会**始终引用**这些类加载器,而这些类加载器则会**始终引用**它们所加载的类的Class对象,因此这些Class对象**始终是可触及的**。 93 | * **由用户自定义的类加载器加载的类是可以被卸载的。** 94 | 95 | # loadClass和forName区别 96 | 97 | * Classloader.loadClass(className) 98 | * 目标对象被装载后不会进行链接,loadClass不会执行静态代码块 99 | * Class.forName(className) 100 | * 在loadClass之后须初始化 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /hadoop/MapReduce.md: -------------------------------------------------------------------------------- 1 | # MapReduce 的工作原理 2 | 3 | MapReduce中,Map是一个将输入记录转换为中间记录的任务。已转换的中间记录不一定非得与输入记录具有相同的类型。一个给定的输入对可能映射到零个或多个输出对。Map数量通常由输入数据的大小决定,也就是输入数据的总的块数【(MRJobConfig.NUM_MAPS可设置】。Reducer接收的数据是Mapper中处理出来的已经排好序的数据。 4 | 5 | **在MapReduce过程中需要将各个节点上的同一类数据汇集到一个节点进行计算。把这些分布在不同节点的数据按照一定规则聚集到一起的过程,就称之为shuffle。** 6 | 7 | * ## 4个阶段 8 | 9 | * Split(分片输入) 10 | 11 | * Map 12 | 13 | * 增加map任务个数 14 | 15 | 增大:mapred.map.tasks 16 | 17 | * 减少map个数.增大mapred.min.split.size 18 | 19 | * 若要减少map个数,但有很多小文件,可将小文件合并成大文件,再使用准则2 20 | 21 | * Combine 22 | 23 | * 可认为Combine是对本地reduce操作 24 | 25 | * Shuffle 26 | 27 | * Reduce 28 | 29 | **Map数量:** 对于大文件:由任务的 split 切片决定的,**一个 split 切片对应一个map任务**。先明确一点 split 切片的大小可自己配置的,一般来说对于大文件会选择split == block,如果split < block的情况下会增加 map 的数量,虽然这样可以增加map执行的并行度,但是会导致map任务在不同节点拉取数据,浪费了网络资源等。ps:HDFS 中 block 是最小的存储单元,默认128M。 对于小文件:由参与任务的文件数量决定,默认情况一个小文件启动一个 map 任务,小文件数量较多会导致启动较大数量的 map 任务,增加资源消耗。此时建议将多个小文件通过 **InputFormat 合并成一个大文件加入到一个 split 中**,并增加 split 的大小,这样可以有效减少 map 的数量,降低并发度,减少资源消耗。 30 | 31 | **Reduce数量**:由分区(partiton)的数量决定的,我们可以在代码中配置 job.setNumReduceTasks(*)来控制 reduce 的任务数量。 32 | 33 | 34 | 35 | ## Shuffle 过程分为Map端跟Reduce端的Shuffle过程 36 | 37 | ### **Map端流程** 38 | 39 | 1. **环形内存缓存区**:每个split数据交由一个map任务处理,map的处理结果不会直接写到硬盘上,会先输送到环形内存缓存区中,默认的大小是100M(可通过配置修改),当缓冲区的内容达到80%后会开始溢出,此时缓存区的溢出内容会被写到磁盘上,形成一个个spill file,注意这个文件没有固定大小。 40 | 2. **在内存中经过分区、排序后溢出到磁盘**:分区主要功能是用来指定 map 的输出结果交给哪个 reduce 任务处理,**默认是通过 map 输出结果的 key 值取hashcode 对代码中配置的 redue task数量取模运算**,值一样的分到一个区,也就是一个 reduce 任务对应一个分区的数据。这样做的好处就是可以避免有的 reduce 任务分配到大量的数据,而有的 reduce 任务只分配到少量甚至没有数据,平均 reduce 的处理能力。并且在每一个分区(partition)中,都会有一个 sort by key 排序,如果此时设置了 Combiner,将排序后的结果进行 Combine 操作,相当于 map 阶段的本地 reduce,这样做的目的是让尽可能少的数据写入到磁盘。 41 | 3. **合并溢出文件**:随着 map 任务的执行,不断溢出文件,直到输出最后一个记录,可能会产生大量的溢出文件,这时需要对这些大量的溢出文件进行合并,在合并文件的过程中会不断的进行排序跟 Combine 操作,这样做有两个好处:**减少每次写入磁盘的数据量&减少下一步 reduce 阶段网络传输的数据量**。最后合并成了一个分区且排序的大文件,此时可以再进行配置压缩处理,可以减少不同节点间的网络传输量。合并完成后着手将数据拷贝给相对应的reduce 处理,那么要怎么找到分区数据对应的那个 reduce 任务呢?简单来说就是 **JobTracker 中保存了整个集群中的宏观信息**,只要 reduce 任务向 JobTracker 获取对应的 map 输出位置就可以了。具体请参考上方的MapReduce工作原理。 42 | 43 | ### **Reduce端流程** 44 | 45 | reduce 会接收到不同 map 任务传来的有序数据,如果 reduce 接收到的数据较小,**则会存在内存缓冲区中,直到数据量达到该缓存区的一定比例时对数据进行合并后溢写到磁盘上**。随着溢写的文件越来越多,后台的线程会将他们合并成一个更大的有序的文件,可以为后面合并节省时间。这其实跟 map端的操作一样,**都是反复的进行排序、合并**,这也是 Hadoop 的灵魂所在,但是如果在 map 已经压缩过,在合并排序之前要先进行解压缩。合并的过程会产生很多中间文件,但是最后一个合并的结果是不需要写到磁盘上,而是可以直接输入到 reduce 函数中计算,每个 reduce 对应一个输出结果文件。 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /hadoop/YARN.md: -------------------------------------------------------------------------------- 1 | # Yarn与Mesos的对比 2 | 3 | ## 框架担任的角色: 4 | 5 | 在Mesos中,各种计算框架是完全融入Mesos中的,也就是说,如果你想在Mesos中添加一个新的计算框架,首先需要在Mesos中部署一套该框架;而在YARN中,各种框架作为client端的library使用,仅仅是你编写的程序的一个库,不需要事先部署一套该框架。从这点上说,YARN运行和使用起来更加方便。 6 | 7 | ![img](https://upload-images.jianshu.io/upload_images/6116404-e81ad3d9acd16cd2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp) 8 | 9 | # 描述Yarn执行一个任务的过程? 10 | 11 | [YARN]() 12 | 13 | 1)客户端client向ResouceManager提交Application,ResouceManager接受Application并根据集群资源状况选取一个node来启动Application的任务调度器driver(ApplicationMaster) 14 | 15 | 2)ResouceManager找到那个node,命令其该node上的nodeManager来启动一个新的JVM进程运行程序的driver(ApplicationMaster)部分,driver(ApplicationMaster)启动时会首先向ResourceManager注册,说明由自己来负责当前程序的运行 16 | 3)driver(ApplicationMaster)开始下载相关jar包等各种资源,基于下载的jar等信息决定向ResourceManager申请具体的资源内容。 17 | 4)ResouceManager接受到driver(ApplicationMaster)提出的申请后,会最大化的满足 18 | 资源分配请求,并发送资源的元数据信息给driver(ApplicationMaster); 19 | 5)driver(ApplicationMaster)收到发过来的资源元数据信息后会根据元数据信息发指令给具体 20 | 机器上的NodeManager,让其启动具体的container。 21 | 6)NodeManager收到driver发来的指令,启动container,container启动后必须向driver(ApplicationMaster)注册。 22 | 7)driver(ApplicationMaster)收到container的注册,开始进行任务的调度和计算,直到 23 | 任务完成。 24 | 25 | 补充:如果ResourceManager第一次没有能够满足driver(ApplicationMaster)的资源请求 26 | ,后续发现有空闲的资源,会主动向driver(ApplicationMaster)发送可用资源的元数据信息 27 | 28 | 以提供更多的资源用于当前程序的运行 29 | 30 | # Yarn中的container是由谁负责销毁的,在Hadoop Mapreduce中container可以复用么? 31 | 32 | ApplicationMaster负责销毁,在Hadoop Mapreduce不可以复用,在spark on yarn程序container可以复用 33 | 34 | 35 | 36 | # 提交任务时,如何指定Spark Application的运行模式? 37 | 38 | 1)cluster模式:./spark-submit --class xx.xx.xx --master yarn --deploy-mode cluster xx.jar 39 | 40 | 2) client模式:./spark-submit --class xx.xx.xx --master yarn --deploy-mode client xx.jar 41 | 42 | 43 | 44 | # Spark中的4040端口由什么功能? 45 | 46 | 收集Spark作业运行的信息 47 | 48 | 49 | 50 | # 谈谈你对container的理解? 51 | 52 | 1)Container作为资源分配和调度的基本单位,其中封装了的资源如内存,CPU,磁盘,网络带宽等。 目前yarn仅仅封装内存和CPU 53 | 54 | 2)Container由ApplicationMaster向ResourceManager申请的,由ResouceManager中的资源调度器异步分配给ApplicationMaster 55 | 56 | 3) Container的运行是由ApplicationMaster向资源所在的NodeManager发起的,Container运行时需提供内部执行的任务命令 57 | 58 | ![167964803287336123.jpg](https://i.loli.net/2019/05/21/5ce3a4eed1bfa51728.jpg) 59 | 60 | # Executor启动时,资源通过哪几个参数指定? 61 | 62 | 1)num-executors是executor的数量 63 | 2)executor-memory 是每个executor使用的内存 64 | 3)executor-cores 是每个executor分配的CPU 65 | 66 | -------------------------------------------------------------------------------- /面试/拼多多.md: -------------------------------------------------------------------------------- 1 | # 一面 2 | 3 | ## 网络7层模型 4 | 5 | * 应用层 6 | * 表示层 7 | * 会话层 8 | * 网络层 9 | * 传输层 10 | * 数据链路层 11 | * 物理层 12 | 13 | ## TCP和UDP位于哪一层 14 | 15 | 传输层 16 | 17 | ## Ip寻址流程 18 | 19 | * 根据hosts或dns找到目的主机的ip 20 | * 根据自身ip与掩码计算自身网段并与目的主机比较,发现不在同一网段 21 | * 查找自身arp缓存是否有缺省网关mac地址 22 | * 若没有,则启动arp协议,通过本地网络广播查询,查到则加入arp缓存表 23 | * 数据到达路由接口,根据目的ip查找路由表,发送到下一路由 24 | 25 | ## 进程与线程的区别 26 | 27 | * 进程有独立的内存单元 28 | * 多个线程共享内存,极大提高程序运行效率 29 | * 线程是CPU调度的基本单位,进程是资源分配的最小单位 30 | * 一个进程至少有一个线程 31 | 32 | ## Java调用进程与线程 33 | 34 | ## HashMap结构 35 | 36 | * Node+链表+红黑树 37 | 38 | ## String和Stringbuffer区别 39 | 40 | * String不可变,Stringbuffer可变 41 | 42 | ## 用过哪些设计模式 43 | 44 | * 单例模式 45 | * 模板方法模式 46 | * 工厂模式 47 | * 代理模式 48 | 49 | ## 静态代理实现 50 | 51 | ## 动态代理实现 52 | 53 | ## 观察者模式 54 | 55 | 多个观察者同时监听一个主题,当主题状态有变时,立即通知所有观察者 56 | 57 | ## 观察者模式使用场景 58 | 59 | 发布订阅场景 60 | 61 | ## E-R图 62 | 63 | ## JVM内存区域划分 64 | 65 | * 线程私有 66 | * 程序计数器 67 | * JVM栈 68 | * 本地方法栈 69 | * 线程共享 70 | * 堆 71 | * 方法区/MetaSpace 72 | 73 | ## 一个对象从进入堆区到死亡的全流程 74 | 75 | ## 数据库索引的实现 76 | 77 | ## B树 78 | 79 | ## 数据库两种存储引擎的区别 80 | 81 | * InnoDB与MyISAM的区别 82 | * 锁 83 | * MyISAM不支持行锁,不支持外键 84 | * 索引 85 | * innodb为聚集索引;myisam非聚集索引 86 | * innodb和myisam使用B+树 87 | * 事务 88 | * innodb支持事务 89 | * 存储 90 | * innodb将索引和数据存储在一起 91 | 92 | ## 为什么MyISAM不支持行锁 93 | 94 | # 二面 95 | 96 | ## 用了哪些设计模式 97 | 98 | ## Spring aop怎么实现? 99 | 100 | ## Mysql索引的实现 101 | 102 | ## 使用b 树的理由 103 | 104 | ### B 树做索引比红黑树好在哪里? 105 | 106 | ### 项目里Redis怎么用 107 | 108 | ### 分布式缓存可能出现的问题 109 | 110 | ### 分布式锁 111 | 112 | ### Setnx加锁的原理 113 | 114 | ### 怎么解除分布式锁? 115 | 116 | ### Jvm内存区域划分 117 | 118 | ### 程序计数器的作用 119 | 120 | ### 本地方法栈和虚拟机栈的区别 121 | 122 | ### Gc全流程 123 | 124 | ### Gc算法 125 | 126 | ### 连接过程中什么时候会出现time_wait状态 127 | 128 | ### 为什么要有time_wait状态 129 | 130 | ### 一致性hash了解吗? 131 | 132 | ### 一致性hash的优点? 133 | 134 | ### **设计题:**有一个服务器专门接收大量请求,怎么设计? 135 | 136 | ### 同步和异步的区别 137 | 138 | ### 非阻塞io和阻塞式io的区别 139 | 140 | ### http如何保持连接 141 | 142 | ### 如果不用http,如何保持连接 143 | 144 | ### Volatile 关键字的作用 145 | 146 | ### Volatile 关键字的实现 147 | 148 | * 读时JMM将工作内存数据设置无效,要求从主存中读 149 | * 写时JMM把工作内存中数据刷新到主存,其它线程可以读取就是最新值 150 | 151 | ### 用户态和内核态的区别 152 | 153 | ### lru了解吗? 154 | 155 | ### 怎么实现lru? 156 | 157 | ### 布隆过滤器了解吗? 158 | 159 | ### **算法题:**二叉树前序遍历非递归 160 | 161 | # 2020-08-08 162 | 163 | 一面 164 | 165 | * group by 和 where的区别 166 | * 线程状态转换的函数 167 | * this关键字的实现 168 | 169 | -------------------------------------------------------------------------------- /面试/神舟信息.md: -------------------------------------------------------------------------------- 1 | # instanceof用法? 2 | 3 | 比如:SubClass.instanceof(BaseClass)返回ture or false? 4 | 5 | true 6 | 7 | # js实现打开一个页面 page.jsp,停留3秒钟,自动关闭 8 | 9 | ```javascript 10 | 15 | 16 | ``` 17 | 18 | # 怎么实现web服务器启动时,自动初始化servlet类 19 | 20 | ```xml 21 | 22 | t1 23 | com.base.test.T1 24 | 25 | 1 26 | 27 | ``` 28 | 29 | < load-on-startup>标记web容器是否在启动的时候就加载这个servlet 当值为0或者大于0时,表示web容器在应用启动时就加载这个servlet; 当是一个负数时或者没有指定时,则指示容器在该servlet被选择时才加载; 正数的值越小,启动该servlet的优先级越高 30 | 31 | # 抽象类能不能有构造方法 32 | 33 | 可以 34 | 35 | # java的关键字有哪些? 36 | 37 | volatile,native,goto,instanceof是不是java关键字 38 | 39 | 是 40 | 41 | # 枚举类型的定义代码 42 | 43 | # throws Exception和try{}catch()能同时用吗 44 | 45 | 可以 46 | 47 | # 数据库的ER模型图 48 | 49 | # jsp中的对象(关键字)都有哪些? 50 | 51 | * Out 52 | * Session 53 | * PageContext 54 | * Page 55 | * Request 56 | * Response 57 | * Exception 58 | * Config 59 | 60 | # 用户注册,百度搜索用get还是post? 61 | 62 | post,get 63 | 64 | # 用什么集合类来存储商品信息,理由 65 | 66 | 可用HashSet,商品信息不重复 67 | 68 | # js内置对象 69 | 70 | * Math 71 | * String 72 | * Array 73 | * Boolean 74 | * Number 75 | * Date 76 | 77 | # int a="abc";编译会出错吗 78 | 79 | 会 80 | 81 | # session会不会失效? 82 | 83 | 会,Tomcat默认30分钟 84 | 85 | # sessionid只能通过cookie取得吗 86 | 87 | * 保存session id的方式可以采用cookie,这样在交互过程中浏览器可以自动的按照规则把这个标识发送给服务器。 88 | * 由于cookie可以被人为的禁止,必须有其它的机制以便在cookie被禁止时仍然能够把session id传递回服务器,经常采用的一种技术叫做URL重写,就是把session id附加在URL路径的后面,附加的方式也有两种,一种是作为URL路径的附加信息,另一种是作为查询字符串附加在URL后面。网络在整个交互过程中始终保持状态,就必须在每个客户端可能请求的路径后面都包含这个session id。 89 | 90 | # pageCoding是页面编码还是输出流编码 91 | 92 | * pageEncoding是jsp文件本身的编码 93 | * contentType的charset是指服务器发送给客户端时的内容编码 94 | * JSP要经过两次的“编码”,第一阶段会用pageEncoding,第二阶段会用utf-8至utf-8,第三阶段就是由Tomcat出来的网页, 用的是contentType。 95 | * 第一阶段是jsp编译成.java,它会根据pageEncoding的设定读取jsp,结果是由指定的编码方案翻译成统一的UTF-8 JAVA源码(即.java),如果pageEncoding设定错了,或没有设定,出来的就是中文乱码。 96 | * 第二阶段是由JAVAC的JAVA源码至java byteCode的编译,不论JSP编写时候用的是什么编码方案,经过这个阶段的结果全部是UTF-8的encoding的java源码。 97 | 98 | # JVM 99 | 100 | # 抽象类与接口区别与应用 101 | 102 | # 垃圾回收原理 103 | 104 | # 工厂模式 105 | 106 | # 类加载原理 107 | 108 | # Linux操作系统 109 | 110 | # Spring Boot 111 | 112 | # 线程池 113 | 114 | # 线程池的内存溢出有什么情况 115 | 116 | # HDFS操作 117 | 118 | # Java反射原理 119 | 120 | # 锁 121 | 122 | # VI光标至最后一行 123 | 124 | # linux中日志存在哪个文件 125 | 126 | # linux中环境变量在哪个文件 -------------------------------------------------------------------------------- /数据结构/排序/排序.md: -------------------------------------------------------------------------------- 1 | # [排序算法分类](https://blog.csdn.net/pange1991/article/details/85460755) 2 | 3 | ![这里写图片描述](https://i.loli.net/2020/08/01/KRqZpEjaDlB1fVg.jpg) 4 | 5 | # 排序算法的时间复杂度和空间复杂度 6 | 7 | | **排序算法** | **平均时间复杂度** | **最坏时间复杂度** | **最好时间复杂度** | **空间复杂度** | **稳定性** | 8 | | ---------------- | ------------------ | ------------------ | ------------------ | -------------- | ---------- | 9 | | **冒泡排序** | O(n²) | O(n²) | O(n) | O(1) | 稳定 | 10 | | **直接选择排序** | O(n²) | O(n²) | O(n) | O(1) | 不稳定 | 11 | | **直接插入排序** | O(n²) | O(n²) | O(n) | O(1) | 稳定 | 12 | | **快速排序** | O(nlogn) | O(n²) | O(nlogn) | O(nlogn) | 不稳定 | 13 | | **堆排序** | O(nlogn) | O(nlogn) | O(nlogn) | O(1) | 不稳定 | 14 | | **希尔排序** | O(nlogn) | O(ns) | O(n) | O(1) | 不稳定 | 15 | | **归并排序** | O(nlogn) | O(nlogn) | O(nlogn) | O(n) | 稳定 | 16 | | **计数排序** | O(n+k) | O(n+k) | O(n+k) | O(n+k) | 稳定 | 17 | | **基数排序** | O(N*M) | O(N*M) | O(N*M) | O(M) | 稳定 | 18 | 19 | # 冒泡排序 20 | 21 | ![img](https://i.loli.net/2020/08/01/osJfAyS4GNnUl2g.gif) 22 | 23 | ```java 24 | //array[]为待排序数组,n为数组长度 25 | void BubbleSort(int array[], int n) 26 | { 27 | int i, j, k; 28 | for(i=0; iarray[j+1]) 32 | { 33 | k=array[j]; 34 | array[j]=array[j+1]; 35 | array[j+1]=k; 36 | } 37 | } 38 | } 39 | ``` 40 | 41 | # 直接选择排序 42 | 43 | ```java 44 | //array[]为待排序数组,n为数组长度 45 | void selectSort(int array[], int n) 46 | { 47 | int i, j ,min ,k; 48 | for( i=0; iarray[j]) 54 | { 55 | min=j; 56 | } 57 | } 58 | if(min!=i) 59 | { 60 | k=array[min]; 61 | array[min]=array[i]; 62 | array[i]=k; 63 | } 64 | } 65 | } 66 | ``` 67 | 68 | # 直接插入排序 69 | 70 | ![img](https://i.loli.net/2020/08/01/Xk9NB2O3s1wnuJl.gif) 71 | 72 | # 快速排序 73 | 74 | ![img](https://i.loli.net/2020/08/01/nVHdjhDkUL73MwP.gif) 75 | 76 | # 堆排序 77 | 78 | ![img](https://i.loli.net/2020/08/01/49DWu7aelXnMPLf.gif) -------------------------------------------------------------------------------- /spark/算法.md: -------------------------------------------------------------------------------- 1 | # 推荐算法介绍 2 | * 基于关系型规则的推荐 3 | 4 | ``` 5 | 购买产品A,有多大机率购买产品B 6 | ``` 7 | 8 | * 基于内容的推荐 9 | 10 | ``` 11 | 分析网页内容自动分类,再将用户自动分类 12 | 将新进已分类网页推荐给该群感兴趣的用户 13 | ``` 14 | 15 | * 人口统计式的推荐 16 | 17 | ``` 18 | 将用户按其个人属性作为分类指针 19 | ``` 20 | 21 | * 协同过滤式的推荐 22 | 23 | ``` 24 | 通过观察到的所有用户对产品的评分,来推断用户喜好 25 | ``` 26 | 27 | # 创建推荐引擎 28 | #### 使用spark-shell导入ml-100k数据 29 | ##### 导入ml-100k 数据 30 | 31 | ``` 32 | val rawUserData = sc.textFile("file:///home/sotowang/Templates/ml-100k/u.data") 33 | ``` 34 | 35 | #### 查看导入的数据 36 | ##### 查看u.data数据的第一条数据 37 | 38 | ``` 39 | rawUserData.first() 40 | ``` 41 | 42 | ##### 查看前五条数据 43 | 44 | ``` 45 | rawUserData.take(5).foreach(println) 46 | ``` 47 | 48 | ##### 查看userid 字段的统计信息 49 | 50 | ``` 51 | rawUserData.map(_.split('\t')(0).toDouble).stats() 52 | ``` 53 | 54 | ##### 查看item id 字段的统计信息 55 | 56 | ``` 57 | rawUserData.map(_.split('\t')(1).toDouble).stats() 58 | ``` 59 | 60 | ##### 查看rate字段的统计信息 61 | 62 | ``` 63 | rawUserData.map(_.split('\t')(2).toDouble).stats() 64 | ``` 65 | 66 | #### 使用ALS.train进行训练 67 | ##### 导入相关Lib 68 | 69 | ``` 70 | import org.apache.spark.mllib.recommendation.ALS 71 | import org.apache.spark.mllib.recommendation.Rating 72 | ``` 73 | 74 | ##### 读取rawUserData的前3个字段 75 | 76 | ``` 77 | val rawRatings = rawUserData.map(_.split('\t').take(3)) 78 | ``` 79 | 80 | ##### 准备ALS训练数据 81 | 82 | ``` 83 | val ratingsRDD = rawRatings.map{ 84 | case Array(user, movie, rating) 85 | => Rating(user.toInt,movie.toInt,rating.toDouble) 86 | } 87 | ``` 88 | 89 | ##### 使用ALS.train命令进行训练 90 | 91 | ``` 92 | val model = ALS.train(ratingsRDD,10,10,0.01) 93 | ``` 94 | 95 | #### 使用模型进行推荐 96 | ##### 针对用户推荐电影 97 | 98 | ``` 99 | model.recommendProducts(196,5).mkString("\n") 100 | ``` 101 | 102 | ##### 查看针对用户推荐产品的评分 103 | 104 | ``` 105 | model.predict(196,624) 106 | ``` 107 | 108 | ##### 针对电影推荐给用户 109 | 110 | ``` 111 | model.recommendUsers(464,5).mkString("\n") 112 | ``` 113 | 114 | #### 显示推荐的电影名称 115 | ##### 创建电影ID与名称的对照表 116 | 117 | ``` 118 | val itemRDD = sc.textFile("file:///home/sotowang/Templates/ml-100k/u.item") 119 | val movieTitle = itemRDD.map(line=>line.split("\\|").take(2)).map(array=>(array(0).toInt,array(1))).collectAsMap() 120 | ``` 121 | 122 | ##### 显示对照表的前5条数据 123 | 124 | ``` 125 | movieTitle.take(5).foreach(println) 126 | ``` 127 | 128 | ##### 查询电影名称 129 | 130 | ``` 131 | movieTitle(146) 132 | ``` 133 | 134 | ##### 显示5条推荐的电影名称 135 | 136 | ``` 137 | model.recommendProducts(196,5).map(rating => 138 | (rating.product,movieTitle(rating.product),rating.rating)).foreach(println) 139 | ``` 140 | 141 | ![DeepinScreenshot_select-area_20181016105525.png](https://i.loli.net/2018/10/16/5bc5532c31603.png) 142 | -------------------------------------------------------------------------------- /Java/泛型.md: -------------------------------------------------------------------------------- 1 | # 为什么需要泛型 2 | 3 | * 我只需要定义一次类,就可以被“任何”类型使用,而不是对每一种类型定义一个类 4 | * 我的泛型只能保存我指明的类型,而不是放一堆object引用。 5 | 6 | # 泛型通配符 7 | 8 | > 泛型通配符在声明局部变量时是没有意义的.但当为一个方法声明一个参数时,是非常最要的 9 | 10 | ```properties 11 | - ? 不确定的Java类型 12 | - T(type) 具体的一个Java类型 13 | - K V(key value) java键值中的Key Value 14 | - E(element) 代表Element 15 | ``` 16 | 17 | * 上界通配符 18 | 19 | * 如果传入的类型不是E或者E的子类.编译不成功 20 | * 泛型中可以使用E的方法,否则还要强转成E才能使用 21 | 22 | * 下界通配符 23 | 24 | * 泛型中的参数必须是E或者E的父类 25 | 26 | * ?与T的区别 27 | 28 | * 通过T确保泛型参数一致性 29 | 30 | * T可以多重限定 31 | 32 | ```java 33 | public static void test(T t) 34 | //T必须是A和B的公有子类型 35 | //t具有所限定的方法和属性 36 | //对于通配符?,因它不是一个确定的类型,所以不能多重限定 37 | ``` 38 | 39 | * ?可以使用super限定 40 | 41 | ```java 42 | // 可以 43 | T t = operate(); 44 | // 不可以 45 | ? car = operate(); 46 | ``` 47 | 48 | 49 | # [泛型擦除](https://juejin.im/post/5e61fb10e51d4526d6406cb0) 50 | 51 | ## 泛型擦除是什么? 52 | 53 | * 这个所谓的泛型`T`最后会被转化为一个`Object`,最后又通过强制转化来进行一个转变。从这里我们也就能够知道为什么我们的数据从前面过来的时候,`String`类型数据能够直接被`Integer`进行接收了。 54 | 55 | ## [为什么要类型擦除?](http://www.pulpcode.cn/2017/12/30/why-java-generic-use-type-eraser/) 56 | 57 | * 向后兼容。**java在一开始都是不支持泛型的**。为了让一个不支持泛型的语言支持泛型,只有两条路可以走,要么以前的非泛型容器保持不变,然后平行的增加一套泛型化的类型。要么直接把已有的非泛型容器扩展为泛型。不添加任何新的泛型版本。 58 | 59 | * 避免JVM大换血,如果 JVM 将泛型类型延续到运行期,那么到运行期时 JVM 就需要进行大量的重构工作了,提高了运行期的效率。 60 | 61 | 为什么使用类型擦除就能保持向后兼容呢 62 | 63 | * 我形象的理解为,之前非泛型的写法,编译成的虚拟机汇编码块是A,之后的泛型写法,只是在A的前面,后面“插入”了其它的汇编码,而并不会破坏A这个整体。这才算是既把非泛型“扩展为泛型”,又兼容了非泛型。 64 | 65 | ## 带来的问题 66 | 67 | **(1) 强制类型转化** 68 | 69 | 这个问题的结果我们已经在上述文章中提及到了,通过反射的方式去进行插入的时候,我们的数据就会发生错误。 70 | 71 | 如果我们在一个`List`中在不知情的情况下插入了一个`String`类型的数值,那这种重大错误,我们该找谁去说呢。 72 | 73 | **(2)引用传递问题** 74 | 75 | 上面的问题中,我们已经说过了`T`将在后期被转义成`Object`,那我们对引用也进行一个转化,是否行得通呢? 76 | 77 | ```java 78 | List listObject = new ArrayList(); 79 | List listObject = new ArrayList(); 80 | ``` 81 | 82 | 如果你这样写,在我们的检查阶段,会报错。但是从逻辑意义上来说,其实你真的有错吗? 83 | 84 | **假设说我们的第一种方案是正确的**,那么其实就是将一堆`Object`数据存入,然后再由上面所说的强制转化一般,转化成`String`类型,听起来完全ok,因为在`List`中本来存储数据的方式就是`Object`。但其实是会出现`ClassCastException`的问题,因为`Object`是万物的基类,但是强转是为子类向父类准备的措施。 85 | 86 | **再来假设说我们的第二种方案是正确的**,这个时候,根据上方的数据`String`存入,但是有什么意义存在呢?最后都还是要成`Object`的,你还不如就直接是`Object`。 87 | 88 | ## 解决方案 89 | 90 | 其实很简单,如果看过一些公开课想来就见过这样的用法。 91 | 92 | ```java 93 | public class Part { 94 | 95 | private T val; 96 | 97 | public T getVal() { 98 | return val; 99 | } 100 | 101 | public void setVal(T val) { 102 | this.val = val; 103 | } 104 | } 105 | 106 | ``` 107 | 108 | 相比较于之前的`Part`而言,他多了``的语句,==其实这就是将基类重新规划的操作,就算被编译,虚拟机也会知道将数据转化为`Parent`而不是直接用`Object`来直接进行替代==。 109 | 110 | ## 应用场景 111 | 112 | * ``继承型 -------------------------------------------------------------------------------- /面试/今日头条.md: -------------------------------------------------------------------------------- 1 | 作者:Commando20180403011197 2 | 3 | 链接:https://www.nowcoder.com/discuss/142963?type=2&order=0&pos=5&page=1 4 | 5 | # 一面 6 | 7 | ``` 8 | 挑了HDFS让我讲一下。 9 | NN和DN。 10 | HA的实现 11 | zookeeper的原理,zk是如何保证一致性的,zk是如何判断session超时,connection超时的。如何触发回调。 12 | client和HDFS文件的读写过程,延迟太高,怎么解决。我当时脑子一蒙,直接说了设计的就是高吞吐量的文件系统。 13 | yarn的结构,RM和NM的交互,如何分配任务的。 14 | yarn在什么层面调度,和k8s和mesos有什么区别,内存调度是什么怎么调度的,如果考虑CPU怎么调度的。如何实现隔离的,Control group 和Namespace是怎么回事。 15 | 手撕算法,链表排序。 16 | ``` 17 | 18 | ### zookeeper的原理,zk是如何保证一致性的,zk是如何判断session超时,connection超时的。如何触发回调。 19 | 20 | [ZooKeeper原理与应用](https://www.jianshu.com/p/84ad63127cd1) 21 | 22 | ZooKeeper是一个典型的**分布式数据一致性**的**解决方案**。分布式应用程序可以基于它实现诸如**数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master选举、分布式锁和分布式队列**等功能。ZooKeeper可以保证如下分布式一致性特性。 23 | 24 | - **顺序一致性** 25 | 从同一个客户端发起的事务请求,最终将会严格按照其**发起顺序**被应用到ZooKeeper中。 26 | - **原子性** 27 | 所有事务请求的结果在集群中**所有机器**上的应用情况是一致的,也就是说要么整个集群所有集群**都成功**应用了某一个事务,要么**都没有**应用,一定**不会出现**集群中部分机器应用了该事务,而另外一部分没有应用的情况。 28 | - 单一视图 29 | **无论**客户端连接的是**哪个**ZooKeeper服务器,其看到的**服务端数据模型**都是**一致**的。 30 | - **可靠性** 31 | 一旦服务端成功地应用了一个事务,并完成对客户端的响应,那么该事务所引起的服务端状态变更将会**被一直保留**下来,除非有另一个事务又对其进行了变更。 32 | - **实时性** 33 | 通常人们看到实时性的第一反应是,一旦一个事务被成功应用,那么客户端能够立即从服务端上读取到这个事务变更后的最新数据状态。这里需要注意的是,ZooKeeper**仅仅保证**在**一定的时间段内**,客户端**最终**一定能够从服务端上读取到**最新**的数据状态。 34 | 35 | # 二面 36 | 37 | ``` 38 | 面的计算机基础: 39 | 上来手撕,剑指原题,两个栈实现一个队列。 40 | 问了一下转专业的经历。 41 | 讲个简历的项目。 42 | 操作系统中的进程和线程的区别。 43 | JVM的内存模型说一下,堆,栈,永久区,GC。 44 | Java的多线程。 45 | Hadoop的MR和Spark有什么区别,为什么Spark有优势。 46 | TCP 47 | 用过什么数据库啊,然后就没往深了问了。 48 | 手推神经网络上的反向传播,把链式求导写出来,激活函数sigmoid。 49 | 介绍一下LSTM,和GRU的区别。 50 | 过。 51 | 52 | ``` 53 | 54 | # 三面 55 | 56 | ``` 57 | 技术深度,问得特别特别细 58 | 看过源码对吧,hadoop的HDFS,Yarn,MapReduce源码讲讲,精确到方法和类。 59 | 客户端和NN的通信过程,和DN的通信过程。 60 | HA中的选举过程,如何防止脑裂,为什么需要fencing,SSH连不上怎么办。 61 | checkpoint的过程 62 | yarn的状态机和epoll 63 | yarn的公平调度器和容量调度器和FIFO 64 | yarn抢占 65 | MapReduce全过程,分片怎么读的,为什么用快排,换别的行不行,多路归并怎么实现的,环形缓冲区怎么实现的。 66 | 场景,很多牛逼的电脑,大CPU大内存,网卡超烂,如何优化? 强制本地化,选高压缩的序列化格式,核心就是尽量减少网络IO。 67 | 场景,一个加载在内存里的HashMap,Key和Value全是int,从硬盘读进来只做查询不做修改,不考虑查询效率,尽可能提高空间效率,稍微考虑一下时间效率。从JVM调优到数据结构到GC到。。。。 68 | 手撕,实现一个线程池。 69 | 在spark和hadoop中如何处理数据倾斜。 70 | spark的调度过程,DAGScheduler如何划分stage,TaskScheduler如何调度任务的。Spark的shuffle是什么样的,怎么优化的。 71 | 评价一下Hadoop和Spark的代码风格,我曹,我随便说了说,怕送命题。幸好我说完了他就自己说了,疯狂点头。 72 | Java的多线程,讲讲锁。synchronized和reentrantlock的区别。讲讲阻塞队列,volatile 73 | synchronized为啥是非公平的,这个我真不知道,回来一顿狠查,赶紧记住了。 74 | Java的Obejct谈谈 75 | Java的容器谈谈 76 | Java的NIO用得咋样,不咋样。。。那就不聊了。 77 | MPI聊聊 78 | 你Scala用得怎么样呀,Python怎么样啊 79 | 设计,设计一个RPC框架,我看你简历上做过,谈谈思路,观察者模式讲一下,并发容器。 80 | 设计,现在有一个RPC框架,需要使用线程池,多次复用socket,TCP,怎么传递命令。变相考hadoop,使用操作码。 81 | 结束。这一面的面试官超强,被压着打。 82 | 83 | ``` 84 | # 四面 85 | 86 | ``` 87 | Um.....和我这个岗没有一毛钱关系。 88 | 手写一个leetcode hard,就是两个数组,找全局中间数那个。 89 | 问问搜索。 90 | 如何构建倒排索引 91 | BM25 92 | 如何加速查询,WAND算法细节。 93 | 倒排索引的log时间合并 94 | 如何评价一次query,设计一个机器学习模型,如何设计这样的模型,如何提取feature,用什么模型 95 | 如何做查询补全 Trie 96 | 设计一个查询缓存 97 | 如何对倒排索引进行空间压缩,我先说了OptPForDelta 98 | 如何选择最优分裂点,抽样,然后算。 99 | 手撕个代码实现一下 100 | 如果不抽样,你这样是全局最优吗?我说是啊,他说不是。。。。对每一个算一个。好吧,他说得对。 101 | 还有别的优化方式吗 Variable Byte 102 | 聊家常。。。。出了门感觉人生都灰暗了,跪 103 | ``` 104 | -------------------------------------------------------------------------------- /面试/投资银行.md: -------------------------------------------------------------------------------- 1 | # 来自投资银行面试题 2 | 3 | ## 在多线程环境中使用HashMap会有什么问题?在什么情况下使用get()方法会产生无限循环? 4 | 5 |  HashMap 扩容的时候会调用 `resize()` 方法,就是这里的并发操作容易在一个桶上形成环形链表;这样当获取一个不存在的 key 时,计算出的 index 正好是环形链表的下标就会出现死循环。![img](https://i.loli.net/2019/05/08/5cd1d2c4ede54.jpg) 6 | 7 | ## 不重写Bean的hashCode()方法是否会对性能带来影响? 8 | 9 | 如果一个计算hash的方法写得不好,直接的影响是,当向HashMap中添加元素的时候会更频繁地造成冲突,因此最终增加了耗时。但是自从Java 8开始,这种影响不再像前几个版本那样显著了,因为当冲突的发生超出了一定的限度之后,**链表类的实现将会被替换成二叉树(binary tree)实现**,这时你仍可以得到O(logN)的开销,优于链表类的O(n)。 10 | 11 | 12 | 13 | ## 对于一个不可修改的类,它的每个对象是不是都必须声明成final的? 14 | 15 | 不尽然,因为你可以通过将成员声明成非final且private,并且不要在除了构造函数的其他地方来修改它。不要为它们提供setter方法,同时不会通过任何函数泄露出对此成员的引用。需要记住的是,把对象声明成final仅仅保证了它不会被重新赋上另外一个值,你**仍然可以通过此引用来修改引用对象的属性**。这一点是关键,面试官通常喜欢听到你强调这一点。 16 | 17 | ## String的substring()方法内部是如何实现的? 18 | 19 | substring方法**通过原字符串创建了一个新的对象**,否则你的回答肯定是不能令人满意的。这个问题也经常被拿来测试应聘者对于substring()可能带来的内存泄漏风险是否有所了解。直到Java 1.7版本之前,substring会保存一份原字符串的字符数组的引用,这意味着,如果你从1GB大小的字符串里截取了5个字符,而**这5个字符也会阻止那1GB内存被回收**,因为这个引用是强引用。 20 | 21 | 到了Java 1.7,这个问题被解决了,原字符串的字符数组已经不再被引用,但是这个改变也使得substring()创建字符串的操作更加耗时,以前的开销是O(1),现在最坏情况是O(n)。 22 | 23 | ## 能否写一个单例模式,并且保证实例的唯一性? 24 | 25 | ```java 26 | 1 public static Singleton getInstance(){ 27 | 2 if (instance == null) 28 | 3 synchronized(instance){ 29 | 4 if(instance == null) 30 | 5 instance = new Singleton(); 31 | 6 } 32 | 7 return instance; 33 | 8 } 34 | ``` 35 | 36 | ## Executor.submit()和Executor.execute()这两个方法有什么区别? 37 | 38 | 前者**返回一个Future对象**,可以通过这个对象来获得工作线程执行的结果。 39 | 40 | 当我们考察异常处理的时候,又会发现另外一个不同。 41 | 42 | 当你使用execute提交的任务抛出异常时,此异常将会交由未捕捉异常处理过程来处理(uncaught exception handler),当你没有显式指定一个异常处理器的话,**默认情况下仅仅会通过System.err打印出错误堆栈**。 43 | 44 | 当你用submit来提交一个任务的时候,这个任务一旦抛出异常(无论是否是运行时异常),那这个异常是任务返回对象的一部分。对这样一种情形,当你**调用Future.get()方法的时候,这个方法会重新抛出这个异常,并且会使用ExecutionException进行包装**。 45 | 46 | ## 工厂模式和抽象工厂模式有何不同? 47 | 48 | 抽象工厂模式提供了多一级的抽象。**不同的工厂类都继承了同一个抽象工厂方法,但是却根据工厂的类别创建不同的对象**。例如,AutomobileFactory, UserFactory, RoleFactory都继承了AbstractFactory,但是每个工厂类创建自己对应类型的对象。下面是工厂模式和抽象工厂模式对应的UML图。 49 | 50 | ## 能否写一段用Java 4或5来遍历一个HashMap的代码? 51 | 52 | ```java 53 | Map map = new HashMap(); 54 | 55 | for (Map.Entry entry : map.entrySet()) { 56 | 57 | System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue()); 58 | 59 | } 60 | ``` 61 | 62 | ## 我们要同步整个getInstance()方法,还是只同步getInstance()方法中的关键部分? 63 | 64 | 仅仅同步关键部分(Critical Section)。这是因为,如果我们同步整个方法的话,每次有线程调用getInstance()方法的时候都会等待其他线程调用完成才行,即使在此方法中并没有执行对象的创建操作。换句话说,我们只需要同步那些创建对象的代码,而创建对象的代码只会执行一次。**一旦对象创建完成之后,根本没有必要再对方法进行同步保护了**。事实上,从性能上来说,对方法进行同步保护这种编码方法非常要命,因为它会使性能降低10到20倍。 65 | 66 | 67 | 68 | ## 创建字符串对象的时候,使用字面值和使用new String()构造器这两种方式有什么不同? 69 | 70 | 当我们使用new String构造器来创建字符串的时候,字符串的值会在堆中创建,而不会加入JVM的字符串池中。相反,**使用字面值创建的String对象会被放入堆的PermGen段中**。例如: 71 | 72 | > String str=new String(“Test”); 73 | 74 | 这句代码创建的对象str不会放入字符串池中,我们需要显式调用String.intern()方法来将它放入字符串池中。仅仅当你使用字面值创建字符串时,Java才会自动将它放入字符串池中,比如:String s=”Test”。顺便提一下,这里有个容易被忽视的地方,当我们将参数“Test”传入构造器的时候,这个参数是个字面值,因此它也会在字符串池中保存另外一份。想了解更多关于字面值字符串和字符串对象之间的差别,请看这篇文章。 75 | 76 | ## 什么是不可修改对象(ImmutableObject)?你能否写一个例子? 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /spring/springboot/springboot面试.md: -------------------------------------------------------------------------------- 1 | # Spring Boot自动配置实现 2 | 3 | * Spring Boot 项目启动注解:@SpringBootApplication 4 | * @Configuration 5 | * @ComponentScan 6 | * @EnableAutoConfiguration 7 | * 实现自动配置入口 8 | * 该注解通过@Import注解导入了AutoConfigurationImportSelector,在该类中加载META-INF/spring.factories的配置信息 9 | * 筛选出以EnableAutoConfiguration为key的数据,加载到IOC容器中 10 | 11 | # Spring Cache三种常用的缓存注解和意义 12 | 13 | * @Cacheable 14 | * 声明方法是可缓存的,将结果存储到缓存中,后续调用直接取值 15 | * @CachePut 16 | * 每次都会执行该方法,将执行结果以键值对的形式存入指定缓存 17 | * @CacheEvict 18 | * 标在需要清除缓存元素的方法或类上 19 | 20 | # JPA 和 Hibernate 有哪些区别? 21 | 22 | JPA是一种规范,只提供一些相关接口,不能直接使用,Hibernate是JPA的一个实现集 23 | 24 | # JPA 可以支持动态 SQL 吗? 25 | 26 | JPA根据实体类注解创建对应表和字段,若需要动态创建表或字段, 27 | 28 | * 需要动态构建对应的实体类 29 | * 再重新调用JPA刷新整个Entity 30 | 31 | # [Spring循环依赖](https://blog.csdn.net/github_38687585/article/details/82317674) 32 | 33 | * Spring循环依赖的理论依据 34 | * Java基于引用传递,当我们获取到对象的引用时,对象的field和属性是可以延后设置的 35 | * Spring单例对象的初始化过程:实例化,填充属性,初始化 36 | * `createBeanInstance`实例是调用对应构造方法,Spring中xml中的preperty没有进 37 | * `populate`填充属性,对Spring xml中的属性进行填充 38 | * `initializeBean`,调用Spring xml中指定的init方法或AfterPropertiesSet方法 39 | * 循环依赖发生在第一步和第二步 40 | 41 | * 循环依赖产生的结果 42 | * Spring加载Bean时会以正常顺序创建Bean,当存在循环依赖时,Spring将无法决定创建哪个Bean 43 | * Spring将产生`BeanCurrentlyInCreationException`异常 44 | * 若双方使用setter注入或属性值注入,Spring可自动解决循环依赖问题 45 | * 若双方使用构造函数注入或**主Bean**(Spring先加载的Bean)使用构造函数注入,则无法解决依赖注入,程序无法启动 46 | 47 | * 解决方案 48 | * 重新设计结构,消除循环依赖 49 | * 使用注解 `@Lazy `懒加载(可能会掩盖问题) 50 | * 使用`Setter/Field`注入,当依赖最终被使用时才进行注入 51 | * 使用`PostConstruct` 52 | * 实现`ApplicationContextAware`与`InitializingBean` 53 | 54 | ## 三级缓存 55 | 56 | ```java 57 | /** Cache of singleton objects: bean name --> bean instance */ 58 | 59 | private final Map singletonObjects = new ConcurrentHashMap(256); 60 | 61 | /** Cache of singleton factories: bean name --> ObjectFactory */ 62 | 63 | private final Map> singletonFactories = new HashMap>(16); 64 | 65 | /** Cache of early singleton objects: bean name --> bean instance */ 66 | 67 | private final Map earlySingletonObjects = new HashMap(16); 68 | ``` 69 | 70 | * 指 71 | * `singletonObjects`单例对象Cache(一级) 72 | * 完成初始化的单例对象的cache(一级缓存) 73 | * `earlySingletonObjects`提前曝光的单例对象cache(二级) 74 | * 完成实例化但是尚未初始化的,提前暴光的单例对象的Cache (二级缓存) 75 | * `singletonFactories`单例工厂Cache(三级) 76 | * 进入实例化阶段的单例对象工厂的cache 77 | 78 | * 三级缓存用法 79 | 80 | * `protected Object getSingleton(String beanName, boolean allowEarlyReference) ` 81 | 82 | * Spring从`singletonObjects`(一级缓存)中获取 83 | * 若获取不到且对象在创建中,则从`earlySingletonObjects`(二级缓存)中获取 84 | * 若获取不到则从`singletonFactories`(三级缓存)中获取,若获取到了则将`singletonObject`放入到`earlySingletonObjects`,即将三级缓存升到二级缓存中 85 | 86 | * 为何需要三级而不是二级 87 | * 将三级缓存放到二级缓存时,会是否有`SmartInstantiationAwareBeanPostProcessor`这样的后置处理器,这里是给用户提供接口扩展的(循环使用?) 88 | 89 | ## [第二级缓存earlySingletonObjects的作用](https://juejin.im/post/5dbb9fdef265da4d4c202483#heading-10) 90 | 91 | * 既然有了三级缓存了,为什么还要设计二级缓存呢? 92 | * 可能很多人觉得二级缓存是个鸡肋,可有可无,其实这是Spring大量使用缓存提高性能的一点体现。每次都通过工厂去拿,需要遍历所有的后置处理器、判断是否创建代理对象,而判断是否创建代理对象本身也是一个复杂耗时的过程。设计二级缓存避免再次调用调用`getEarlyBeanReference`方法,提高bean加载流程。只能说,Spring是个海洋。 93 | 94 | ## 缓存生命周期 -------------------------------------------------------------------------------- /hadoop/HBase.md: -------------------------------------------------------------------------------- 1 | # hbase 的特点是什么 2 | 3 |  (1) Hbase一个分布式的基于列式存储的数据库,基于Hadoop的hdfs存储,zookeeper进行管理。 4 | 5 | (2) Hbase适合存储半结构化或非结构化数据,对于数据结构字段不够确定或者杂乱无章很难按一个概念去抽取的数据。 6 | 7 | (3) Hbase为null的记录不会被存储. 8 | 9 | (4)基于的表包含rowkey,时间戳,和列族。新写入数据时,时间戳更新,同时可以查询到以前的版本. 10 | 11 | (5) hbase是主从架构。hmaster作为主节点,hregionserver作为从节点。 12 | 13 | 为了运行Hbase,Zookeeper是必须的,zookeeper 是一个用来进行分布式协调的服务,这些**服务包括配置服务,维护元信息和命名空间服务**。 14 | 15 | # Hbase和hive 有什么区别 16 | 17 | Hive和Hbase是两种基于Hadoop的不同技术 18 | 19 | Hive是一种类SQL 的引擎,并且运行MapReduce 任务, 20 | 21 | Hbase 是一种在Hadoop之上的NoSQL的Key/vale数据库。 22 | 23 | Hive 可以用来进行统计查询,HBase 可以用来进行实时查询,数据也可以从Hive 写到Hbase,设置再从Hbase 写回Hive。 24 | 25 | 26 | 27 | # HBase 28 | 29 | - HBase Table组成 30 | 31 | Table = RowKey + Family+Column+Timestamp+value 32 | 33 | - 数据存储模式 34 | 35 | (Table,Rowkey,Family。Column,Timestamp)-> Value 36 | 37 | ## LSM树存储思想 38 | 39 | 0级:日志/内存 40 | 41 | 1级:日志/内存 42 | 43 | 2级:合并(Compaction) 44 | 45 | ![深度截图_选择区域_20190524135424.png](https://i.loli.net/2019/05/24/5ce7871df3b5c97238.png) 46 | 47 | - Region 48 | 49 | 负载均衡和分布式存储的最小单元 50 | 51 | - HFile 52 | 53 | 存储的最小单元 54 | 55 | Data Block 56 | 57 | - WAL 58 | 59 | HLog: 实现WAL的类,一台服务器(RegionServer)只有一个 60 | 61 | ## HBase Compaction 62 | 63 | 将小文件合并成大文件,方便管理,打开关闭小文件太耗时。 64 | 65 | * MinorCompaction 66 | 67 | * MajorCompaction(大合并) 68 | 69 | 合并成一个StoreFile 70 | 71 | ![深度截图_选择区域_20190524144412.png](https://i.loli.net/2019/05/24/5ce792cc1300183045.png) 72 | 73 | * 触发时机 74 | 75 | ## 数据存储流程 76 | 77 | ### 写数据流程 78 | 79 | 1. HBase Client请求zookeeper,确定meta表(HBase元数据表)所在regionSever地址 80 | 2. 根据rowkey找到归属的regionserver 81 | 3. 提交put,delete请求,put默认放到本地buffer(默认2M),超过阈值将提交至服务器 82 | 4. 加锁(RowLock)保证行的原子操作,把数据分别写到HLog和MemStore上一份,释放行锁,日志同步 83 | 5. MemStore达到一个阈值(64M)后则把数据刷成一个StoreFile文件。若MemStore中的数据有丢失,则可以总HLog上恢复 84 | 6. 当多个StoreFile文件达到一定的大小后,会触发Compact合并操作,合并为一个StoreFile,这里同时进行版本的合并和数据删除。 85 | 7. 当Compact后,逐步形成越来越大的StoreFIle后,会触发Split操作,把当前的StoreFile分成两个,这里相当于把一个大的region分割成两个region 86 | 87 | ### 读数据流程 88 | 89 | 1. HBase请求zookeeper,从zookeeper中找到meta表region的位置,然后读取meta表中的数据。meta中又存储了用户表的region信息。 90 | 2. 根据namespace、表名和rowkey在meta表中找到对应的region信息 91 | 3. 找到这个region对应的regionserver 92 | 4. 查找对应的region 93 | 5. 先从MemStore找数据,如果没有,再到StoreFile上读(为了读取的效率)。 94 | 95 | ## api 96 | 97 | ### put(Put put) 98 | 99 | * 构造方法 100 | 101 | Put(byte[] row) 102 | 103 | * 填充值 104 | 105 | Put add(byte[] family,byte[] qualifier,byte[] value) 106 | 107 | ### delete(Delete delete) 108 | 109 | * 构造方法 110 | 111 | Dlelete(byte[] row) 112 | 113 | * 填充值 114 | 115 | Delete deleteFamily(byte[] family) 116 | 117 | Delete deleteColumns(byte[] family,byte[] qualifer) 118 | 119 | ### Result get(Get get) 120 | 121 | * 构造方法 122 | 123 | Get(byte[] row) 124 | 125 | * 填充值 126 | 127 | Get addFamily(byte[] family) 128 | 129 | Get addColumn(byte[] family,byte[] qualifier) 130 | 131 | Get setMaxVersions() 132 | 133 | Get setTimeRange(long minStamp,long maxStamp) 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | -------------------------------------------------------------------------------- /面试/阿里.md: -------------------------------------------------------------------------------- 1 | # 一 2 | 3 | ## 一面 4 | 5 | ### Java容器 6 | 7 | ### 多线程,线程池 8 | 9 | ### java的序列化方式,hadoop的序列化方式,Avro,parquet,transient关键字 10 | 11 | ### spark的原理 12 | 13 | ### 设计模式,观察者,hadoop用了啥 14 | 15 | ### 业务题,拿spark实现个业务逻辑,拿嘴说就行。map然后reducebykey 16 | 17 | ## 二三面 18 | 19 | 说个项目,问我项目实现细节。工程细节,你这怎么加速,Geohash怎么用的。并对我的辣鸡项目表示了鄙视。 20 | spark streaming和storm,flink的区别 21 | 各种分布式计算框架的区别 22 | storm如何处理反压,如何保证流的可靠性的 23 | flink会吗,不会 24 | hbase的row key设计,我现在就要范围查询value怎么设计。 25 | yarn里面机器崩了,怎么让任务接着算。。。我说了重启nodemanager重算这个分片,如果这个分片也不想重算呢,接着算,没这功能没说出来。回来想想其实还是应该能说个思路的。 26 | 说了AppMaster的故障怎么实现的HA 27 | zookeeper是如何选举新的Active Namenode,没仔细说,说了个原理他又不继续问了,后悔。 28 | 大数算法:10亿个int查重,讲思路,布隆过滤,mapreduce,bitmap,算法的复杂度说说 29 | 机器学习竞赛跟我说说,讲了特征工程,提了GBDT,然而我觉得他并不知道GBDT是啥,讲完和我说你这就是java的hello world啊。主要也是自己讲的不好,我也很是哽咽 30 | 31 | # [二](https://www.nowcoder.com/discuss/369371) 32 | 33 | ## MySql如何查看表用的引擎 34 | 35 | > Mysql->show engines 36 | 37 | ## 数据库连接池作用 38 | 39 | * 类比线程池,增加连接复用,同一资源管理,降低时间空间开销 40 | * 资源重用,避免了数据库连接频繁建立、关闭的开销 41 | * 更快的系统响应速度,直接从连接池中获取连接,响应速度加快 42 | * 控制资源的使用。如果不使用连接池,每次访问数据库都需要创建一个连接,这样系统的稳定性受系统连接需求影响很大,很容易产生资源浪费和高负载异常。 43 | 44 | ## 场景题 45 | 46 | ``` 47 | 公司要为一个历史日志文件做一个数据库表格,用Innodb还是MyISAM好? 48 | ``` 49 | 50 | * 我觉得使用MyISAM更好,因为需要更频繁地读,写操作较少 51 | 52 | ``` 53 | 如果联合索引a属性有100情况,b属性有10000情况,主键索引应该建在那个上面? 54 | ``` 55 | 56 | * 建在 b上好 57 | 58 | ## MyISAM和InnodB引擎的区别 59 | 60 | ## B+树 61 | 62 | ## 文件结构.indb .MyI .Myd 63 | 64 | * `.indb`是innodb引擎产生的文件,存储数据和索引 65 | * `.myi`是MyISAM引擎产生的文件,存储索引 66 | * `.Myd`是MyISAM引擎产生的文件,存储数据 67 | 68 | ## 常用的集合类 69 | 70 | * 扯到了hashMap的数据结构,数组+链表+红黑树 71 | 72 | ## HashMap put方法 73 | 74 | * 若HashMap未初始化,则初始化 75 | * 对Key求Hash,再计算下标 76 | * 若无碰撞,直接入桶,若碰撞,则以链表形式插入 77 | * 红黑树转换 78 | 79 | ## ConcurrentHashMap源码 put方法 80 | 81 | * Hash值定位表位置 82 | * CAS+Synchronized锁插入元素 83 | * 若hash值为-1,则正在扩容,线程加入扩容 84 | 85 | ## equals和HashCode 86 | 87 | * equals相同则HashCode必相同,反之不成立 88 | * hashCode的存在使得对象比较时,只用比较Hash值而不用一个个比较,效率较高 89 | * 如Set集合插入时判断是否重复 90 | 91 | ## 红黑树 92 | 93 | * 平衡二叉树,解决退化成链表的问题,降低树的高度,减少查询的复杂度 94 | 95 | ## java特性 96 | 97 | * 面向对象 98 | * 封装 99 | * 继承 100 | * 多态 101 | 102 | ## 多态 103 | 104 | * 举了接口的例子,父类引用指向子类对象 105 | 106 | ## JVM虚拟机分区 107 | 108 | * 新生代 109 | * Eden 110 | * ToSurvivor 111 | * FromSurvivor 112 | * 老年代 113 | * MetaSpace(永久代/方法区) 114 | 115 | ## 哪些线程共享,哪些线程独享 116 | 117 | * 线程共享 118 | * 堆 119 | * 方法区 120 | * 类,静态变量,常量 121 | * 线程私有 122 | * 程序计数器 123 | * JVM栈 124 | * 本地方法栈 125 | 126 | ## 常用的垃圾回收器 127 | 128 | * 年轻代 129 | * Serial 130 | * Parallel Scavenge 131 | * Parnew 132 | * 老年代 133 | * Serial old 134 | * parallel old 135 | * CMS 136 | * G1通吃 137 | 138 | ## G1会不会导致Stop the World 139 | 140 | * 会 141 | 142 | ## 若多个线程访问static变量会怎样 143 | 144 | * 不能保证原子性,多个线程间数据不一致,想要同步加schronized(XXX.class){} 145 | 146 | ## HashMap,ConcurrentHashMap,HashTable区别 147 | 148 | * 线程安全方面 149 | * HashTable,ConcurrentHashMap线程安全 150 | * HashMap线程不安全 151 | * 锁方面 152 | * ConcurrentHashMap使用CAS+Synchronized锁 153 | * HashTable使用Synchronized锁 154 | * 初始容量 155 | * HashTable默认11,扩容量为old*2+1 156 | * HashMap和ConcurrentHashMap为16,扩容2倍重排 157 | * put()方法 158 | * HashMap key,value可以为Null 159 | 160 | (谈到了ConcurrentHashMap分段--16锁定,HashTable整体锁定,线程处理较慢) 161 | 162 | ## 什么时候发生full gc 163 | 164 | * 老年代满 165 | * 永久代满 -------------------------------------------------------------------------------- /面试/小米.md: -------------------------------------------------------------------------------- 1 | # 一面 2 | 3 | ## 对面向对象的理解 4 | 5 | ## 面向对象和面向过程区别 6 | 7 | ## java为什么不能多继承 8 | 9 | ## java抽象类和接口 10 | 11 | * Java8之后接口中的方法可被默认实现 12 | * 接口可做为一种标记`Serializable`,可向上转型至多个 13 | * 变量默认`public static final` 14 | 15 | ## java中为什么要写非static方法 16 | 17 | * Static方法在类第一次加载时便存入内存中,直到结束才会释放内存 18 | * 非static方法的成员函数,在使用完之后便会被释放 19 | 20 | ## volatile和synchronized的区别 21 | 22 | * Volatile为轻量级Synchronized,但不保证原子性 23 | * Volatile使变量可见,只能修饰变量,Synchronized可用来修饰类,方法,变量 24 | * Volatile禁止指令重排,例如单例模式下使用DCL 25 | * Synchrnized加锁需要操作系统仲裁 26 | 27 | ## 算法 28 | 29 | * 跳台阶问题 30 | 31 | * 树的非递归后序遍历 32 | 33 | ```java 34 | package com.example.demo; 35 | 36 | import java.util.ArrayList; 37 | import java.util.LinkedList; 38 | 39 | /** 40 | * @author wst 41 | * @create 2019-09-07 下午2:58 42 | */ 43 | public class PostOrderBinTree { 44 | public static ArrayList postOrder(TreeNode root) { 45 | ArrayList res = new ArrayList<>(); 46 | if (root == null) { 47 | return res; 48 | } 49 | 50 | LinkedList stack = new LinkedList<>(); 51 | TreeNode p = root; 52 | 53 | while (p != null || !stack.isEmpty()) { 54 | if (p != null) { 55 | stack.push(p); 56 | p.flag = 0; 57 | p = p.left; 58 | } else { 59 | p = stack.peek(); 60 | if (p.right == null || p.right.flag == 1) { 61 | res.add(stack.pop().val); 62 | p.flag = 1; 63 | p = null; 64 | } else { 65 | p = p.right; 66 | } 67 | } 68 | } 69 | return res; 70 | 71 | } 72 | ``` 73 | 74 | 75 | 76 | ## 设计 77 | 78 | * 一个停车场有一些大车位和小车位,大车只能停大车位,小车既能停大车位又能停小车位,实现这种场景下的调度系统 79 | 80 | # 二面 81 | 82 | ## 算法题 83 | 84 | * 输入一个字符串,输出该字符串中字符的所有排列 85 | 86 | ```java 87 | package com.soto; 88 | 89 | import java.util.ArrayList; 90 | import java.util.Collections; 91 | 92 | /** 93 | * @author wst 94 | * @create 2019-09-06 21:57 95 | */ 96 | public class Permutation { 97 | 98 | 99 | public static ArrayList permutation(String s) { 100 | ArrayList res = new ArrayList<>(); 101 | if (s == null || s.length() == 0) { 102 | return res; 103 | } 104 | permutationCore(s.toCharArray(), 0, res); 105 | Collections.sort(res); 106 | return res; 107 | } 108 | public static void permutationCore(char[] chars, int begin, ArrayList res) { 109 | if (begin == chars.length - 1) { 110 | String s = String.valueOf(chars); 111 | if (!res.contains(s)) { 112 | res.add(s); 113 | return; 114 | } 115 | } 116 | for (int i = begin; i < chars.length; i++) { 117 | swap(chars, begin, i); 118 | permutationCore(chars, begin + 1, res); 119 | swap(chars,begin,i); 120 | } 121 | } 122 | 123 | public static void swap(char[] chars,int i, int j) { 124 | char temp = chars[i]; 125 | chars[i] = chars[j]; 126 | chars[j] = temp; 127 | 128 | } 129 | 130 | public static void main(String[] args) { 131 | ArrayList res = Permutation.permutation("abc"); 132 | System.out.println(res); 133 | 134 | } 135 | } 136 | 137 | ``` 138 | 139 | -------------------------------------------------------------------------------- /数据库/mybatis.md: -------------------------------------------------------------------------------- 1 | # # 和 $的区别 2 | 3 | * `#`对传入的数据加双引号,`$`直接解析成sql 4 | * `#`防止sql注入,能用`#`不用`$` 5 | * 原sql: `select count(*) from admin where username = 'test' and password = 'test'` 6 | * [注入](https://blog.csdn.net/u012436758/article/details/53871290): `select count(*) from admin where username = ' 'or 1=1-- ' and password = ' ' "`sql在招行时,`"--"`将`and`及之后的语句都注释了 7 | * `$`方式一般用于传入数据库对象,例如传入表名 8 | * 简单说#{}是经过预编译的,是安全的,而${}是未经过预编译的,仅仅是取变量的值,是非安全的,存在sql注入。 9 | * 只能`${}的情况,order by、like 语句只能用${}`了,用#{}会多个' '导致sql语句失效.此外动态拼接sql也要用${}。 10 | 11 | # [一级缓存和二级缓存](https://tech.meituan.com/2018/01/19/mybatis-cache.html) 12 | 13 | ![img](https://img-blog.csdn.net/20150726164148424?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 14 | 15 | * 一级缓存(`SqlSession`级别) 16 | * 同一`SqlSession`执行相同`sql`,第一次会将结果写入缓存(内存`HashMap`) 17 | * 若执行commit操作(insert,update,delete),清空一级缓存 18 | * 二级缓存(Mapper级别) 19 | * 多个`SqlSession`共用二级缓存,作用域为Mapper的同一个namespace 20 | * 默认没开二级缓存,需在setting全局参数中配置开启二级缓存 21 | * 使用顺序 22 | * **二级缓存->一级缓存->数据库** 23 | * 缓存实现 24 | * `MyBatis`自身缓存实现 25 | * 用户自定义Cache接口实现 26 | * 跟第三方内存缓存库和集成 27 | * 缓存置换策略 28 | * LRU 29 | * FIFO 30 | * 主要设计模式 31 | * 装饰器模式 32 | 33 | 1. MyBatis的二级缓存相对于一级缓存来说,实现了`SqlSession`之间缓存数据的共享,同时粒度更加的细,能够到`namespace`级别,通过Cache接口实现类不同的组合,对Cache的可控性也更强。 34 | 2. MyBatis在多表查询时,极大可能会出现脏数据,有设计上的缺陷,安全使用二级缓存的条件比较苛刻。 35 | 3. 在分布式环境下,由于默认的MyBatis Cache实现都是基于本地的,分布式环境下必然会出现读取到脏数据,需要使用集中式缓存将MyBatis的Cache接口实现,有一定的开发成本,直接使用Redis、Memcached等分布式缓存可能成本更低,安全性也更高。 36 | 37 | # [分页](https://blog.csdn.net/chenbaige/article/details/70846902) 38 | 39 | * 数组分页(逻辑分页) 40 | 41 | * 获取所有满足条件的记录存在临时数组中,通过`List`的`subList()`分页 42 | 43 | * `sql`语句分页(物理分页) 44 | 45 | * 在`sql`后面加`limit`分页语句 46 | 47 | * `RowBounds`分页 48 | 49 | * 和数组分页原理一样,只是不需要我们自己实现分页原理 50 | 51 | * 内存消耗大,可能导致性能差,OOM 52 | 53 | * ```java 54 | /加入RowBounds参数 55 | public List queryUsersByPage(String userName, RowBounds rowBounds); 56 | ``` 57 | 58 | * 拦截器分页 59 | 60 | ## 逻辑分页和物理分页 61 | 62 | * 区别 63 | * 物理每次都访问数据库,负担大,逻辑只访问一次,占内存大 64 | * 物理实时性高,逻辑一次访问全部数据.实时性差 65 | * 适用 66 | * 逻辑: 数据量小,数据稳定 67 | * 物理:数据量大, 更新频繁 68 | 69 | # 延迟加载 70 | 71 | * 先加载主要数据,如果需要关联数据,再加载 72 | 73 | * 优点 74 | 75 | * 避免资源浪费,提升查询速度 76 | 77 | * 开启 78 | 79 | ```xml 80 | 81 | 82 | 83 | 84 | //lazyLoadingEnabled 这个是开启懒加载的全局配置 //aggressiveLazyLoading 这个属性必须改为false 否则不生效 85 | ``` 86 | 87 | # MyBatis和 Hibernate的区别 88 | 89 | * MyBatis半自动,Hibernate全自动 90 | * Hibernate完全可以通过对象关系模型(ORM)实现对数据库操作,拥有完整的JavaBean对象与数据库的映射结构自动生成SQL 91 | * MyBatis仅有基本字段映射,对象数据及关系还需定制SQL实现管理 92 | * Hibernate数据库移植性好 93 | * MyBatis需要手写SQL,耦合度高 94 | * Hibernate拥有完整日志系统 95 | * 包括:SQL记录,关系异常,优化警告,缓存提示,脏数据警告 96 | * MyBatis除了基本记录功能外,功能薄弱 97 | * MyBatis使用简单,但需要关心更多细节 98 | * MyBatis SQL优化较好(公司选择原因) 99 | * MyBatis因sql写在xml里,Hibernate很多是自动生成的,无法直接维护sql 100 | * Hibernate安全性要好,MyBatis存在SQL注入问题 101 | 102 | # Mybatis使用规范 103 | 104 | * 不能使用$语句,要替换$语句 105 | * $语句在sql预编译前就进行了常量替换,存在sql注入风险;而#语句经过了预编译环节,可规避此风险 106 | 107 | * 优先使用mybatis-generator (MBG) 108 | * MBG简介:mybatis 映射文件的生成器,可以读取数据表信息,自动生成对应的POJO,xml和mapper文件; 109 | * 用法: 1) 在pom.xml中配置 MBG plugin 2) 编写generatorConfig.xml 配置文件 3) mvn mybatis-generator:generate 110 | 111 | * 手写的sql 要与MBG生成的分开 112 | * 当MBG生成的API无法满足时,需要手工添加sql,这时,切记要将手写的sql放置到单独的文件中。否则,当MBG重新生成时,你手写的sql会被覆盖; 113 | * 一般做法:新建 *ManualMapper.java 和 *ManualMapper.xml 114 | 115 | * count语句返回类型不能为int 116 | * 原因:若返回类型是int,当数据表为空时,会抛出 BindingException -------------------------------------------------------------------------------- /面试/爱奇艺.md: -------------------------------------------------------------------------------- 1 | # [2018Java实习面试(北京)](https://www.nowcoder.com/discuss/84431?type=2&order=0&pos=57&page=1) 2 | 3 | ## 请说出Java集合有哪些 4 | 5 | Set,List,Map 6 | 7 | ## 说一下你对哈希冲突的理解 8 | 9 | ## List的两大分类以及区别,随机访问的话哪个更快? 10 | 11 | ## Spark集群的理解 12 | 13 | ## 怎么用Docker容器 14 | 15 | ## 问了Spring MVC的理解 16 | 17 | ![深度截图_选择区域_20190526155337.png](https://i.loli.net/2019/05/26/5cea460a80ac716924.png) 18 | 19 | ## 会不会写JS 20 | 21 | # [2018Java实习面试(上海)](https://www.nowcoder.com/discuss/84431?type=2&order=0&pos=57&page=1) 22 | 23 | ## Object类有哪些方法? 24 | 25 | 1. getClass() 26 | 2. hashCode() 27 | 3. equals() 28 | 4. toString() 29 | 5. clone() 30 | 6. wait()... 31 | 7. notify() 32 | 8. notifyAll() 33 | 9. finalize( 34 | 35 | ## hashCode()相等,equals()一定能返回true吗?反过来呢? 36 | 37 | ## equals和==的区别 38 | 39 | ## 如果你要重写equals(),怎么重写,需要注意哪些问题 40 | 41 | ## Java基本数据类型有哪些 42 | 43 | ## Java是如何做参数传递的 44 | 45 | **java本质上只有按值传递;** 46 | 47 | 只有一种参数传递机制 – 按值传递 48 | 无论引用类型或基本类型,当作为参数传递给一个方法时,两种类型都是按值传递的。 49 | 50 | 按值传递意味着当将一个参数传递给一个方法时,方法接收的是原始值的一个副本。 51 | 52 | Java 编程语言只有值传递参数。当一个对象实例作为一个参数被传递到方法中时,参数的值就是该对象的引用一个副本。指向同一个对象,对象的内容可以在被调用的方法中改变,但对象的引用(不是引用的副本)是永远不会改变的。 53 | 54 | 只不过,**当把对象作为参数传递时,可以通过该副本引用改变该对象的的属性**。 55 | 56 | ## int和Integer区别 57 | 58 | ## HashMap的底层是如何实现的 59 | 60 | ## HashMap是怎么实现存的? 61 | 62 | ## HashMap是怎么实现get()方法的 63 | 64 | ## HashMap和ConcurrentHashMap的区别 65 | 66 | ## 对MySQL索引有哪些了解? 哪些列适合建索引?索引是越多越好吗? 67 | 68 | ## 列举Redis的5种基本数据类型 69 | 70 | ## cookie 和session 的区别 71 | 72 | ## 经常访问的页面用cookie还是session 73 | 74 | ## HTTP方法GET和POST区别 75 | 76 | ## 列举几个你知道的HTTP状态码 77 | 78 | ## 请说出TCP三次握手是怎么实现的 79 | 80 | https://www.nowcoder.com/discuss/126493?type=2&order=0&pos=27&page=1 81 | 82 | 1、Spring MVC 的入口函数是什么?DispatcherServlet什么作用? 83 | 84 | 2、Sring AOP底层实现原理;SSM框架用了多久 85 | 86 | 3、MySQL: 两种引擎;索引的数据结构;B+树和红黑树 87 | 88 | 4、Redis:持久化方式 ;如何设计一个队列。除了Redis之外常见的缓存,Java使用缓存的方式;学了多久 89 | 90 | 5、Java: CMS垃圾回收机制;jvm内存管理;jvm常见命令,如何查看线程 91 | 92 | 6、Socket使用方式、运用场景 93 | 94 | ## MapReduce shuffle原理 95 | 96 | ## 排序这个过程是在map还是在reduce 97 | 98 | ## hdfs原理 99 | 100 | ## hdfs是并行写入的还是顺序写的 101 | 102 | 是顺序流式读写。 103 | 104 | ## 分布式文件系统机制 105 | 106 | --- 107 | 108 | # 2019Java全栈开发实习面试 109 | 110 | ## HashMap原理 111 | 112 | ## 链表转红黑树阈值,红黑树转链表阈值,为什么 113 | 114 | ## ConcurrentHashMap原理 115 | 116 | ## CAS及其缺点 117 | 118 | ## NIO原理 119 | 120 | ## 用户态到内核态 121 | 122 | ## select,poll,epoll 123 | 124 | ## epoll数据结构 125 | 126 | ## 知道的Java设计模式,除了工厂与单例 127 | 128 | ## Synchronized与ReentrantLock区别 129 | 130 | ## Synchronized锁方法和锁代码段的实现 131 | 132 | * 主要是对象头与monitor_enter讲一下 133 | 134 | ## Synchronized会响应中断么,可重入么 135 | 136 | ## Spring AOP实现原理 137 | 138 | ## 线程池参数 139 | 140 | ## 若线程池中2个线程,执行完毕,现有新任务会怎样 141 | 142 | ## 死锁的条件 143 | 144 | ## 如何避免死锁 145 | 146 | ## MySQL隔离级别 147 | 148 | ## InnoDB与MyISAM区别 149 | 150 | ## 什么是聚簇索引 151 | 152 | ## GAP锁 153 | 154 | ## 你所知道的数据库引擎 155 | 156 | ## MySQL可重复读下如何解决幻读 157 | 158 | ## 可重复读与未提交读区别 159 | 160 | ## Redis数据结构及其实现 161 | 162 | ## Redis跳表 163 | 164 | ## Redis分布式锁 165 | 166 | ## 缓存击穿,缓存雪崩与缓存穿透的解决方法 167 | 168 | ## Http请求头 169 | 170 | ## Http2.0与1.0的区别 171 | 172 | ## HTTP1.1与1.0的区别 173 | 174 | ## 僵尸进程与孤儿进程的区别 175 | 176 | ## 拥塞控制原理 177 | 178 | ## AIMD算法中在包丢失情况下,窗口大小 179 | 180 | ## 进程通信方法 181 | 182 | ## CMS原理 183 | 184 | ## CMS 中Stop the word阶段 185 | 186 | ## Mybatis $与#的区别 187 | 188 | ## Mybatis与Hibernate的区别 189 | 190 | ## 在10亿数中找到一个数(bitmap) 191 | 192 | ## 找数据流的中位数(剑指offer) 193 | 194 | ## RabbitMQ与RocketMQ的区别 195 | 196 | ## Git中Rebase和Merge区别 197 | 198 | ## Vue与React的区别 199 | 200 | ## Git的内存结构,实现原理 201 | 202 | ## 常用的linux命令 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | -------------------------------------------------------------------------------- /Java/java性能调优.md: -------------------------------------------------------------------------------- 1 | # 内存泄漏 2 | 3 | * 程序分配了内存,但在程序结束时未被释放,导致那部分内存不可用 4 | 5 | ``` java 6 | Student s1 = new Student(); 7 | Student s2 = new Student(); 8 | //在ArrayList里放入s1和s2,再将s1和s2置为null,此时两对象所占内存不会被释放 9 | ``` 10 | 11 | ## 如何避免内存泄漏 12 | 13 | * 尽早释放无用对象的引用 14 | * 使用临时变量时,让引用在退出活动域后自动设置为null,暗示垃圾收集器收集该对象 15 | * 程序进行字符串处理时,避免使用String,而使用StringBuffer,因每一个Stringcfqj都会独立占用内存一块区域 16 | 17 | ## 检查内存泄漏工具 18 | 19 | * MemoryAnalyzer 20 | * Java堆转储文件分析工具,可帮助发现内存漏洞和减少内存消耗 21 | * EclipseMAT 22 | * 开源的Java内存分析软件,查找内存泄漏,能容易找到大块内存并验证谁在一直占用它 23 | * JProbe 24 | * 分析Java的内存泄漏 25 | 26 | # 基于JDK命令行工具的监控 27 | 28 | * JVM参数类型 29 | 30 | * 标准参数 31 | 32 | ```bash 33 | -help 34 | -server 35 | -client 36 | -version 37 | -showversion 38 | -cp -classpath 39 | ``` 40 | 41 | * X参数(非标准化参数) 42 | 43 | ```bash 44 | -Xint: 解释执行 45 | -Xcomp: 每一次使用就编译成本地代码 46 | -Xmixed: 混合模式,JVM自己来商定是否编译成本地代码 47 | ``` 48 | 49 | * XX参数 50 | 51 | * Boolean类型 52 | 53 | * -X:[+-]表示启用或者禁用name属性 54 | 55 | ```bash 56 | -X:+UseConcMarkSweepGC 57 | -X:+UseG1GC 58 | ``` 59 | 60 | * 非Boolean类型 61 | 62 | * -XX:=表示name属性的值是value 63 | 64 | ```bash 65 | -XX:MaxGCPauseMillis=500 66 | -XX:GCTimeRatio=19 67 | ``` 68 | 69 | * -Xms 70 | 71 | * 等价于-XX:InitialHeapSize 72 | 73 | * -Xmx 74 | 75 | * 等价于-XX:MaxHeapSize 76 | 77 | 78 | 79 | * 查看运行时JVM参数 80 | 81 | * -XX:+PrintFlagsInitial 82 | 83 | * -XX:+PrintFlagsFinal 84 | 85 | ```bash 86 | bool IgnoreUnrecognizedVMOptions = false {product} 87 | uintx IncreaseFirstTierCompileThresholdAt = 50 {product} 88 | bool IncrementalInline = true {C2 product} 89 | uintx InitialBootClassLoaderMetaspaceSize = 4194304 {product} 90 | uintx InitialCodeCacheSize = 2555904 {pd product} 91 | // := 表示修改后的值 92 | uintx InitialHeapSize := 125829120 {product} 93 | uintx InitialRAMFraction = 64 {product} 94 | ``` 95 | 96 | * -XX:+UnlockExperimentalVMOptions解锁实验参数 97 | 98 | * -XX:+UnlockDiagnosticVMOptions解锁诊断参数 99 | 100 | * -XX:+PrintCommandLineFlags打印命令行参数 101 | 102 | * 查看JVM统计信息 103 | 104 | * jps 105 | 106 | * jinfo 107 | 108 | ```bash 109 | //查看最大堆内存 110 | jinfo -flag MaxHeapSize PID 111 | //查看垃圾回收器 112 | jinfo -flag UseG1GC PID 113 | ``` 114 | 115 | * jstat 116 | 117 | ```bash 118 | //类装载信息,每隔1000ms 输出10次 119 | jstat -class PID 1000 10 120 | //关于GC信息 121 | jsta -gc PID 122 | //JIT编译信息 123 | jstat -compiler PID 124 | ``` 125 | 126 | * jmap+MAT 内存溢出 127 | 128 | * 如何导出内存映像文件 129 | 130 | * 内存溢出自动导出 131 | 132 | ```bash 133 | -XX:+HeapDumpOnOutOfMemoryError 134 | -XX:HeapDumpPath=./ 135 | ``` 136 | 137 | * jmap导出 138 | 139 | ```bash 140 | jmap -dump:format=b,file=heap.hprof PID 141 | ``` 142 | 143 | * MAT分析内存溢出原因 144 | 145 | * jstack 死循环与死锁 146 | 147 | # 基于JVisualVM的可视化监控 148 | 149 | * 监控本地Java进程 150 | * 监控远程Java进程 151 | * 监控本地Tomcat 152 | * 监控远程Tomcat 153 | 154 | # 基于Btrace和监控调试 155 | 156 | # Tomcat性能监控与调优 157 | 158 | * Tomcat debug 159 | * Tomcat-manager监控Tomcat 160 | * psi-probe监控Tomcat 161 | * Tomcat调优 162 | 163 | # Ngnix性能监控调优 164 | 165 | * ngx_http_stub_status监控连接信息 166 | * ngxtop监控请求信息 167 | * ngx-rrd图形化监控 168 | 169 | # JVM GC调优 170 | 171 | * JVM内存结构 172 | * JVM垃圾回收 173 | * GC日志格式与可视化日志分析工具 174 | * Tomcat的GC调优 175 | 176 | # Java代码层调优 177 | 178 | * JVM字节码指令与javap 179 | * i++与++i,字符串+拼接原理 180 | * 常用代码优化方法 -------------------------------------------------------------------------------- /hadoop/hadoop.md: -------------------------------------------------------------------------------- 1 | # [Hadoop基础知识面试题整理](https://www.iteblog.com/archives/1629.html) 2 | 3 | ## 1、hadoop 安装步骤 4 | 5 | ``` 6 | 1) 安装JDK并配置环境变量(/etc/profile) 7 | 8 | 2) 关闭防火墙 9 | 10 | 3) 配置hosts文件,方便hadoop通过主机名访问(/etc/hosts) 11 | 12 | 4) 设置ssh免密码登录 13 | 14 | 5) 解压缩hadoop安装包,并配置环境变量 15 | 16 | 6) 修改配置文件($HADOOP_HOME/conf) 17 | 18 | hadoop-env.sh core-site.xml hdfs-site.xml mapred-site.xml 19 | 20 | 7) 格式化hdfs文件系统 (hadoop namenode -format) 21 | 22 | 8) 启动hadoop ($HADOOP_HOME/bin/start-all.sh) 23 | 24 | 9) 使用jps查看进程 25 | 26 | ``` 27 | 28 | ## 2、hadoop集群中hadoop都分别需要启动那些进程,他们的作用 29 | 30 | ``` 31 | 32 | 1) NameNode: HDFS的守护进程,负责记录文件是如何分割成数据块,以及这些数据块分别被存储到那些数据节点上,它的主要功能是对内存及IO进行集中管理 33 | 34 | 2) Secondary NameNode:辅助后台程序,与NameNode进行通信,以便定期保存HDFS元数据的快照。 35 | 36 | 3) DataNode:负责把HDFS数据块读写到本地的文件系统。 37 | 38 | 4) JobTracker:负责分配task,并监控所有运行的task。 39 | 40 | 5) TaskTracker:负责执行具体的task,并与JobTracker进行交互。 41 | 42 | ``` 43 | 44 | ## 3、请列出你所知道的hadoop调度器,并简要说明其工作方法。 45 | 46 | **1) 默认调度器FIFO** 47 | 48 | hadoop中默认的调度器,采用先进先出的原则 49 | 50 | **2) 计算能力调度器Capacity Scheduler** 51 | 52 | 选择占用资源小,优先级高的先执行 53 | 54 | **3) 公平调度器Fair Scheduler** 55 | 56 | 同一队列中的作业公平共享队列中所有资源 57 | 58 | 59 | 60 | ## 4、Hive有那些方式保存元数据的,各有那些特点。 61 | 62 | 1) 内存数据库derby,较小,不常用 63 | 2) 本地mysql,较常用 64 | 3) 远程mysql,不常用 65 | 66 | ## 5、请简述hadoop怎样实现二级排序。 67 | 68 | 在[Hadoop](https://www.iteblog.com/archives/tag/hadoop/)中,默认情况下是按照key进行排序,如果要按照value进行排序怎么办? 69 | 有两种方法进行二次排序,分别为:buffer and in memory sort和 value-to-key conversion。 70 | 71 | **buffer and in memory sort** 72 | 主要思想是:在reduce()函数中,将某个key对应的所有value保存下来,然后进行排序。 这种方法最大的缺点是:可能会造成out of memory。 73 | 74 | **value-to-key conversion** 75 | 主要思想是:将key和部分value拼接成一个组合key(实现WritableComparable接口或者调setSortComparatorClass函数),这样reduce获取的结果便是先按key排序,后按value排序的结果,需要注意的是,用户需要自己实现Paritioner,以便只按照key进行数据划分。[Hadoop](https://www.iteblog.com/archives/tag/hadoop/)显式的支持二次排序,在Configuration类中有个setGroupingComparatorClass()方法,可用于设置排序group的key值。[《Hadoop&Spark解决二次排序问题(Hadoop篇)》](https://www.iteblog.com/archives/1415) 76 | 77 | ## 6、简述hadoop实现Join的几种方法。 78 | 79 | **(1)、reduce side join** 80 | reduce side join是一种最简单的join方式,其主要思想如下: 81 | 在map阶段,map函数同时读取两个文件File1和File2,为了区分两种来源的key/value数据对,对每条数据打一个标签(tag),比如:tag=0表示来自文件File1,tag=2表示来自文件File2。即:map阶段的主要任务是对不同文件中的数据打标签。 82 | 在reduce阶段,reduce函数获取key相同的来自File1和File2文件的value list, 然后对于同一个key,对File1和File2中的数据进行join(笛卡尔乘积)。即:reduce阶段进行实际的连接操作。 83 | 84 | **(2)、map side join** 85 | 之所以存在reduce side join,是因为在map阶段不能获取所有需要的join字段,即:同一个key对应的字段可能位于不同map中。Reduce side join是非常低效的,因为shuffle阶段要进行大量的数据传输。 86 | Map side join是针对以下场景进行的优化:两个待连接表中,有一个表非常大,而另一个表非常小,以至于小表可以直接存放到内存中。这样,我们可以将小表复制多份,让每个map task内存中存在一份(比如存放到hash table中),然后只扫描大表:对于大表中的每一条记录key/value,在hash table中查找是否有相同的key的记录,如果有,则连接后输出即可。 87 | 为了支持文件的复制,[Hadoop](https://www.iteblog.com/archives/tag/hadoop/)提供了一个类DistributedCache,使用该类的方法如下: 88 | (1)用户使用静态方法DistributedCache.addCacheFile()指定要复制的文件,它的参数是文件的URI(如果是HDFS上的文件,可以这样:hdfs://namenode:9000/home/XXX/file,其中9000是自己配置的NameNode端口号)。JobTracker在作业启动之前会获取这个URI列表,并将相应的文件拷贝到各个TaskTracker的本地磁盘上。(2)用户使用DistributedCache.getLocalCacheFiles()方法获取文件目录,并使用标准的文件读写API读取相应的文件。 89 | 90 | **(3)、SemiJoin** 91 | SemiJoin,也叫半连接,是从分布式数据库中借鉴过来的方法。它的产生动机是:对于reduce side join,跨机器的数据传输量非常大,这成了join操作的一个瓶颈,如果能够在map端过滤掉不会参加join操作的数据,则可以大大节省网络IO。 92 | 实现方法很简单:选取一个小表,假设是File1,将其参与join的key抽取出来,保存到文件File3中,File3文件一般很小,可以放到内存中。在map阶段,使用DistributedCache将File3复制到各个TaskTracker上,然后将File2中不在File3中的key对应的记录过滤掉,剩下的reduce阶段的工作与reduce side join相同。 93 | 94 | (4)、reduce side join + BloomFilter 95 | 在某些情况下,SemiJoin抽取出来的小表的key集合在内存中仍然存放不下,这时候可以使用BloomFiler以节省空间。 96 | BloomFilter最常见的作用是:判断某个元素是否在一个集合里面。它最重要的两个方法是:add() 和contains()。最大的特点是不会存在false negative,即:如果contains()返回false,则该元素一定不在集合中,但会存在一定的true negative,即:如果contains()返回true,则该元素可能在集合中。 97 | 因而可将小表中的key保存到BloomFilter中,在map阶段过滤大表,可能有一些不在小表中的记录没有过滤掉(但是在小表中的记录一定不会过滤掉),这没关系,只不过增加了少量的网络IO而已。 98 | 99 | ## 7、请简述MapReduce中combiner、partition的作用 100 | 101 | **(1)、combiner** 102 | 有时一个map可能会产生大量的输出,combiner的作用是在map端对输出先做一次合并,以减少网络传输到reducer的数量。 103 | 注意:mapper的输出为combiner的输入,reducer的输入为combiner的输出。 104 | 105 | **(2)、partition** 106 | 把map任务输出的中间结果按照key的范围划分成R份(R是预先定义的reduce任务的个数),划分时通常使用hash函数,如:hash(key) mod R 107 | 这样可以保证一段范围内的key,一定会由一个reduce任务来处理。 108 | 109 | 110 | 111 | # **如何查看当前系统都有哪些进程?** 112 | 113 | 答: 114 | 115 | ps -aux 或者ps -elf 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /面试/腾讯.md: -------------------------------------------------------------------------------- 1 | # IEG 2 | 3 | ## 一面 4 | 5 | ### 线程的局部变量 6 | 7 | * ThreadLocal与ThreadLocalMap与内存泄漏与线程池下的不安全 8 | 9 | ### 线程池参数 10 | 11 | * corePoolSize 12 | * maxmumPoolSize 13 | * allowCoreThreadTimeout 14 | * keepAliveTime 15 | * queueCapacity 16 | * BlockingQueue 17 | 18 | ### String、StringBuffer、StringBuilder的区别 19 | 20 | * String不变性 21 | - String对象是常量,它的值不能被创建后改变,StringBuffer和StringBuilder可以可变; 22 | * StringBuilder非线程安全(单线程使用),String与StringBuffer线程安全(多线程使用); 23 | * 如果程序不是多线程的,那么使用StringBuilder效率高于StringBuffer。 24 | 25 | * 常量池 26 | 27 | 常量池是一个内存空间,不同于使用new关键字创建的对象所在的堆空间。 28 | 常量池是为了避免频繁的创建和销毁对象而影响系统性能,其实现了对象的共享。当需要一个对象时,就可以从池中取一个出来(如果池中没有则创建一个),则在需要重复创建相等变量时节省了很多时间。 29 | 在编译期被确定,并被保存在已编译的.class文件中的一些数据,包括类、方法、接口等中的常量和字符串常量。常量池还具备动态性,运行期间可以将新的常量放入池中。java中基本类型的包装类的大部分都实现了常量池技术, 即Byte,Short,Integer,Long,Character,Boolean; 30 | 31 | 下面代码创建了几个String对象? 32 | 33 | ```java 34 | String s1 = new String("s1") ; 35 | String s2 = new String("s1") ; 36 | ``` 37 | 38 | ```java 39 | // 3个,编译期在常量池中创建1个,即“s1”常量对象;运行期堆中创建2个,即s1和s2对象。 40 | String s1 = "s1"; 41 | String s2 = s1; 42 | s2 = "s2"; 43 | ``` 44 | 45 | ------ 46 | 47 | ### ==和equals的区别 48 | 49 | ### 重写equals()不重写hashCode()会发生什么 50 | 51 | ### volatile怎么保证可见性 52 | 53 | ### 并发编程的锁机制 54 | 55 | * 可重入锁 56 | 57 | * 读写锁 58 | 59 | 读写锁将对一个资源的访问分成了2个锁,如文件,一个读锁和一个写锁。正因为有了读写锁,才使得多个线程之间的读操作不会发生冲突。`ReadWriteLock`就是读写锁,它是一个接口,ReentrantReadWriteLock实现了这个接口。可以通过readLock()获取读锁,通过writeLock()获取写锁。 60 | 61 | * 可中断锁 62 | 63 | 可中断锁,即可以中断的锁。在Java中,synchronized就不是可中断锁,而Lock是可中断锁。 如果某一线程A正在执行锁中的代码,另一线程B正在等待获取该锁,可能由于等待时间过长,线程B不想等待了,想先处理其他事情,我们可以让它中断自己或者在别的线程中中断它,这种就是可中断锁。 64 | 65 | Lock接口中的**lockInterruptibly**()方法就体现了Lock的可中断性。 66 | 67 | * 公平锁 68 | 69 | `synchronized`是非公平锁,它无法保证等待的线程获取锁的顺序。对于`ReentrantLock`和`ReentrantReadWriteLock`,默认情况下是非公平锁,但是可以设置为公平锁。 70 | 71 | ### synchronized和lock的区别 72 | 73 | - Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现; 74 | - synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁; 75 | - Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断; 76 | - 通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。 77 | - Lock可以提高多个线程进行读操作的效率。(可以通过readwritelock实现读写分离) 78 | - 性能上来说,在资源竞争不激烈的情形下,Lock性能稍微比synchronized差点(编译程序通常会尽可能的进行优化synchronized)。但是当同步非常激烈的时候,synchronized的性能一下子能下降好几十倍。而ReentrantLock确还能维持常态。 79 | 80 | 到了JDK1.6,发生了变化,对synchronize加入了很多优化措施,有自适应自旋,锁消除,锁粗化,轻量级锁,偏向锁等等。导致在JDK1.6上synchronize的性能并不比Lock差。官方也表示,他们也更支持synchronize,在未来的版本中还有优化余地,所以还是提倡在synchronized能实现需求的情况下,优先考虑使用synchronized来进行同步。 81 | 82 | ### synchronized的JVM底层实现 83 | 84 | ### sleep和wait的区别 85 | 86 | ### 锁池和等待池 87 | 88 | ### notify和notifyAll有什么区别 89 | 90 | ### 什么情况会发生死锁 91 | 92 | ### 死锁的处理方法 93 | 94 | ### Cookie和Session的区别 95 | 96 | ### 怎么防止Cookie欺骗 97 | 98 | ### 在浏览器输入域名,到浏览器显示出页面的过程 99 | 100 | ## 二面 101 | 102 | ### 谈谈对UDF的理解, 103 | 104 | ### 写UDF的目的,代码怎么写 105 | 106 | ``` 107 | 5、项目里面为什么要用kafka stream做实时计算,而不是用spark或者flink,kafka sql和spark sql了解过吗 108 | 6、项目里面用到了时序数据库opentsdb,为什么要用这个,有没有跟其它的时序数据库对比过 109 | 7、平时逛不逛社区,有没有参与过开源项目 110 | ``` 111 | 112 | ### 改造hive表后怎么进行数据一致性校验的,有没有自动化流程 113 | 114 | ### 讲讲kafka broker的源码里面你最熟悉的类,以及这个类的主要方法,用的什么设计模式 115 | 116 | ### 数据采集到数据可视化,如何判断数据有没有丢,若丢了如何定位到在哪一个环节 117 | 118 | ## 三面 119 | 120 | ``` 121 | 1、看你写了实时计算的程序,你怎么保证计算的结果肯定是对的 122 | 2、数据接入的时候,怎么往kafka topic里面发的,用的什么方式,起了几个线程,producer是线程安全的吗 123 | 3、kafka集群有几台机器,怎么确定你们项目需要用几台机器,有评估过吗,吞吐量测过吗 124 | 4、spark streaming是怎么跟kafka交互的,具体代码怎么写的,程序执行流程是怎样的,这个过程中怎么确保数据不丢 125 | 5、kafka监控是怎么做的,kafka中能彻底删除数据吗,怎么做的 126 | ``` 127 | 128 | ## 面委会(全程聊天) 129 | 130 | - 平时是怎么学习的,爱看哪些博客,怎么看待加班,有没有成为leader的潜力 131 | 132 | # 腾讯视频(PCG) 133 | 134 | ## 一面 135 | 136 | ### 算法 137 | 138 | * 有序数组合并 139 | * 前序遍历二叉树 140 | 141 | ### 智力题 142 | 143 | * 有1000个苹果,10个篮子,问怎么把这1000个苹果放在这10个篮子里,能让任选多少个苹果都能整篮提取 144 | 145 | ### 计算机网络 146 | 147 | * 网络编程中,客户端和端各需要调用哪些函数 148 | * tcp协议里,怎么保证四次的最后一个包没有丢 149 | 150 | ### SQL 151 | 152 | 有三张mysql表:table_a,table_b,table_c.其中都包含字段sentence,类型为varchar,问:查询出在table_c中,但不在table_a且不在table_b的sentence 153 | 154 | ### redis如何淘汰过期的数据 155 | 156 | # 财付通(CDG) 157 | 158 | * MySQL范式 159 | * MySQL隔离级别 160 | * 事务特性具体介绍 161 | * 数组和链表的区别 162 | * 排序有哪些,时空复杂度 163 | * 依赖注入的好处 164 | * 数据库中 左连接Left outer join,右连接Right outer join, 内连接(Inner join) 165 | * 线程的状态 166 | * 如何结束线程 167 | * 算法 168 | * 输入一个字符串,这个字符串是某个数字的十六进制表示,可以以0x,0X开头,也可以没有,输出该字符串对应的十进制数 -------------------------------------------------------------------------------- /MQ/MQ.md: -------------------------------------------------------------------------------- 1 | # [为何要用MQ系统](https://mp.weixin.qq.com/s/-DZj158-LOQmnCayf1_n3A) 2 | 3 | ``` 4 | 当我们不使用消息队列时,所有用户请求通过直接落到服务器,然后通过数据库或缓存响应.假如在高并发环境下,如果没有缓存或者数据库承受不了这么大压力,会造成响应变慢,甚至造成数据库宕机。 5 | 但是,在使用消息队列之后,用户的请求数据发送给了消息队列之后就可以立即返回,再由消息队列的消费者进程从消息队列中获取数据,异步写入数据库,不过要确保消息不被重复消费还要考虑到消息丢失问题。由于消息队列服务器处理速度快于数据库,因此响应速度得到大幅改善。 6 | 通过以上分析我们可以得出消息队列具有很好的削峰作用的功能——即通过异步处理,将短时间高并发产生的事务消息存储在消息队列中,从而削平高峰期的并发事务。 举例:在电子商务一些秒杀、促销活动中,合理使用消息队列可以有效抵御促销活动刚开始大量订单涌入对系统的冲击。 7 | ``` 8 | 9 | 10 | 11 | 12 | 13 | * 解耦 14 | * 通过Pub/Sub发布订阅消息模型,使系统解耦 15 | 16 | ![img](https://user-gold-cdn.xitu.io/2018/12/14/167aa142fc55e9a3?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) 17 | 18 | * 异步 19 | 20 | ![img](https://user-gold-cdn.xitu.io/2018/12/14/167aa14316752f9e?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) 21 | 22 | * 削峰 23 | ![img](https://user-gold-cdn.xitu.io/2018/12/14/167aa14336c8057f?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) 24 | 25 | # [消息队列优缺点](https://mp.weixin.qq.com/s/-DZj158-LOQmnCayf1_n3A) 26 | 27 | * 优点 28 | * 解耦 29 | * 异步 30 | * 削峰 31 | * 缺点 32 | * 系统可用性降低 33 | * 引用外部依赖越多,越容易挂掉,系统可用性在某种程度上降低,为什么这样说呢?在加入 MQ 之前,你不用考虑消息丢失或者说 MQ 挂掉等等的情况,但是,引入 MQ 之后你就需要去考虑了! 34 | * 系统复杂度高 35 | * 重复消费问题 36 | * 消息丢失问题 37 | * 消息顺序性 38 | * 一致性问题 39 | * A系统处理完返回成功,但若BCD中有没成功,用户会以为成功,导致数据不一致 40 | * 消息队列带来的异步确实可以提高系统响应速度。但是,万一消息的真正消费者并没有正确消费消息怎么办?这样就会导致数据不一致的情况了! 41 | 42 | # MQ(ActiveMQ/RabbitMQ/RocketMQ/Kafka)对比 43 | 44 | * RabbitMQ 45 | 46 | * 吞吐量大(w级) 47 | * 开源社区活跃 48 | * Erlang开发,很难看懂源码,依赖于开源社区 49 | * RocketMQ 50 | 51 | * 吞吐量比RabbitMQ大 52 | 53 | * 消息0丢失 54 | 55 | * 阿里开源,社区活跃度弱于RabbitMQ,可能黄掉 56 | 57 | * 分布式易扩展 58 | * Kafka 59 | * 适于大数据领域 60 | * 吞吐量高 61 | * 实时计算,日志采集 62 | 63 | ​ 64 | 65 | ![img](https://user-gold-cdn.xitu.io/2018/12/14/167aa14337dccf2e?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) 66 | 67 | # RocketMQ集群模式 68 | 69 | * 多master 70 | 71 | * 多master多slave异步复制模式 72 | 73 | * 多master多slave同步双写模式 74 | 75 | * 多master多slave模式 76 | 77 | ![多master多slave模式](https://segmentfault.com/img/bVbcl9A?w=788&h=465) 78 | 79 | # 如何保证MQ高可用 80 | 81 | * RabbitMQ 82 | * 普通集群模式 83 | * 消费者消费数据时,找到一个节点的Queue,该Queue再去寻找拥有数据的节点Queue,增加了Queue之间的网络传输 84 | * 镜像集群模式 85 | * 每个Queue都有全部数据,减少了网络IO,写消息时才有网络IO 86 | * 缺点 87 | * 非分布式,若Queue数量很大时,会超出机器容量 88 | 89 | * RocketMQ 90 | * Producer与NameServer集群中一个节点(随机)建立长连接,定期从NameServer取Topic路由信息,并向提供Topic服务的Broker Master建立长连接,且定时向Broker发送心跳,Producer只能将消息发送到 Broker Master 91 | * Consumer同时和提供Topic服务的Master和Slave建立长连接,既可从Broker Master订阅消息,也可从Broker Slave订阅消息 92 | * Kafka 93 | * 分布式架构,多个partition副本,选举一个leader,生产者/消费者从leader生产/消费数据,leader负责数据同步 94 | 95 | # 如何保证不被重复消费(幂等性) 96 | 97 | * 为什么造成重复消费 98 | 99 | * 正常下,消费者消费完毕时会发确认消息给消息队列 ,消息队列将消息删除 100 | * RabbitMQ发送ACK确认消息 101 | * RocketMQ返回CONSUME_SUCCESS成功标志 102 | * Kafka每个消息有一个offset,kafka消费过后,提交offset,让消息队列知道已消费过 103 | 104 | * 造成重复消费的原因 105 | 106 | * 网络传输故障,确认信息没到消息队列,消息队列不知已消费,再次将消息分给其他消费者 107 | 108 | * 解决 109 | 110 | * 若用消息做数据库insert,给消息做唯一主键,重复消费会使主键冲突,避免脏数据 111 | * 若用消息做redis的set操作,set本身幂等,不用解决 112 | * 准备第三方介质,做消费记录,以redis为例,给消息分配一个全局id,只要消费消息,将以K-V形式写入redis,消费前去redis中查询有无消费记录 113 | 114 | # 如何保证消息的可靠性 115 | 116 | * 生产者弄丢数据 117 | 118 | * RabbitMQ提供transaction和confirm模式保证生产者不丢消息 119 | 120 | * 发送消息前开启事务(channel.txSelect()),发送过程中出现异常,事务回滚(channel.txRollback()),发送成功则提交事务(channel.txCommit()) 121 | * 缺点: 122 | 123 | * 吞吐量下降 124 | * 生产上使用confirm,一旦channel进入confirm,生产上发布的消息都会被指派一个唯一ID,一旦消息被投递,会发ACK给生产者(包含消息ID),生产者知道消息到达;若没能处理该消息,则会发Nack,进行重试 125 | 126 | * 消息队列弄丢数据 127 | * 配合confirm机制,消息持久化之后,再给producer发送ACK,若producer未收到ACK,生产者重发 128 | * 持久化步骤 129 | * 将queue持久化标识`durable=true`,代表持久化队列 130 | * 发送消息时将deliveryMode=2 131 | * 消费者弄丢数据 132 | * 原因 133 | * 一般采用自动确认消息模式,消费者自动确认收到的消息.此时RabbitMQ立即将消息删除,若消费者异常则会丢失该消息 134 | * 解决 135 | * 手动确认消息,消费完自己发送确认消息 136 | 137 | # 如何保证消息顺序性 138 | 139 | * 将消息按顺序放到同一消息队列(Kafka中为partition,RabbitMQ为queue) 140 | 141 | * 只用一个消费者消费该队列 142 | 143 | > 保证入队有序,出队以后的顺序交给消费者保证 144 | 145 | # 如何处理消息积压 146 | 147 | * 新建topic,新建30个partition 148 | * 将原来消费者消费的消息放入(改消费者代码)该topic中 149 | * 新增30个消费者,消费该partition 150 | 151 | # 顺序消息扩容的过程中,如何在不停写的情况下保证消息顺序? 152 | 153 | * 成倍扩容,实现扩容前后,同样的key,hash到原队列或者hash到新扩容队列 154 | * 扩容前,记录旧队列的最大位点 155 | * 对于每个Consumer Group,保证旧队列中的数据消费完,再消费新队列(先对新队列禁读) 156 | 157 | # 分布式消息队列中,如何对消息重放 158 | 159 | * 将Consumer Offset改至需要位置 160 | 161 | -------------------------------------------------------------------------------- /MQ/RocketMQ.md: -------------------------------------------------------------------------------- 1 | # 基本命令 2 | 3 | * 启动nameServer 4 | 5 | > nohup ./mqnamesrv & 6 | 7 | * 启动broker 8 | 9 | > nohup sh mqbroker -n 127.0.0.1:9876 -c ../conf/2m-noslave/broker-a.properties > broker.out & 10 | 11 | * broker查看 12 | 13 | > ./mqadmin clusterList -n 127.0.0.1:9876 14 | 15 | * 关闭broker 16 | 17 | > ./mqshutdown broker 18 | 19 | * 关闭 nameServ 20 | 21 | > ./mqshutdown namesrv 22 | 23 | # 概念模型 24 | 25 | * Produccer 26 | 27 | * 失败默认重试2次 28 | * 在事务消息机制中,若发送消息的producer在还未commit/rollback前挂掉,broker会在一段时间回查ProducerGroup里的其他实例,确认消息应该commit/rollback 29 | 30 | * Consumer 31 | 32 | * CLUSTERING模式下,一条消息只会被ConsumerGroup里的一个实例消费,但可被多个不同ConsumerGroup消费 33 | * BROADCASTING模式下,一条消息会被ConsumerGroup里的所有实例消费 34 | 35 | * Push Consumer 36 | * Consumer的一种,需要向Consumer对象注册监听 37 | * 使用pull实现,采用**长轮询** 38 | * Broker挂起客户端请求一段时间,若有新消息到达,立刻返回Consumer 39 | * 主动权在Consumer中,即使Broker有大量消息积压,也不会主动推送给Consumer 40 | * 挂起请求时需要占用资源,适合消息队列这种客户端可控的场景 41 | * Broker收到消息请求 42 | * 若队列里无新消息,通过循环不断查看状态,每次waitForRunning5s,再check.每3次check时,等待时间超过15s(suspendMaxTimeMills),返回空. 43 | * 若收到消息,通过notifyMessageArriving返回请求结果 44 | 45 | * Pull Consumer 46 | * Consumer的一种,需要用户主动请求Broker 拉取消息 47 | 48 | * Producer Group 49 | * 生产者集合,一般用于发送一类消息 50 | 51 | * Consumer Group 52 | * 消费者集合,一般用于接受一类消息进行消费 53 | 54 | 55 | 56 | * Broker 57 | * MQ消息服务(中转角色,用于消息存储与生产消费转发) 58 | * Broker存Topic信息,Topic,由多个队列组成,队列平均分散在多个Broker上 59 | * Producer发送机制保证消息尽量平均分配到所队列中 60 | 61 | * NameServer 62 | * 可以部署多个,相互之间独立 63 | * 其他角色向多个NameServer上报状态信息,从而达到热备份目的 64 | * 本身无状态,Broker,Topic等状态信息不会持久存储,由各角色上报存在内存 65 | 66 | * Topic 67 | 68 | * 默认4个队列,需要顺序消费的消息送同一队列 69 | 70 | * queueNums(队列数) 71 | 72 | * 客户端自动创建,最多创建8个队列,若要超过8个,可通过控制台创建/修改,Topic配置保存在store/config/topics.json 73 | * 消费负载均衡小粒度为队列,Consumer数量不在于队列数 74 | * 读写队列数(writeQueueNums/readQueueNums)为RocketMQ特有概念,可通过console修改 75 | 76 | # RocketMQ 生产者 77 | 78 | ## 核心参数 79 | 80 | * producerGroup -----组名 81 | * createTopicKey 82 | * defaultTopicQueueNums (默认为4) 83 | * sendMsgTimeout (单位:ms) 84 | * compressMsgBodyOverHowmuch (默认压缩字节4096) 85 | * retryTimesWhenSendFailed 86 | * retryAnotherBrokerWhenNotStoreOK(默认false) 87 | * maxMessageSize(默认128k) 88 | 89 | ## 主从同步机制解析 90 | 91 | * Master - Slave主从同步 92 | * 同步信息 93 | * 数据内容 94 | * 元数据信息 95 | * 元数据同步 96 | * Broker角色识别,为Slave启动同步任务 97 | * 消息同步 98 | * HAService 99 | * HAconnection 100 | * WaitNotifyObject 101 | 102 | ## 同步消息发送 103 | 104 | * producer.send(Message msg) 105 | 106 | ## 异步消息发送 107 | 108 | * producer.send(Message msg,SendCallback sendCallback) 109 | * 异步发送消息核心实现 110 | * DefaultMQProducerImpl 111 | 112 | # 包结构 113 | 114 | * rocketmq-broker 115 | * 主要的业务逻辑,消息收发,主从同步,pagecache 116 | * rocketmq-client 117 | * 客户端接口,比如生产者和消费者 118 | * rocketmq-example 119 | * 示例 120 | * rocketmq-common 121 | * 公用数据结构 122 | * rocketmq-distribution 123 | * 编译模块,编译输出等 124 | * rocketmq-filter 125 | * 进行Broker过滤的不感兴趣的消息传输,减小带宽压力 126 | * rocketmq-logappender rocketmq-logging 127 | * 日志相关 128 | * rocketmq-namesrv 129 | * Namesrv服务,用于服务协调 130 | * rocketmq-openmessaging 131 | * 对外提供服务 132 | * rocketmq-remoting 133 | * 远程调用接口,封装Netty底层通信 134 | * rocketmq-srvutil 135 | * 公用的工具方法,比如解析命令行参数 136 | * rocketmq-store 137 | * 消息存储 138 | * rocketmq-tools 139 | * 管理工具(mqadmin) 140 | 141 | # 集群环境 142 | 143 | * 单点模式 144 | * 主从模式 145 | * 保障消息即时性与可靠性 146 | * 双主模式 147 | * 双主双从模式 多主多从模式 148 | 149 | # 心跳机制 150 | 151 | * 单个Broker跟所有Namesrv保持心跳请求,间隔30秒,心跳请求包括当前Broker所有Topic 152 | 153 | * Namesrv反查Broker心跳信息,若某Broker2分内无心跳,则认为其下线,调整Topic跟Broker对应关系,但Namesrv不会主动通知Producer,Consumer有Broker宕机 154 | 155 | * Consumer跟Broker长连接,每30s发心跳.Broker每10s检查当前存活Consumer,若某Consumer2分内无心跳,则断开连接,并向Consumer Group其它实例发送通知,触发消费者集群的负载均衡 156 | 157 | * producer每30s从Namesrv获取Topic跟Broker映射关系,更新至本地内存,再与Topic涉及的所Broker建立长连接,每隔30s发一次心跳.Broker端每隔10s检查当前注册的Producer,若2分内无心跳,则断开连接 158 | 159 | # Namesrv开销 160 | 161 | * 维持心跳,提供Topic-Broker的关系数据 162 | * Broker向Namesrv发心跳时会带上所负责的Topic信息,若Topic太多(万级别),会导致一次心跳中Topic几十M,网络差时可能导致心跳失败 163 | 164 | # 消息存储 165 | 166 | * 由ConsumeQueue和CommitLog配合完成 167 | 168 | > ConsumeQueue只存储少量数据,消息主体通过CommitLog进行读写 169 | 170 | > 若某个消息只在CommitLog中有数据,在ConsumeQueue中没有,则消息无法消费,RocketMQ的事务利用了这一点 171 | 172 | * CommitLog 173 | * 消息主体以及元数据的存储主体,对CommitLog建立一个ConsumeQueue,每个ConsumeQueue对应一个MessageQueue,所以只要有CommitLog在.ConsumeQueue即使数据丢失,仍然可以恢复 174 | * ConsumeQueue 175 | * 消息的逻辑队列,存储Queue在CommitLog 中起始offset,log大小和MessageTag的hashCode,log大小和MessageTag的hashCode.每个Topic下的每个Queue都有一个对应 的ConsumeQueue 176 | 177 | 178 | 179 | -------------------------------------------------------------------------------- /elasticsearch/elasticsearch.md: -------------------------------------------------------------------------------- 1 | # Solr与ES 2 | 3 | * 区别 4 | * 当实时建立索引时,Solr会产生io阻塞,查询性能较差,ES具有明显优势 5 | * 随着数据量增加,Solr的搜索效率会变低,而ES却无明显变化 6 | * Solr支持更多格式数据,ES仅支持json 7 | 8 | # Logstash 9 | 10 | * 是ELK的中央数据流引擎,用于从不同目标(文件/数据存储/MQ)的收集的不同格式数据,经过过滤后支持输出到不同目的地(文件/MQ/redis/elasticsearch/kafka等)。 11 | 12 | # Kibana 13 | 14 | * 可以将es的数据通过友好的界面展示出来 15 | 16 | * 提供实时分析的功能 17 | 18 | * 测试 19 | 20 | ```json  21 | GET _analyze 22 | { 23 | "analyzer": "ik_smart", 24 | "text": "测试文档" 25 | } 26 | GET _analyze 27 | { 28 | "analyzer": "ik_max_word", 29 | "text": "测试文档" 30 | } 31 | ``` 32 | 33 | > IKAnalyzer.cfg.xml 34 | 35 | ```xml 36 | ?xml version="1.0" encoding="UTF-8"?> 37 | 38 | 39 | IK Analyzer 扩展配置 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | ``` 50 | 51 | 52 | 53 | # ElasticSearch 54 | 55 | * 面向文档,索引即为一个数据库,文档即为库中的数据 56 | * Types 逐渐被弃用 57 | 58 | ## 与关系型数据库对比 59 | 60 | | 关系型DB | ES | 61 | | ------------------ | --------------- | 62 | | 数据库(database) | 索引(indices) | 63 | | 表(tables) | types(弃用) | 64 | | 行(rows) | documents | 65 | | 字段(columns) | fields | 66 | 67 | ## 倒排索引 68 | 69 | 采用Lucene倒排索引作为底层,这种结构适用于快速的全文搜索,一个索引由文档中所有不重复的列表构成。对于每一个词,都有一个词包含它的文档列表。 70 | 71 | 例如,现在2个文档,每个文档包含的内容如下: 72 | 73 | ```yml 74 | study every day, good good up to forever # 文档1包含内容 75 | To forever, study every day,good good up # 文档2包含内容 76 | ``` 77 | 78 | 为了创建倒排索引,我们首先要将每个文档拆分成独立的词(或称为词条或者tokens),然后创建一个包含所有不重复的词条的排序列表,然后列出每个词条出现在哪个文档 79 | 80 | | Term | Doc_1 | Doc_2 | 81 | | ----- | ----- | ----- | 82 | | study | V | X | 83 | | To | X | X | 84 | | every | V | V | 85 | | day | v | v | 86 | 87 | ## IK分词器 88 | 89 | > elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.8.8/elasticsearch-analysis-ik-6.8.8.zip 90 | 91 | * 分词 92 | * 把一段中文或别的词划分成一个个关键字,我们在搜索时会把信息进行分词,会把数据库中或者索引库中的数据进行分词,然后进行一个匹配操作,默认的中文分词是将每个字看成一个词。显然是不够用的,我们需要安装中文分记词器IK来解决这个问题 93 | * 如果要使用中文,建议使用中文分词器 94 | * IK提供两个分词算法 95 | * ik_smart 为最少切分 96 | * ik_max_word 为最细粒度切分 97 | 98 | ## 增删改查 99 | 100 | | method | url | 描述 | 101 | | -------------- | ----------------------------------------------- | ---------------------- | 102 | | PUT | localhost:9200/索引名称/类型名称/文档id | 创建文档(指定文档id) | 103 | | POST | localhost:9200/索引名称/类型名称 | 创建文档(随机文档id) | 104 | | POST(更新推荐) | localhost:9200/索引名称/类型名称/文档id/_update | 修改文档 | 105 | | DELETE | localhost:9200/索引名称/类型名称/文档id | 删除文档 | 106 | | GET | localhost:9200/索引名称/类型名称/文档id | 查询文档通过文档id | 107 | | POST | localhost:9200/索引名称/类型名称/文档id/_search | 查询所有数据 | 108 | 109 | * 创建一个索引 110 | 111 | ```json  112 | PUT /索引名称/类型名称/文档id 113 | {请求体} 114 | --- 115 | PUT /test/type/doc1 116 | { 117 | "name":"王**", 118 | "age":100 119 | } 120 | ``` 121 | 122 | ## 复杂查询 123 | 124 | * _source 结果过滤 125 | * sort 排序 126 | * 分页 127 | * from(从第几个数据开始),size(返回数据量) 128 | 129 | * 布尔值bool 查询(多条件查询) 130 | * must ,should,must_not 131 | * 过滤器filter 132 | * range ,gte,gt,lt,lte 133 | * 多条件查询 134 | * 精确查询 term 135 | * 分词 136 | * term 直接查询精确查询 137 | * match 会使用分词器解析(先分析文档,再在分析后的文档中查询) 138 | * 高亮查询 139 | * highlight,fields,pre_tags,post_tags 140 | 141 | ## 集成SpringBoot 142 | 143 | * 批处理插入 144 | 145 | ```java 146 | for(int i=0;i 关于这个技术来打个比方,一个快递公司收件之后,发现目的地自己没有[站点](https://baike.baidu.com/item/%E7%AB%99%E7%82%B9),无法投送,则将此包裹转交给能到达目的地的快递公司(例如中国邮政)来投递。也就是说将快递公司已经封装好的包裹(类似于IPv6报文),外面再用[中国邮政](https://baike.baidu.com/item/%E4%B8%AD%E5%9B%BD%E9%82%AE%E6%94%BF)的包装再封装一次(类似于封装成IPv4报文),以便于这个包裹能在中国邮政的系统(IPv4海洋)中被正常投递。 83 | 84 | 隧道技术比双协议栈技术和协议转换技术(也都是用来进行IPv4和IPv6转换和过渡的技术)更复杂些,它的工作过程如下图所示。 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /调优/Arthas.md: -------------------------------------------------------------------------------- 1 | # [Arthas(阿尔萨斯)](https://alibaba.github.io/arthas/) 2 | 3 | ## Arthas解决的问题 4 | 5 | * Arthas是Alibaba开源的Java诊断工具 6 | * 解决的问题 7 | * 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception? 8 | * 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了? 9 | * 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗? 10 | * 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现! 11 | * 是否有一个全局视角来查看系统的运行状况? 12 | * 有什么办法可以监控到JVM的实时运行状态? 13 | * 怎么快速定位应用的热点,生成火焰图? 14 | 15 | ## [案例:排查函数调用异常](https://alibaba.github.io/arthas/arthas-tutorials?language=cn&id=arthas-advanced) 16 | 17 | * 启动Demo 18 | 19 | > wget https://github.com/hengyunabc/katacoda-scenarios/raw/master/demo-arthas-spring-boot.jar java -jar demo-arthas-spring-boot.jar 20 | 21 | * 启动之后,可以访问80端口: [https://2886795277-80-ollie02.environments.katacoda.com](https://2886795277-80-ollie02.environments.katacoda.com/) 22 | 23 | * 启动arthas-boot 24 | 25 | > wget https://alibaba.github.io/arthas/arthas-boot.jar java -jar arthas-boot.jar --target-ip 0.0.0.0 26 | 27 | * 目前,访问 http://localhost/user/0 ,会返回500异常: 28 | 29 | ``` 30 | {"timestamp":1550223186170,"status":500,"error":"Internal Server Error","exception":"java.lang.IllegalArgumentException","message":"id < 1","path":"/user/0"} 31 | ``` 32 | 33 | 但请求的具体参数,异常栈是什么呢? 34 | 35 | ### 查看UserController的 参数/异常 36 | 37 | 在Arthas里执行: 38 | 39 | ```bash 40 | watch com.example.demo.arthas.user.UserController * '{params, throwExp}' 41 | ``` 42 | 43 | 1. 第一个参数是类名,支持通配 44 | 2. 第二个参数是函数名,支持通配 45 | 46 | 访问 `curl http://localhost/user/0` ,`watch`命令会打印调用的参数和异常 47 | 48 | 可以看到实际抛出的异常是`IllegalArgumentException`。 49 | 50 | 可以输入 `Q` 或者 `Ctrl+C` 退出watch命令。 51 | 52 | 如果想把获取到的结果展开,可以用`-x`参数: 53 | 54 | ``` 55 | watch com.example.demo.arthas.user.UserController * '{params, throwExp}' -x 2 56 | ``` 57 | 58 | ### 返回值表达式 59 | 60 | 在上面的例子里,第三个参数是`返回值表达式`,它实际上是一个`ognl`表达式,它支持一些内置对象: 61 | 62 | - loader 63 | - clazz 64 | - method 65 | - target 66 | - params 67 | - returnObj 68 | - throwExp 69 | - isBefore 70 | - isThrow 71 | - isReturn 72 | 73 | ### 条件表达式 74 | 75 | 你可以利用这些内置对象来组成不同的表达式。比如返回一个数组: 76 | 77 | ```bash 78 | watch com.example.demo.arthas.user.UserController * '{params[0], target, returnObj}' 79 | ``` 80 | 81 | `watch`命令支持在第4个参数里写条件表达式,比如: 82 | 83 | ``` 84 | watch com.example.demo.arthas.user.UserController * returnObj 'params[0] > 100' 85 | ``` 86 | 87 | 当访问 https://2886795277-80-ollie02.environments.katacoda.com/user/1 时,`watch`命令没有输出 88 | 89 | 当访问 https://2886795277-80-ollie02.environments.katacoda.com/user/101 时,`watch`会打印出结果。 90 | 91 | ### 当异常时捕获 92 | 93 | `watch`命令支持`-e`选项,表示只捕获抛出异常时的请求: 94 | 95 | ```bash 96 | watch com.example.demo.arthas.user.UserController * "{params[0],throwExp}" -e 97 | ``` 98 | 99 | ### 按照耗时进行过滤 100 | 101 | watch命令支持按请求耗时进行过滤,比如: 102 | 103 | ```bash 104 | watch com.example.demo.arthas.user.UserController * '{params, returnObj}' '#cost>200' 105 | ``` 106 | 107 | ## [案例: 热更新代码](https://alibaba.github.io/arthas/arthas-tutorials?language=cn&id=arthas-advanced) 108 | 109 | 下面介绍通过`jad`/`mc`/`redefine` 命令实现动态更新代码的功能。 110 | 111 | 目前,访问 http://localhost/user/0 ,会返回500异常: 112 | 113 | ```bash 114 | curl http://localhost/user/0 115 | {"timestamp":1550223186170,"status":500,"error":"Internal Server Error","exception":"java.lang.IllegalArgumentException","message":"id < 1","path":"/user/0"} 116 | ``` 117 | 118 | 下面通过热更新代码,修改这个逻辑。 119 | 120 | ### jad反编译UserController 121 | 122 | ``` 123 | jad --source-only com.example.demo.arthas.user.UserController > /tmp/UserController.java 124 | ``` 125 | 126 | jad反编译的结果保存在 `/tmp/UserController.java`文件里了。 127 | 128 | 再打开一个`Terminal 3`,然后用vim来编辑`/tmp/UserController.java`: 129 | 130 | ``` 131 | vim /tmp/UserController.java 132 | ``` 133 | 134 | 比如当 user id 小于1时,也正常返回,不抛出异常. 135 | 136 | ### sc查找加载UserController的ClassLoader 137 | 138 | ``` 139 | sc -d *UserController | grep classLoaderHash 140 | $ sc -d *UserController | grep classLoaderHash 141 | classLoaderHash 1be6f5c3 142 | ``` 143 | 144 | 可以发现是 spring boot `LaunchedURLClassLoader@1be6f5c3` 加载的。 145 | 146 | ### mc 147 | 148 | 保存好`/tmp/UserController.java`之后,使用`mc`(Memory Compiler)命令来编译,并且通过`-c`参数指定ClassLoader: 149 | 150 | ```bash 151 | mc -c 1be6f5c3 /tmp/UserController.java -d /tmp 152 | $ mc -c 1be6f5c3 /tmp/UserController.java -d /tmp 153 | Memory compiler output: 154 | /tmp/com/example/demo/arthas/user/UserController.class 155 | Affect(row-cnt:1) cost in 346 ms 156 | ``` 157 | 158 | ### redefine 159 | 160 | 再使用`redefine`命令重新加载新编译好的`UserController.class`: 161 | 162 | ``` 163 | redefine /tmp/com/example/demo/arthas/user/UserController.class 164 | ``` 165 | 166 | ### 热修改代码结果 167 | 168 | `redefine`成功之后,再次访问 https://2886795277-80-ollie02.environments.katacoda.com/user/0 ,结果是: 169 | 170 | ``` 171 | { 172 | "id": 0, 173 | "name": "name0" 174 | } 175 | ``` 176 | 177 | ## [案例: 动态更新应用Logger Level](https://alibaba.github.io/arthas/arthas-tutorials?language=cn&id=arthas-advanced) 178 | 179 | ### 查找UserController的ClassLoader 180 | 181 | ```bash 182 | sc -d com.example.demo.arthas.user.UserController | grep classLoaderHash 183 | 184 | ``` 185 | 186 | ### 用ognl获取logger 187 | 188 | ``` 189 | ognl -c 1be6f5c3 '@com.example.demo.arthas.user.UserController@logger' 190 | 191 | ``` 192 | 193 | ### 单独设置UserController的logger level 194 | 195 | ``` 196 | ognl -c 1be6f5c3 '@com.example.demo.arthas.user.UserController@logger.setLevel(@ch.qos.logback.classic.Level@DEBUG)' 197 | ``` 198 | 199 | 再次获取`UserController@logger`,可以发现已经是`DEBUG`了: 200 | 201 | ``` 202 | ognl -c 1be6f5c3 '@com.example.demo.arthas.user.UserController@logger' 203 | ``` 204 | 205 | ### 修改logback的全局logger level 206 | 207 | 通过获取`root` logger,可以修改全局的logger level: 208 | 209 | ``` 210 | ognl -c 1be6f5c3 '@org.slf4j.LoggerFactory@getLogger("root").setLevel(@ch.qos.logback.classic.Level@DEBUG)' 211 | ``` 212 | 213 | -------------------------------------------------------------------------------- /Java/Java反射.md: -------------------------------------------------------------------------------- 1 | # 什么是反射 2 | 3 | * 在运行中获取任何类的所有属性和方法;对于任意一个对象,能够调用它的任意方法和属性 4 | 5 | * 功能 6 | * 在运行时判断任意一个对象所属的类; 7 | * 在运行时构造任意一个类的对象; 8 | * 在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法); 9 | * 在运行时调用任意一个对象的方法 10 | 11 | # 反射的主要用途 12 | 13 | * IDE中输入一个对象想调用其方法或属性时,按点号会自动列出 14 | * Spring框架(通过XML配置Bean),根据配置文件运行时动态加载不同的对象或类 15 | 16 | # 反射的实现 17 | 18 | * 获得 Class 对象 19 | 20 | * `class.getClass()` 21 | 22 | ```java 23 | StringBuilder str = new StringBuilder("123"); 24 | Class klass = str.getClass(); 25 | ``` 26 | 27 | * `Class.forName()` 28 | 29 | ```java 30 | public static Class forName(String className) 31 | //比如在 JDBC 开发中常用此方法加载数据库驱动: 32 | //...java 33 | Class.forName(driver); 34 | ``` 35 | 36 | * `ClassLoader.loadClass()` 37 | 38 | * 直接获取对象的Class 39 | 40 | ```java 41 | Class klass = int.class; 42 | Class classInt = Integer.TYPE; 43 | ``` 44 | 45 | * 判断是否为某个类的实例 46 | 47 | * `instanceof`关键字 48 | 49 | * Class对象的`isInstance()` 50 | 51 | ```java 52 | public native boolean isInstance(Object obj); 53 | ``` 54 | 55 | * 创建实例 56 | 57 | * `Class.forName()` 58 | * `ClassLoader.loadClass()` 59 | 60 | ## `Class.forName`与`Classloader.loadClass`区别 61 | 62 | * 初始化不同 63 | 64 | * `Class.forName()`会对类初始化;`loadClass()`只会装载和链接 65 | * `forName()`在类加载时会执行静态代码块(初始化);`loadClass()`只有在调用`newInstance()`时才会执行静态代码块 66 | 67 | * 类加载器不同 68 | 69 | * `Class.forName(String)`只有一个参数,使用调用`forName`方法代码的类加载器 70 | 71 | * `ClassLoader.loadClass()`是一个实例方法(非静态方法),调用时需要指定类加载器 72 | 73 | ```java 74 | ClassLoader classLoader = new ClassLoader() { 75 | @Override 76 | public Class loadClass(String name) throws ClassNotFoundException { 77 | return super.loadClass(name); 78 | } 79 | }; 80 | ``` 81 | 82 | 83 | 84 | * 获取方法 85 | * `getDeclaredMethods()` 86 | * 返回类或接口的所有方法,不包括继承的方法 87 | * `getMethods()` 88 | * 返回某类所有public方法,包括其继承类的public方法 89 | * `getMethod()` 90 | * 返回特定的方法,第一个参数为方法名称,后面参数为方法的参数的Class类型 91 | 92 | ## 获取构造器信息 93 | 94 | 获取类构造器的用法与上述获取方法的用法类似。主要是通过Class类的getConstructor方法得到Constructor类的一个实例,而Constructor类有一个newInstance方法可以创建一个对象实例: 95 | 96 | 此方法可以根据传入的参数来调用对应的Constructor创建对象实例。 97 | 98 | ## 获取类的成员变量(字段)信息 99 | 100 | 主要是这几个方法,在此不再赘述: 101 | 102 | * `getFiled`:访问公有的成员变量 103 | * `getDeclaredField`:所有已声明的成员变量,但不能得到其父类的成员变量 104 | 105 | getFileds 和 getDeclaredFields 方法用法同上(参照 Method)。 106 | 107 | ## 调用方法 108 | 当我们从类中获取了一个方法后,我们就可以用 invoke() 方法来调用这个方法。invoke 方法的原型为: 109 | 110 | ```java 111 | public Object invoke(Object obj, Object... args) 112 | throws IllegalAccessException, IllegalArgumentException, 113 | InvocationTargetException 114 | ``` 115 | 116 | 下面是一个实例: 117 | 118 | ```java 119 | public class test1 { 120 | public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { 121 | Class klass = methodClass.class; 122 | //创建methodClass的实例 123 | Object obj = klass.newInstance(); 124 | //获取methodClass类的add方法 125 | Method method = klass.getMethod("add",int.class,int.class); 126 | //调用method对应的方法 => add(1,4) 127 | Object result = method.invoke(obj,1,4); 128 | System.out.println(result); 129 | } 130 | } 131 | class methodClass { 132 | public final int fuck = 3; 133 | public int add(int a,int b) { 134 | return a+b; 135 | } 136 | public int sub(int a,int b) { 137 | return a+b; 138 | } 139 | } 140 | ``` 141 | 142 | ## 利用反射创建数组 143 | 144 | 数组在Java里是比较特殊的一种类型,它可以赋值给一个Object Reference。下面我们看一看利用反射创建数组的例子: 145 | 146 | ```java 147 | public static void testArray() throws ClassNotFoundException { 148 | Class cls = Class.forName("java.lang.String"); 149 | Object array = Array.newInstance(cls,25); 150 | //往数组里添加内容 151 | Array.set(array,0,"hello"); 152 | Array.set(array,1,"Java"); 153 | Array.set(array,2,"fuck"); 154 | Array.set(array,3,"Scala"); 155 | Array.set(array,4,"Clojure"); 156 | //获取某一项的内容 157 | System.out.println(Array.get(array,3)); 158 | } 159 | ``` 160 | 161 | 其中的Array类为java.lang.reflect.Array类。我们通过Array.newInstance()创建数组对象,它的原型是: 162 | 163 | ```java 164 | public static Object newInstance(Class componentType, int length) 165 | throws NegativeArraySizeException { 166 | return newArray(componentType, length); 167 | } 168 | ``` 169 | 170 | 而 newArray 方法是一个 native 方法,它在 HotSpot JVM 里的具体实现我们后边再研究,这里先把源码贴出来: 171 | 172 | ```java 173 | private static native Object newArray(Class componentType, int length) 174 | throws NegativeArraySizeException; 175 | ``` 176 | 177 | 源码目录: 178 | 179 | > openjdk\hotspot\src\share\vm\runtime\reflection.cpp 180 | 181 | ```c++ 182 | arrayOop Reflection::reflect_new_array(oop element_mirror, jint length, TRAPS) { 183 | if (element_mirror == NULL) { 184 | THROW_0(vmSymbols::java_lang_NullPointerException()); 185 | } 186 | if (length < 0) { 187 | THROW_0(vmSymbols::java_lang_NegativeArraySizeException()); 188 | } 189 | if (java_lang_Class::is_primitive(element_mirror)) { 190 | Klass* tak = basic_type_mirror_to_arrayklass(element_mirror, CHECK_NULL); 191 | return TypeArrayKlass::cast(tak)->allocate(length, THREAD); 192 | } else { 193 | Klass* k = java_lang_Class::as_Klass(element_mirror); 194 | if (k->oop_is_array() && ArrayKlass::cast(k)->dimension() >= MAX_DIM) { 195 | THROW_0(vmSymbols::java_lang_IllegalArgumentException()); 196 | } 197 | return oopFactory::new_objArray(k, length, THREAD); 198 | } 199 | } 200 | ``` 201 | 202 | 另外,Array 类的 set 和 get 方法都为 native 方法,在 HotSpot JVM 里分别对应 Reflection::array_set 和 Reflection::array_get 方法,这里就不详细解析了。 203 | 204 | # 反射缺点 205 | 206 | * 额外消耗系统资源,若不需动态创建对象,则不需要用反射 207 | * 反射调用方法时可忽略权限检查,可能会破坏封装性而导致安全问题 208 | 209 | 210 | -------------------------------------------------------------------------------- /计算机网络/无线网.md: -------------------------------------------------------------------------------- 1 | 2 | # 隐藏终端 3 | 4 | "隐藏终端"(Hidden node problem/Hidden terminal problem [1] ):在通信领域,基站A向基站B发送信息,基站C未侦测到A也向B发送,故A和C同时将信号发送至B,引起信号冲突,最终导致发送至B的信号都丢失了。"隐藏终端"多发生在大型单元中(一般在室外环境),这将带来效率损失,并且需要错误恢复机制。当需要传送大容量文件时,尤其需要杜绝"隐藏终端"现象的发生。 5 | 6 | 7 | 8 | # 暴露终端 9 | 10 | **简介** 11 | 12 | 暴露终端是指在发送节点的覆盖范围内而在接收节点的覆盖范围外的节点,暴露终端因听到发送节点的发送而可能延迟发送。但是,它其实是在接收节点的通信范围之外,它的发送不会造成冲突。这就引入了不必要的延时。 13 | 14 | ## 原因和解决方法 15 | 16 | 编辑 17 | 18 | ### 隐藏终端和暴露终端问题产生的原因 19 | 20 | 由于ad hoc网络具有动态变化的网络拓扑结构,且工作在无线环境中,采用异步通信技术,各个移动节点共享同一个通信信道,存在信道分配和竞争问题;为了提高信道利用率,移动节点电台的频率和发射功率都比较低;并且信号受无线信道中的噪声、信道衰落和障碍物的影响,因此移动节点的通信距离受到限制,一个节点发出的信号,网络中的其它节点不一定都能收到,从而会出现“隐藏终端”和“暴露终端”问题。 21 | 22 | 隐藏终端和暴露终端问题对ad hoc网络的影响: 23 | 24 | 隐藏终端”和“暴露终端”的存在,会造成ad hoc网络时隙资源的无序争用和浪费,增加数据碰撞的概率,严重影响网络的吞吐量、容量和数据传输时延。在ad hoc网络中,当终端在某一时隙内传送信息时,若其隐藏终端在此时隙发生的同时传送信息,就会产生时隙争用冲突。受隐藏终端的影响,接收端将因为数据碰撞而不能正确接收信息,造成发送端的有效信息的丢失和大量时间的浪费(数据帧较长时尤为严重),从而降低了系统的吞吐量和量。 25 | 26 | 当某个终端成为暴露终端后,由于它侦听到另外的终端对某一时隙的占用信息,而放弃了预约该时隙进行信息传送。其实,因为源终端节点和目的终端节点都不一样,暴露终端是可以占用这个时隙来传送信息的。这样,就造成了时隙资源的浪费。 27 | 28 | ### 隐藏终端和暴露终端问题的解决方法 29 | 30 | 解决隐藏终端问题的思路是使接收节点周围的邻居节点都能了解到它正在进行接收,目前实现的方法有两种:一种是接收节点在接收的同时发送忙音来通知邻居节点,即BTMA系列;另一种方法是发送节点在数据发送前与接收节点进行一次短控制消息握手交换,以短消息的方式通知邻居节点它即将进行接收,即RTS/CTS方式。这种方式是目前解决这个问题的主要趋势,如已经提出来的CSMA/CA、MACA、MACAW等。还有将两种方法结合起来使用的多址协议,如DBTMA。 31 | 32 | 对于隐藏发送终端问题,可以使用控制分组进行握手的方法加以解决。一个终端发送数据之前,首先要发送请求发送分组,只有听到对应该请求分组的应答信号后才能发送数据,而没有收到此应答信号的其他终端必须延迟发送。 33 | 34 | 在单信道条件下使用控制分组的方法只能解决隐藏发送终端,无法解决隐藏接收终端和暴露终端问题。为此,必须采用双信道的方法。即利用数据信道收发数据,利用控制信道收发控制信号 . 35 | 36 | 37 | 38 | # Ad hoc 39 | 40 | Ad-Hoc([点对点](https://baike.baidu.com/item/%E7%82%B9%E5%AF%B9%E7%82%B9/7452984))模式:ad-hoc模式就和以前的直连双绞线概念一样,是P2P的连接,所以也就无法与其它[网络沟通](https://baike.baidu.com/item/%E7%BD%91%E7%BB%9C%E6%B2%9F%E9%80%9A/8445726)了。一般无线终端设备像PMP、[PSP](https://baike.baidu.com/item/PSP)、DMA等用的就是ad-hoc模式。 在家庭[无线局域网](https://baike.baidu.com/item/%E6%97%A0%E7%BA%BF%E5%B1%80%E5%9F%9F%E7%BD%91)的组建,我想大家都知道最简单的莫过于两台安装有[无线网卡](https://baike.baidu.com/item/%E6%97%A0%E7%BA%BF%E7%BD%91%E5%8D%A1/292243)的计算机实施无线互联,其中一台计算机连接Internet就可以共享[带宽](https://baike.baidu.com/item/%E5%B8%A6%E5%AE%BD/266879)。如右图所示,一个基于Ad-Hoc结构的[无线局域网](https://baike.baidu.com/item/%E6%97%A0%E7%BA%BF%E5%B1%80%E5%9F%9F%E7%BD%91/176200)便完成了组建。 41 | 42 | ![img](https://gss2.bdstatic.com/9fo3dSag_xI4khGkpoWK1HF6hhy/baike/c0%3Dbaike72%2C5%2C5%2C72%2C24/sign=0f5b23b881cb39dbd5cd6f04b17f6241/d6ca7bcb0a46f21f6c961901f6246b600d33aec6.jpg) 43 | 44 | 45 | 46 | # 蓝牙 47 | 48 | 49 | 50 | 蓝牙主设备最多可与一个微微网(一个采用蓝牙技术的临时计算机网络)中的七个设备通讯, 当然并不是所有设备都能够达到这一最大量。设备之间可通过协议转换角色,从设备也可转换为主设备(比如,一个头戴式耳机如果向手机发起连接请求,它作为连接的发起者,自然就是主设备,但是随后也许会作为从设备运行。) 51 | 52 | 蓝牙核心规格提供两个或以上的微微网连接以形成分布式网络,让特定的设备在这些微微网中自动同时地分别扮演主和从的角色。 53 | 54 | 数据传输可随时在主设备和其他设备之间进行(应用极少的广播模式除外)。主设备可选择要访问的从设备;典型的情况是,它可以在设备之间以轮替的方式快速转换。因为是主设备来选择要访问的从设备,理论上从设备就要在接收槽内待命,主设备的负担要比从设备少一些。主设备可以与七个从设备相连接,但是从设备却很难与一个以上的主设备相连。规格对于散射网中的行为要求是模糊的。 55 | 56 | # 载波侦听多路访问/冲突避免(CSMA/CA) 57 | 58 | ## 工作原理 59 | 60 | (1)首先检测信道是否有使用,如果检测出信道空闲,则等待一段随机时间后,才送出数据。 61 | 62 | (2)接收端如果正确收到此帧,则经过一段时间间隔后,向发送端发送确认帧ACK。 63 | 64 | (3)发送端收到ACK帧,确定数据正确传输,在经历一段时间间隔后,会出现一段空闲时间。 65 | 66 | ## 工作流程 67 | 68 | CSMA/CA协议的工作流程分为两个分别是: 69 | 70 | 1.送出数据前,监听媒体状态,等没有人使用媒体,维持一段时间后,才送出数据。由于每个设备采用的随机时间不同,所以可以减少冲突的机会。 71 | 72 | 2.送出数据前,先发送一段小小的请求传送[报文](https://baike.baidu.com/item/%E6%8A%A5%E6%96%87)(RTS : Request to Send)给目标端,等待目标端回应 CTS: Clear to Send 报文后,才开始传送。 利用RTS-CTS握手(handshake)程序,确保接下来传送资料时,不会被碰撞。 同时由於RTS-CTS[封包](https://baike.baidu.com/item/%E5%B0%81%E5%8C%85)都很小,让传送的无效开销变小。 73 | 74 | CSMA/CA通过这两种方式来提供无线的共享访问,这种显式的ACK机制在处理无线问题时非常有效。然而不管是对于802.11还是802.3来说,这种方式都增加了额外的负担,所以802.11网络和类似的Ethernet网比较总是在性能上稍逊一筹。 75 | 76 | ## 主要差别 77 | 78 | [CSMA/CD](https://baike.baidu.com/item/CSMA%2FCD):带有[冲突检测](https://baike.baidu.com/item/%E5%86%B2%E7%AA%81%E6%A3%80%E6%B5%8B)的[载波监听多路访问](https://baike.baidu.com/item/%E8%BD%BD%E6%B3%A2%E7%9B%91%E5%90%AC%E5%A4%9A%E8%B7%AF%E8%AE%BF%E9%97%AE),可以检测冲突,但无法“避免” 79 | 80 | CSMA/CA:带有冲突避免的载波监听多路访问,发送包的同时不能检测到信道上有无冲突,只能尽量“避免”; 81 | 82 | 1.两者的传输介质不同,CSMA/CD用于总线式[以太网](https://baike.baidu.com/item/%E4%BB%A5%E5%A4%AA%E7%BD%91),而CSMA/CA则用于[无线局域网](https://baike.baidu.com/item/%E6%97%A0%E7%BA%BF%E5%B1%80%E5%9F%9F%E7%BD%91)[802.11a](https://baike.baidu.com/item/802.11a)/b/g/n等等; 83 | 84 | 2.检测方式不同,CSMA/CD通过电缆中电压的变化来检测,当数据发生碰撞时,电缆中的电压就会随着发生变化;而CSMA/CA采用能量检测(ED)、载波检测(CS)和能量载波混合检测三种检测信道空闲的方式; 85 | 86 | 3.WLAN中,对某个[节点](https://baike.baidu.com/item/%E8%8A%82%E7%82%B9)来说,其刚刚发出的信号强度要远高于来自其他节点的信号强度,也就是说它自己的信号会把其他的信号给覆盖掉; 87 | 88 | 4.本节点处有冲突并不意味着在接收节点处就有冲突。 89 | 90 | 综上,在WLAN中实现CSMA/CD是比较困难的 91 | 92 | # 网络分配矢量(NAV) 93 | 94 | NAV=Network Allocation Vector 95 | 96 | 是网络工程的专业术语:网络分配矢量 97 | 98 | ![img](https://gss0.bdstatic.com/-4o3dSag_xI4khGkpoWK1HF6hhy/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=46bc5f328bd4b31ce4319ce9e6bf4c1a/8c1001e93901213fb45f0aad54e736d12f2e9556.jpg) 99 | 100 | 只要NAV的数值不为零,就代表媒介处于忙碌状态,此即虚拟载波监听功能。当NAV为零时,虚拟载波监听功能会显示媒介处于空闲状态。 101 | 102 | 利用NAV可以保证工作站的原子操作(atomic operation )的正常进行,如下图所示的RTS/CTS过程即属于一种基本操作。(注:原子操作指不可被中断的操作) 103 | 104 | NAV 由发射台传输到接收台 105 | 106 | # 无线访问接入点(WirelessAccessPoint)(AP) 107 | 108 | 109 | AP就是传统有线网络中的HUB,也是组建小型无线局域网时最常用的设备。AP相当于一个连接有线网和无线网的桥梁,其主要作用是将各个无线网络[客户端](https://baike.baidu.com/item/%E5%AE%A2%E6%88%B7%E7%AB%AF/101081)连接到一起,然后将无线网络接入以太网。 110 | 111 | 大多数的[无线AP](https://baike.baidu.com/item/%E6%97%A0%E7%BA%BFAP)都支持多用户接入、[数据加密](https://baike.baidu.com/item/%E6%95%B0%E6%8D%AE%E5%8A%A0%E5%AF%86/11048982)、多速率发送等功能,一些产品更提供了完善的无线网络管理功能。对于家庭、办公室这样的小范围无线局域网而言,一般只需一台无线AP即可实现所有计算机的无线接入。 112 | 113 | AP的室内覆盖范围一般是30m~100m,不少厂商的AP产品可以互联,以增加WLAN覆盖面积。也正因为每个AP的覆盖范围都有一定的限制,正如手机可以在基站之间漫游一样,无线局域网客户端也可以在AP之间漫游。 114 | 115 | AP的一个重要的功能就是中继,所谓中继就是在两个无线点间把无线信号放大一次,使得远端的客户端可以接受到更强的无线信号。例如我在a点放置一个AP,而在c点有一个客户端,之间有120米的距离,从a点到c点信号已经削弱很多,于是我在中途60米处的b点放一个AP做为中继,这样c点的客户端的信号就可以有效的增强,保证了传输速度和稳定性。 116 | 117 | 118 | 119 | # COA地址 120 | 121 | ## 转交地址 122 | 123 | 转交地址(通常称为CoA)使用于因特网[路由](https://baike.baidu.com/item/%E8%B7%AF%E7%94%B1),是分配给移动设备的临时IP地址。它允许归属地代理向移动设备转发消息。由于与所在网络的不匹配,用于标识主机的设备IP地址在拓扑上是不正确的,所以需要独立的IP地址用于分别标识主机和在全局IP网络内的位置。 124 | 125 | ## 地址分配 126 | 127 | 移动结点可以通过两种不同的方式获取转交地址: 128 | 129 | 外部代理转交地址(Foreign Agent CoA):外部代理使用的相同的CoA,MN负责接收CoA,实现某种类型的[网络地址转换](https://baike.baidu.com/item/%E7%BD%91%E7%BB%9C%E5%9C%B0%E5%9D%80%E8%BD%AC%E6%8D%A2)(NAT)网络。在外部网络中的所有移动结点具有相同的CoA。 130 | 131 | 同位(Co-located)转交地址:外部网络中的每个移动结点都有自己的CoA,通常由[DHCP服务器](https://baike.baidu.com/item/DHCP%E6%9C%8D%E5%8A%A1%E5%99%A8)负责分配。这种情况经常发生在外部代理还没有部署的网络中。 -------------------------------------------------------------------------------- /linux/linux.md: -------------------------------------------------------------------------------- 1 | # [常用linux命令](https://mp.weixin.qq.com/s/HtLwChoLzqhbM4pKldLDng) 2 | 3 | ```bash 4 | ps aux|grep java 查看java进程 5 | ps aux 查看所有进程 6 | ps –ef|grep tomcat 查看所有有关tomcat的进程 7 | ps -ef|grep --color java 高亮要查询的关键字 8 | kill -9 19979 终止线程号位19979的进程 9 | ``` 10 | 11 | - 整机 12 | - `top` 13 | - 查看系统资源占用情况 14 | - `uptime` 15 | - 系统运行时间 16 | - `load average`负载情况 17 | - CPU 18 | - `vmstat -n 2 3` 19 | - 2:采样的时间间隔数(s);3:采样的次数 20 | - `us+sy>80`说明cpu不足 21 | - `mpstat -P ALL 2` 22 | - 查看所有CPU核信息 23 | - 内存 24 | - `free -m`查看总的内存 25 | - `pidstat -p PID -r 采样间隔秒数` 26 | - 硬盘 27 | - `df -h` 28 | - h表示human 29 | - 磁盘IO 30 | - `iostat -xdk 2 3` 31 | - 网络IO 32 | - `ifstat` 33 | 34 | # 查找特定的文件 35 | 36 | > find path [options] params 37 | 38 | ```shell 39 | find ~ -name "target3.java" //精确查找 40 | find ~ -name "target*" // 模糊查找文件 41 | find ~ -iname "targer*" //忽略大小写 42 | 43 | man find //更多关于 find 的指令说明 44 | ``` 45 | 46 | # 检索文件内容 47 | 48 | >grep [options] pattern file 49 | 50 | ```shell 51 | grep "hadoop" README* 52 | ``` 53 | 54 | # 管道操作符 55 | 56 | 可将指令连接起来,前一个指令的输出作为后一个指令的输入 57 | 58 | ```shell 59 | find ~ | grep "Hadoop" 60 | ``` 61 | 62 | * 管道只处理正确的输出,不执行错误的输出 63 | * 右边命令必须能够接收检索文件输入流,否则传递过程中数据会被抛弃 64 | * sed,awk,grep,cut,head,top,less,more,wc,join,sort,split 65 | 66 | > grep -o 只输出符合 RE 的字符串 67 | 68 | ```shell 69 | grep 'partial\[true\]' *.info,log | grep -o 'engine\[[0-9a-z]\]' 70 | ``` 71 | 72 | >grep -v //过滤掉指令本身 73 | 74 | ```shell 75 | ps -ef | grep ’tomcat‘ | grep -v ’tomcat‘ 76 | ``` 77 | 78 | 79 | 80 | # 对文件内容做统计 81 | 82 | > awk [options] 'cmd' file 83 | 84 | * 一次读取一行文本,按输入分隔符进行切片,切成多个组成部分 85 | * 将切片直接保存在内建的变量中,$1,$2...($0表示行的全部) 86 | * 支持对单个切片的判断,支持循环判断,默认分隔符为空格 87 | 88 | ```shell 89 | awk '{print $1,$4}' README.txt //打印第一个和第4个切片的内容 90 | ``` 91 | 92 | ```shell 93 | awk '$1=="tcp" && $2 == 1 {print $0}' netstat.txt 94 | ``` 95 | 96 | ```shell 97 | awk '($1=="tcp" && $2 == 1) || NR==1 {print $0}' netstat.txt //带有表头的数据 98 | ``` 99 | 100 | ```shell 101 | awk -F "," '{print $2}' test.txt //-F 以逗号为分隔符 102 | ``` 103 | 104 | ```shell 105 | grep 'partial\[true\]' *.info,log | grep -o 'engine\[[0-9a-z]\]' | 106 | awk '{engineer[$1]++}END{for(i in enginearr) print i "\t" enginearr[i]}' 107 | ``` 108 | 109 | # 批量替换文件内容 110 | 111 | > sed [option] 'sed command' filename 112 | 113 | * 全名 stream editor ,流编辑器 114 | * 适合用于对文本的编辑 115 | 116 | ```shell 117 | sed 's/^Str/String/' replace.java //将Str打头的字符替换为String,不改变文档内容 118 | ``` 119 | 120 | ```shell 121 | sed -i 's/^Str/String/' replace.java //将Str打头的字符替换为String,改变文档内容 122 | ``` 123 | 124 | ```shell 125 | sed -i 's/\.$/\;/' replace.java //将 ’.‘ 替换为’;‘ 126 | ``` 127 | 128 | ```shell 129 | sed -i 's/Jack/me/' replace.java //将Jack替换为me 但只能替换一个Jack 130 | ``` 131 | 132 | ```shell 133 | sed -i 's/Jack/me/g' replace.java //将所有Jack替换为me 134 | ``` 135 | 136 | ```shell 137 | sed -i '/^ *$/d' replace.java //删除空行 138 | ``` 139 | 140 | ```shell 141 | sed -i 'Integer/d' replace.java //删除Integer所在行 142 | ``` 143 | 144 | 145 | 146 | # 查看物理CPU和每颗CPU的核数 147 | 148 | ```shell 149 | cat /proc/cpuinfo|grep -c 'physical id' 150 | 4 151 | cat /proc/cpuinfo|grep -c 'processor' 152 | 4 153 | ``` 154 | 155 | # 查看系统负载有两个常用的命令 156 | 157 | ```shell 158 | w 159 | 10:57:38 up 14 min, 1 user, load average: 0.00, 0.00, 0.00 160 | USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT 161 | root pts/0 192.168.147.1 18:44 0.00s 0.10s 0.00s w 162 | uptime 163 | 10:57:47 up 14 min, 1 user, load average: 0.00, 0.00, 0.00 164 | ``` 165 | 166 | 其中load average即系统负载,三个数值分别表示一分钟、五分钟、十五分钟内系统的平均负载,即平均任务数。 167 | 168 | # vmstat r, b, si, so, bi, bo 这几列表示什么含义呢? 169 | 170 | 答: 171 | 172 | ``` 173 | [root@centos6 ~ 10:57 #39]# vmstat 174 | procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- 175 | r b swpd free buff cache si so bi bo in cs us sy id wa st 176 | 0 0 0 1783964 13172 106056 0 0 29 7 15 11 0 0 99 0 0 177 | ``` 178 | 179 | - r即running,表示正在跑的任务数 180 | - b即blocked,表示被阻塞的任务数 181 | - si表示有多少数据从交换分区读入内存 182 | - so表示有多少数据从内存写入交换分区 183 | - bi表示有多少数据从磁盘读入内存 184 | - bo表示有多少数据从内存写入磁盘 185 | 186 | 简记: 187 | 188 | - i --input,进入内存 189 | - o --output,从内存出去 190 | - s --swap,交换分区 191 | - b --block,块设备,磁盘 192 | 193 | 单位都是KB 194 | 195 | # buffer和cache如何区分 196 | 197 | * CPU写数据到磁盘时,先将数据存入buffer 198 | * CPU读数据时,先将数据存入cache 199 | 200 | # [CPU占用过高分析](https://blog.csdn.net/u011277123/article/details/103495338) 201 | 202 | * **定位进程** 203 | * 登录服务器,执行top命令,查看CPU占用情况 204 | * 通过以上命令,我们可以看到,进程ID为1893的Java进程的CPU占用率达到了181%,基本可以定位到是我们的Java应用导致整个服务器的CPU占用率飙升。 205 | * **定位线程** 206 | * 通过top -Hp 1893命令,我们可以发现,当前1893这个进程中,ID为4519的线程占用CPU最高。 207 | * **定位代码** 208 | * 通过jstack命令,查看栈信息 209 | * 通过以上代码,我们可以清楚的看到,BeanValidator.java的第30行是有可能存在问题的。 210 | 211 | 212 | 213 | # 统计文件中出现次数最多的前10个词 214 | 215 | ```shell 216 | cat words.txt |sort |uniq -c |sort -k1,1nr |head -10 217 | ``` 218 | 219 | * `sort` 对一行一个单词的列表进行排序 220 | * `uniq -c`对排序好的单词列表统计每个单词出现的次数 221 | * 再用`sort`按照单词出现的次数从大到小排序,若出现频率相同,再按字母顺序排序 222 | * `sort -n `使用纯数字进行排序 223 | * `sort -r`倒序 224 | * `sork -k` 指定那个字段 225 | * `sort -t`指定分隔符 226 | 227 | # VIM 228 | 229 | * 打开与退出 230 | 231 | * vi file: 打开文件 file 232 | * :q : 退出 vi 编辑器 233 | * :wq: 保存缓冲区的修改并退出编辑器 234 | * :q!: 不保存直接退出 235 | * :w 保存缓冲区内容至默认的文件 236 | * :w file 保存缓冲区内容至 file 文件 237 | 238 | * 插入文本 239 | 240 | * a : 在当前光标的右边插入文本 241 | * A : 在当前光标行的末尾插入文本 242 | * i : 在当前光标的左边插入文本 243 | * I : 在当前光标所在行的开始处插入文本 244 | * o: 在当前行在下面新建一行 245 | * O:在当前行的上面新建一行 246 | * R:替换当前光标位置以及以后的若干文本 247 | * J:连接光标所在行和下一行 248 | 249 | * 删除文本 250 | 251 | * x: 删除一个字符 252 | * dd: 删除一行 253 | * ndd: 删除 n 行 254 | * u: 撤销上一次操作 255 | * U: 撤销对当前行的所有操作 256 | 257 | * 搜索 258 | 259 | * /word 从前向后搜索第一个出现的 word 260 | 261 | * ? word 从后向前搜索第一个出现的 word 262 | 263 | * 设置行号 264 | 265 | * :set nu 在屏幕上显示行号 266 | * :set nonu 取消行号 267 | 268 | # [Linux操作系统网络服务器模型](https://yq.aliyun.com/articles/131978) 269 | 270 | * 并发服务器 271 | 272 | * 并发服务器就是在同一个时刻可以处理来自多个客户端的请求; 273 | * 循环服务器 274 | * 循环服务器是指服务器在同一时刻指可以响应一个客户端的请求 275 | 276 | 277 | 278 | # [SIGINT SIGTERM SIGKILL区别](https://www.jianshu.com/p/f6dfbf51c541) 279 | 280 | * SIGINT SIGTERM SIGKILL都是结束/终止进程 281 | 282 | * **SIGINT信号为ctrl+c发送出来的信号,该信号只能结束前台进程**,信号被当前进程树接收到,也就是说,不仅当前进程会收到信号,它的子进程也会收到; 283 | 284 | * SIGTERM可以被阻塞,**kill不加任何参数的时候发送的就是这个信号,只有当前进程收到信号,子进程不会收到**。如果当前进程被kill了,那么它的子进程的父进程将会是init,也就是pid为1的进程; 285 | 286 | * **SIGKILL是不能被捕获的,程序收到这个信号后,一定会退出。这就是kill -9一定能保证将程序杀死的原因。** 287 | 288 | -------------------------------------------------------------------------------- /Docker/docker基础.md: -------------------------------------------------------------------------------- 1 | # Docker相关命令 2 | 3 | ## 容器生命周期管理 4 | 5 | ```properties 6 | docker run :创建一个新的容器并运行一个命令 7 | docker start: 启动一个或多个已经被停止的容器 8 | docker stop: 停止一个运行中的容器 9 | docker restart:重启容器 10 | docker kill : 杀掉一个运行中的容器 11 | docker rm :删除一个或多个容器 12 | docker pause:暂停容器中所有的进程 13 | docker unpause:恢复容器中所有的进程 14 | docker create: 创建一个新的容器但不启动它 15 | 16 | ``` 17 | 18 | ### 修改容器内容 19 | 20 | > docker exec 21 | 22 | * 容器启动后,可以使用`docker exec -it xx bash`命令再次进行修改 23 | 24 | ### 在运行的容器中执行命令 25 | 26 | ## 容器操作 27 | 28 | ```properties 29 | docker ps : 列出容器 30 | docker inspect: 获取容器/镜像的元数据 31 | docker top :查看容器中运行的进程信息,支持ps命令参数 32 | docker attach: 连接到正在运行中的容器 33 | docker events: 从服务器获取实时事件 34 | docker logs:获取容器的日志 35 | docker wait: 阻塞运行直到容器停止,然后打印出它的退出代码 36 | docker export :将文件系统作为一个tar归档文件导出到STDOUT 37 | docker port :列出指定的容器的端口映射,或者查找将PRIVATE_PORT NAT到面向公众的端口 38 | ``` 39 | 40 | ## 容器rootfs命令 41 | 42 | ```properties 43 | docker commit :从容器创建一个新的镜像(提交镜像) 44 | docker cp :用于容器与主机之间的数据拷贝 45 | docker diff : 检查容器里文件结构的更改 46 | ``` 47 | 48 | ## 镜像仓库 49 | 50 | ```properties 51 | docker login : 登陆到一个Docker镜像仓库,如果未指定镜像仓库地址,默认为官方仓库 Docker Hub 52 | docker logout : 登出一个Docker镜像仓库,如果未指定镜像仓库地址,默认为官方仓库 Docker Hub 53 | docker pull : 从镜像仓库中拉取或者更新指定镜像(下载镜像) 54 | docker push : 将本地的镜像上传到镜像仓库,要先登陆到镜像仓库 55 | docker search : 从Docker Hub查找镜像 56 | ``` 57 | 58 | ## 本地镜像管理 59 | 60 | ```properties 61 | docker images : 列出本地镜像 62 | docker rmi : 删除本地一个或多少镜像 63 | docker tag : 标记本地镜像,将其归入某一仓库 64 | docker history : 查看指定镜像的创建历史 65 | docker save : 将指定镜像保存成 tar 归档文件 66 | docker import : 从归档文件中创建镜像 67 | ``` 68 | 69 | ### 构建镜像 70 | 71 | > docker build 72 | 73 | * 根据 Dockerfile 文件及上下文构建新 Docker 镜像 74 | 75 | * 通过`.dockerignore`文件排除上下文目录下不需要的文件和目录。 76 | 77 | * Dockerfile 一般位于构建上下文的根目录下,也可以通过`-f`指定该文件的位置 78 | 79 | ```dockerfile 80 | docker build -f /path/to/a/Dockerfile . 81 | ``` 82 | 83 | * 镜像标签 84 | 85 | * 如果存在多个仓库下,或使用多个镜像标签,就可以使用多个`-t`参数: 86 | 87 | ``` 88 | docker build -t nginx/v3:1.0.2 -t nginx/v3:latest . 89 | ``` 90 | 91 | * 缓存 92 | 93 | * Docker 守护进程会一条一条的执行 Dockerfile 中的指令,而且会在每一步提交并生成一个新镜像,最后会输出最终镜像的ID。 94 | * 生成完成后,Docker 守护进程会自动清理你发送的上下文。 95 | * Docker 会重用已生成的中间镜像,以加速docker build的构建速度 96 | * 可以通过`--cache-from`指定缓存。指定后将不再使用本地生成的镜像链,而是从镜像仓库中下载。 97 | 98 | ## info|version 99 | 100 | ```properties 101 | docker info : 显示 Docker 系统信息,包括镜像和容器数。。 102 | docker version :显示 Docker 版本信息 103 | ``` 104 | 105 | # Dockerfile 106 | 107 | * 基础镜像信息 108 | 109 | * 维护者信息 110 | 111 | * 镜像操作指令 112 | 113 | * 容器启动执行指令 114 | 115 | * Dockerfile 指令 116 | 117 | * FROM 118 | 119 | * dockerfile中第一条非注释命令 120 | * 创建多个镜像时FROM可以多次出现,需在每个新命令FROM之前,记录提交上次的镜像ID 121 | * tag或digest可选,默认使用latest版本基础镜像 122 | 123 | * RUN 124 | 125 | * RUN创建的中间镜像会被缓存,并在下次构建中使用 126 | 127 | * 如果不想使用缓存镜像,`--no-cache`参数 128 | 129 | > docker build --no-cache 130 | 131 | * COPY 复制文件 132 | 133 | * 源文件的各种元数据都会保留(读,写,执行权限,文件变更时间) 134 | 135 | * ADD 更高级的复制文件 136 | 137 | * 在COPY基础上增加功能,如`<源路径>可以是URL` 138 | 139 | * ENV设置环境变量 140 | 141 | ``` 142 | ENV VERSION=1.0 DEBUG=on \ 143 | NAME="Happy Feet" 144 | ``` 145 | 146 | * EXPOSE 147 | 148 | * 为构建的镜像设置监听端口,使容器在运行时监听 149 | * EXPOSE 指令并不会让容器监听 host 的端口,在 docker run 时使用 `-p`、`-P` 参数来发布容器端口到 host 的某个端口上。 150 | 151 | * VOLUME 定义匿名卷 152 | 153 | * VOLUME 让我们可以将源代码、数据或其它内容添加到镜像中,而又不并提交到镜像中,并使我们可以多个容器间共享这些内容。 154 | 155 | * WORKDIR 指定工作目录 156 | 157 | * 通过WORKDIR设置工作目录后,Dockerfile 中其后的命令 RUN、CMD、ENTRYPOINT、ADD、COPY 等命令都会在该目录下执行。 158 | 159 | * USER 指定当前用户 160 | 161 | * 使用USER指定用户时,可以使用用户名、UID 或 GID,或是两者的组合 162 | * 使用USER指定用户后,Dockerfile 中其后的命令 RUN、CMD、ENTRYPOINT 都将使用该用户。镜像构建完成后,通过 docker run 运行容器时,可以通过 `-u` 参数来覆盖所指定的用户。 163 | 164 | * CMD 165 | 166 | * CMD用于指定在容器启动时所要执行的命令 167 | 168 | * ENTRYPOINT 169 | 170 | * ENTRYPOINT 用于给容器配置一个可执行程序。每次使用镜像创建容器时,通过 ENTRYPOINT 指定的程序都会被设置为默认程序。 171 | * ENTRYPOINT 与 CMD 非常类似,不同的是通过`docker run`执行的命令不会覆盖 ENTRYPOINT,而`docker run`命令中指定的任何参数,都会被当做参数再次传递给 ENTRYPOINT 172 | 173 | # Spring Boot 项目添加Docker支持 174 | 175 | * 在 `pom.xml-properties`中添加 Docker 镜像名称 176 | 177 | ```xml 178 | 179 | springboot 180 | 181 | ``` 182 | 183 | * plugins 中添加Docker构建插件 184 | 185 | ```xml 186 | 187 | 188 | 189 | org.springframework.boot 190 | spring-boot-maven-plugin 191 | 192 | 193 | 194 | com.spotify 195 | docker-maven-plugin 196 | 1.0.0 197 | 198 | ${docker.image.prefix}/${project.artifactId} 199 | src/main/docker 200 | 201 | 202 | / 203 | ${project.build.directory} 204 | ${project.build.finalName}.jar 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | ``` 213 | 214 | * 在目录`src/main/docker`下创建Dockerfile文件 215 | 216 | ```dockerfile 217 | FROM openjdk:8-jdk-alpine 218 | VOLUME /tmp 219 | ADD spring-boot-docker-1.0.jar app.jar 220 | ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"] 221 | ``` 222 | 223 | * FROM ,表示使用 Jdk8 环境 为基础镜像,如果镜像不是本地的会从 DockerHub 进行下载 224 | * VOLUME ,VOLUME 指向了一个`/tmp`的目录,由于 Spring Boot 使用内置的Tomcat容器,Tomcat 默认使用`/tmp`作为工作目录。这个命令的效果是:在宿主机的`/var/lib/docker`目录下创建一个临时文件并把它链接到容器中的`/tmp`目录 225 | * ADD ,拷贝文件并且重命名 226 | * ENTRYPOINT ,为了缩短 Tomcat 的启动时间,添加`java.security.egd`的系统属性指向`/dev/urandom`作为 ENTRYPOINT 227 | 228 | # 镜像精简、加速 229 | 230 | 镜像精简、加速分发部署的关键就在于巧妙利用这种增量机制,主要有两种途径: 231 | 232 | - 减小镜像体积 233 | - 缩减层的体积。在**同一条命令**的最后,尽可能删除所有中间步骤的遗留文件。见下节示例-1。 234 | - 减少层的数量。因为是增量存储,所以即便是删除操作,也不会有负体积的层出现。主要作用在于拉取镜像时,减少处理层与层关系的时间。见下节示例-2。 235 | - 充分复用已经存在下层镜像 236 | - 使用公共的基础镜像。我们在 library 命名空间下提供了经过修改的标准镜像,包括 YUM 源与时区的本地化等,比如 docker-registry.***。见下节示例-3。 237 | - Dockerfile 语句按修改频率排序。这样,不但可以减少拉镜像时的工作量,而且在制作镜像时也可以充分利用之前的缓存,达到加速效果。也可以把不易变的部分提取出来,做自己的基础镜像。见下节示例-4。 238 | 239 | **以上只是优化的原则,如果这些操作影响到应用部署的复杂性,请酌情采纳** 240 | 241 | 1. 缩减层体积 242 | 243 | 2. 减少层数量 244 | 245 | 3. 使用公共基础镜像 246 | 247 | 4. Dockerfile 重排序 248 | 249 | -------------------------------------------------------------------------------- /面试/阿里菜鸟.md: -------------------------------------------------------------------------------- 1 | # 阿里菜鸟 2 | 3 | ## 一面 4 | 5 | ### jdk1.8后对HashMap的改进 6 | 7 | JDK7中HashMap采用的是位桶+链表的方式。而JDK8中采用的是位桶+链表/红黑树的方式,当某个位桶的链表的长度超过8的时候,这个链表就将转换成红黑树。 8 | 9 | ### 讲讲ConcurrentHashMap,ConcurrentHashMap怎么保证线程安全,HashTable怎么保证线程安全 10 | 11 | 12 | 13 | ### HashSet的底层实现,是不是线程安全的 14 | 15 | 16 | 17 | ### ArrayList和LinkedList的区别,是不是线程安全的 18 | 19 | 20 | 21 | ### 讲讲设计模式,最常用哪种设计模式,单例模式的实现方式 22 | 23 | 24 | 25 | ### 可重入锁的可重入性是什么意思,哪些是可重入锁(递归锁) 26 | 27 | 意味着线程可以进入它已经拥有的锁的同步代码块儿。 28 | 29 | 在JAVA环境下 ReentrantLock 和synchronized 都是 可重入锁 30 | 31 | 32 | 33 | ### Java实现多线程的方式,什么是线程安全,怎么保证多线程线程安全 34 | 35 | #### 线程安全 36 | 37 | * 原子性 38 | 39 | 常用的保证Java操作原子性的工具是锁和同步方法(或者同步代码块)。使用锁,可以保证同一时间只有一个线程能拿到锁,也就保证了同一时间只有一个线程能执行申请锁和释放锁之间的代码。 40 | 41 | * 顺序性 42 | 43 | Java中可通过`volatile`在一定程序上保证顺序性,另外还可以通过synchronized和锁来保证顺序性。 44 | 45 | * 可见性 46 | 47 | volatile适用于不需要保证原子性,但却需要保证可见性的场景。一种典型的使用场景是用它修饰用于停止线程的状态标记 48 | 49 | 50 | 51 | ### Java堆溢出问题怎么处理,内存泄漏和内存溢出的区别 52 | 53 | [Java堆溢出问题怎么处理,内存泄漏和内存溢出的区别](https://blog.csdn.net/sinat_35512245/article/details/54866068) 54 | 55 | [Java内存泄漏与内存溢出详解](https://blog.csdn.net/sinat_35512245/article/details/54866068) 56 | 57 | - 内存泄漏指你用malloc或new申请了一块内存,但是没有通过free或delete将内存释放,导致这块内存一直处于占用状态。 58 | - 内存溢出指你申请了10个字节的空间,但是你在这个空间写入11或以上字节的数据,就是溢出。 59 | 60 | 内存泄露是指程序中间动态分配了内存,但在程序结束时没有释放这部分内存,从而造成那部分内存不可用的情况,重启计算机可以解决,但也有可能再次发生内存泄露,内存泄露和硬件没有关系,它是由软件设计缺陷引起的。 61 | 62 | 内存泄漏可以分为4类: 63 | 64 | - 1)常发性内存泄漏。 65 | 66 | - 2)偶发性内存泄漏。 67 | 68 | - 3)一次性内存泄漏。 69 | 70 | - 4)隐式内存泄漏。 71 | 72 | ### 为什么要用线程池,线程池的好处 73 | 74 | 75 | 76 | 77 | 78 | ### Java对象池技术 79 | 80 | [Java对象池技术](https://www.jianshu.com/p/38c5bccf892f) 81 | 82 | #### 为什么用对象池 83 | 84 | 在 java 中,对象的生命周期包括对象创建、对象使用,对象消失三个时间段,对象的创建是比较费时间的,也许感觉不到,好比一个赋值操作int i=1,也是需要耗时的,在比如构造一个对象,一个数组就更加消耗时间。再说对象的消除,在 java 里面使用 GC 来进行对象回收,其实也是需要对对象监控每一个运行状态,包括引用,赋值等。**在 Full GC 的时候,会暂停其他操作,独占 CPU。**所以,我们需要控制对象的创建数量,也不要轻易的让对象消失,让他的复用更加充分。 85 | 86 | ### 对象池 87 | 88 | 想要这样的对象,从池子里取个就行,但是用完得归还。**对象池的对象最好是创建比较费时的大对象**,如果是太简单的对象,再进入池化的时间比自己构建还多,就不划算了。可以理解对象池为单例模式的延展,多例模式,就那么几个对象实例,再多没有了。 89 | 90 | 书上说这个模式会用在数据库连接的管理上。比如,每个用户的连接数是有限的,**这样每个连接就是一个池子里的一个对象,“连接池”类就可以控制连接数了。** 91 | 92 | ### 自定义一个低质量的对象池 93 | 94 | 首先构造一个池化对象,也就是对实际对象封装下,为什么呢?当然是为了让对象池更好的管理 95 | 96 | ```java 97 | public class PooledObject { 98 | 99 | private T objection = null;// 外界使用的对象 100 | private boolean busy = false; // 此对象是否正在使用的标志,默认没有正在使用 101 | 102 | // 构造函数,池化对象 103 | public PooledObject(T objection) { 104 | this.objection = objection; 105 | } 106 | 107 | // 返回此对象中的对象 108 | public T getObject() { 109 | return objection; 110 | } 111 | 112 | // 设置此对象的,对象 113 | public void setObject(T objection) { 114 | this.objection = objection; 115 | } 116 | 117 | // 获得对象对象是否忙 118 | public boolean isBusy() { 119 | return busy; 120 | } 121 | 122 | // 设置对象的对象正在忙 123 | public void setBusy(boolean busy) { 124 | this.busy = busy; 125 | } 126 | } 127 | ``` 128 | 129 | 池化对象现在包括两个属性,一个是原始对象的引用,另外一个表示当前对象是否在使用 130 | 131 | ### JVM垃圾处理方法 132 | 133 | • **标记-清除算法** 134 | 135 | –标记阶段:先通过根节点,标记所有从根节点开始的对象,未被标记的为垃圾对象。 136 | 137 | –清除阶段:清除所有未被标记的对象。 138 | 139 | • **复制算法** 140 | 141 | –将原有的内存空间分为两块,每次只使用其中一块,在垃圾回收时,将正在使用的内存中的存活对象复制到未使用的内存块中,然后清除正在使用的内存块中的所有对象。 142 | 143 | • **标记-整理算法** 144 | 145 | –标记阶段:先通过根节点,标记所有从根节点开始的可达对象,为被标记的为垃圾对象 146 | 147 | –整理阶段:将所有的存活对象压缩到内存的一段,之后清理边界所有的空间 148 | 149 | 150 | 151 | • 三种算法的比较 : 152 | • 效率:复制算法 > 标记/整理算法 > 标记/清除算法(此处的效率只是简单的对比时间复杂度,实际情况不一定如此)。 153 | • 内存整齐度:复制算法=标记/整理算法>标记/清除算法。 154 | 155 | • 内存利用率:标记/整理算法=标记/清除算法>复制算法。 156 | 157 | ### 对象什么时候进入老年代 158 | 159 | (1)当对象首次创建时, 会放在新生代的eden区, 若没有GC的介入,会一直在eden区, **GC后**,是可能进入survivor区或者年老代 160 | 161 | (2)当对象**年龄达到一定的大小** ,就会离开年轻代, 进入老年代。 而对象的年龄是由GC的次数决定的 162 | 163 | -XX:MaxTenuringThreshold=n  新生代的对象最多经历n次GC, 就能晋升到老年代, 但不是必要条件    164 | 165 | -XX:TargetSurvivorRatio=n  用于设置Survivor区的目标使用率,即当survivor区GC后使用率超过这个值, 就可能会使用较小的年龄作为晋升年龄 166 | 167 | (3)除年龄外, 对象体积也会影响对象的晋升的, 若对象体积太大, 新生代无法容纳这个对象 168 | 169 | -XX:PretenureSizeThreshold  即对象的大小大于此值, 就会绕过新生代, 直接在老年代分配, 此参数只对串行回收器以及ParNew回收有效, 而对ParallelGC回收器无效 170 | 171 | ### 什么时候进行FullGC 172 | 173 | 1. System.gc()方法的调用 174 | 175 | system.gc(), 此方法的调用是建议JVM进行Full GC, 可通过通过-XX:+ DisableExplicitGC来禁止RMI调用System.gc。 176 | 177 | 2. old/Tenured 空间不足 178 | 179 | 老年代空间在新生代对象转入及创建为大对象、大数组时 180 | 181 | 当执行Full GC后空间仍然不足,报错:java.lang.OutOfMemoryError: Java heap space 182 | 183 | ``` 184 | java -Xmx10m -Xms10m -Xmn10m -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=75 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC gc.ConcurrentMarkSweep 185 | ``` 186 | 187 | 3. perm/metaspace 空间不足 188 | 4. CMS GC时出现promotion failed和concurrent mode failure 189 | 5. 判断当前新生代的对象是否能够全部顺利的晋升到老年代,如果不能,就提早触发一次老年代的收集 190 | 191 | ## 二面 192 | 193 | ``` 194 | 1、讲讲数据库存储引擎 195 | 2、介绍一下索引,索引设置的规则,聚簇索引和非聚簇索引的区别,索引的最左前缀原则 196 | 6、算法题:输入两个字符串,输出它们合并排序后的结果 197 | ``` 198 | 199 | ### -Xms和-Xmx分别指什么 200 | 201 | -xms 初始堆大小 202 | 203 | -xmx 最大堆大小 204 | 205 | ### redis支持哪些数据类型 206 | 207 | 208 | 209 | ### redis与mysql的区别 210 | 211 | Redis基于内存,读写速度快,也可做持久化,但是内存空间有限,当数据量超过内存空间时,需扩充内存,但内存价格贵。 212 | 213 | 1. mysql是一个中小型的网络数据库,比oracle和sqlserver小, 但是并发能力远超过acess这样的桌面数据库。 214 | 2. redis是一个支持网络、可基于内存亦可持久化的日志型、Key-Value数据库。 215 | 3. 可以认为redis比mysql简化很多。 216 | 4. mysql支持集群。 217 | ### 垃圾收集器 218 | 219 | - [新生代收集器](https://crowhawk.github.io/2017/08/15/jvm_3/#%E6%96%B0%E7%94%9F%E4%BB%A3%E6%94%B6%E9%9B%86%E5%99%A8) 220 | - [Serial收集器](https://crowhawk.github.io/2017/08/15/jvm_3/#serial%E6%94%B6%E9%9B%86%E5%99%A8) 221 | 222 | 它是采用**复制算法**的**新生代收集器** 223 | 224 | - [ParNew 收集器](https://crowhawk.github.io/2017/08/15/jvm_3/#parnew-%E6%94%B6%E9%9B%86%E5%99%A8) 225 | - [Parallel Scavenge 收集器](https://crowhawk.github.io/2017/08/15/jvm_3/#parallel-scavenge-%E6%94%B6%E9%9B%86%E5%99%A8) 226 | - [老年代收集器](https://crowhawk.github.io/2017/08/15/jvm_3/#%E8%80%81%E5%B9%B4%E4%BB%A3%E6%94%B6%E9%9B%86%E5%99%A8) 227 | - [Serial Old收集器](https://crowhawk.github.io/2017/08/15/jvm_3/#serial-old%E6%94%B6%E9%9B%86%E5%99%A8) 228 | 229 | Serial Old 是 Serial收集器的老年代版本,它同样是一个**单线程收集器**,使用**“标记-整理”(Mark-Compact)**算法。 230 | 231 | - [Parallel Old收集器](https://crowhawk.github.io/2017/08/15/jvm_3/#parallel-old%E6%94%B6%E9%9B%86%E5%99%A8) 232 | - [CMS收集器](https://crowhawk.github.io/2017/08/15/jvm_3/#cms%E6%94%B6%E9%9B%86%E5%99%A8) 233 | - [G1收集器](https://crowhawk.github.io/2017/08/15/jvm_3/#g1%E6%94%B6%E9%9B%86%E5%99%A8) 234 | 235 | 它**将整个Java堆划分为多个大小相等的独立区域(Region)**,虽然还保留新生代和老年代的概念,但**新生代和老年代不再是物理隔离的了,而都是一部分Region(不需要连续)的集合**。 236 | 237 | **在后台维护一个优先列表**,每次根据允许的收集时间,**优先回收价值最大的Region(这也就是Garbage-First名称的来由)** 238 | 239 | ## 三面: 240 | 241 | ``` 242 | 1、讲讲数据库的范式 243 | 5、设计题:一个市有9个消防站,现在要新增3个消防站,这3个消防站应该放在哪里 244 | ``` 245 | 246 | ------ 247 | 248 | ### Linux进程通信和线程通信 249 | 250 | ### 线程池的参数 251 | 252 | 253 | 254 | ### 什么是内部类,什么是匿名内部类 -------------------------------------------------------------------------------- /数据库/MySql.md: -------------------------------------------------------------------------------- 1 | # MySQL 索引 2 | 3 | * 索引的原理 4 | 5 | * 对要查询的字段建立索引==>**把该字段按照一定的方式排序**; 6 | * 建立的索引只对该字段有用,若查询其他字段,则索引无效 7 | * 索引太多会降低查询的速度 8 | * 优点 9 | 10 | * 查询时就会先去索引列表中一次定位到特定值的行数大大减少遍历匹配的行数,增加查询的速度。 11 | * 缺点 12 | * 全表查询情况,索引无意义 13 | * 对非唯一的字段,例如“性别”这种大量重复值的字段,增加索引也没有什么意义。 14 | * 索引是需要存储空间, 对于记录比较少的表,增加索引不会带来速度的优化反而浪费了存储空间, 15 | * 对于update/insert/delete的每次执行,字段的索引都必须重新计算更新。所以并不是任何情况下都改建立索引的 16 | 17 | ## **哪些列适合建立索引** 18 | 19 | * 经常需要搜索的列 20 | * 在**作为主键的列**上,强制该列的唯一性和组织表中数据的排列结构。 21 | * 经常用在连接的列上,这些列主要是**外键**,**可以加快连接速度。** 22 | * 经常需要**根据范围进行搜索的列**上创建索引,因为索引已经排序,所以其指定的范围是连续的。 23 | * 经常需要排列的列,因为索引已经排序,这样可以利用索引的排序,**加快查询的速度。** 24 | * **经常需要使用WHERE子句**,**加快条件的判断速度。** 25 | 26 | ## [MySQL里的索引类型](https://juejin.im/post/5e6509fd518825490d1267eb) 27 | 28 | * B-Tree索引 29 | 30 | * 最常见的索引类型,基于B-Tree数据结构 31 | * B-Tree的基本思想是,所有值(被索引的列)都是排过序的,每个叶节点到跟节点距离相等。 32 | * B-Tree适合用来查找某一范围内的数据,而且可以直接支持数据排序(ORDER BY)。但是当索引多列时,列的顺序特别重要,需要格外注意。 33 | * InnoDB和MyISAM都支持B-Tree索引。 34 | * B+树索引 35 | * InnoDB默认使用 36 | * MyISAM为了节省空间对索引进行了压缩,从而牺牲了性能 37 | * Hash索引 38 | * 基于hash表。**只支持精确查找,不支持范围查找**,**不支持排序。** 39 | * Hash索引与B+树索引的区别 40 | - Hash索引适合等值查询,但无法进行范围查询 41 | - Hash索引无法完成排序,不支持多列联合索引的最左匹配原则 42 | - 如果有大量重担键值的情况下,效率很低,因存在Hash碰撞 43 | * 全文索引`Full-Text` 44 | * MySQL5.6及以后,MyISAM和InnoDB都支持 45 | * 空间数据索引`R-Tree` 46 | * MyISAM支持,可用于地理数据存储 47 | 48 | ## 索引下推 49 | 50 | * 在MySQL5.6之后,对索引的优化 51 | * 可以在有like条件查询的情况下,减少回表次数 52 | 53 | ## [为何使用B+树为索引](https://segmentfault.com/a/1190000004690721) 54 | 55 | * B树 56 | * B树叶子和非叶节点都会保存数据,导致在非叶子节点保存的指针数量变少,指针少的情况下要保存大量数据,只能增加树高,**导致IO操作变多**,查询性能变低 57 | * B树在提高IO性能的同时并没有解决元素遍历效率低下的问题 58 | * 每个节点Key和Data在一起,无法区间查询 59 | * ![clip_image002](https://images2018.cnblogs.com/blog/834468/201804/834468-20180406232634472-395289491.png) 60 | 61 | * B+树 62 | 63 | * 只要去遍历叶子结点就可以实现整棵树的遍历 64 | 65 | * 更适合外部存储,由于内节点无data域,一个结点可存储更多的内结点,每个节点能索引的范围更大更精确,意味着B+树单次磁盘IO的信息量大于B树,IO效率更高 66 | 67 | * MySQL是一种关系型数据库,区间访问是一种常见的情况,B+树叶子节点有指针,可以用于范围查询 68 | 69 | 70 | 71 | # InnoDB 72 | 73 | * 若一个主键被定义,该主键则作为密集索引;若没有主键被定义,该表的第一个唯一非空索引则作为密集索引;若不满足以上条件,innodb内部会生成一个隐藏主键(密集索引) 74 | * 索引和数据存在一块,默认为B+树 75 | * 有且只有一个密集索引 76 | * 支持事务 77 | * 当某个索引值被使用非常频繁时,会在B+树索引上创建一个哈希索引 78 | 79 | # MyISAM 80 | 81 | * 索引和数据分开存储 82 | * 不管是主键索引,唯一键索引还是普通索引都是稀疏索引 83 | * 不支持事务 84 | 85 | # [MyISAM与InnoDB区别](https://segmentfault.com/q/1010000011454565) 86 | 87 | * 事务 88 | * MyISAM不支持事务,执行速度快,MyISAM读性能强 89 | * InnoDB支持事务与外键与行锁 90 | * InnoDB不保存具体行数,MyISAM可保存好行数读出即可 91 | * 索引 92 | * MyISAM 93 | * MyISAM索引和数据分开且索引有压缩,内存使用率提高不少 94 | * 通过索引直接找到叶子节点中指向具体表中的数据的那个指针 95 | * InnoDB 96 | * InnoDB索引与数据存在一地块 97 | * 有聚簇索引,索引数据时需要在二级索引中找到主键,后根据主键到聚簇索引中找到最终数据,需要走两次索引 98 | * InnoDB不支持全文索引(5.6版本以后支持) 99 | 100 | # .frm .MYD .MYI .idb .par 101 | 102 | * 有数据库a,表格b 103 | * 若表格b采用MyISAM,data\a中会产生3个文件 104 | * `b.frm` 描述表结构文件,字段长度 105 | * `b.MYD(MYData)`数据信息文件 106 | * `b.MYI(MYIndex)`索引信息文件 107 | * 若表格采用InnoDB,data\a中会产生1个或2个文件 108 | * `b.frm`描述表结构文件,字段长度 109 | * `b.idb`存储数据信息和索引信息 110 | * 若采用分区存储,data\a中还会有一个`b.par`文件,存储分区信息 111 | 112 | # MySQL 查询优化 113 | 114 | 115 | 116 | * MySQL逻辑架构 117 | 118 | ![img](http://dbaplus.cn/uploadfile/2017/0928/20170928110355446.png) 119 | 120 | * 客户端层 121 | * 并非MySQL所独有 122 | * 连接处理 123 | * 授权认证 124 | * 安全 125 | * 核心服务 126 | * 查询解析 127 | * 分析 128 | * 优化 129 | * 缓存 130 | * 内置函数 131 | * 存储引擎 132 | * 数据存储 133 | * 数据提取 134 | 135 | * MySQL查询过程 136 | 137 | ![img](http://dbaplus.cn/uploadfile/2017/0928/20170928110411496.jpg) 138 | 139 | - 客户端向MySQL服务器发送一条查询请求 140 | - 服务器首先检查查询缓存,如果命中缓存,则立刻返回存储在缓存中的结果。否则进入下一阶段 141 | - 服务器进行SQL解析、预处理、再由优化器生成对应的执行计划 142 | - MySQL根据执行计划,调用存储引擎的API来执行查询 143 | - 将结果返回给客户端,同时缓存查询结果 144 | 145 | * 避免向数据库请求不需要的数据 146 | 147 | * 使用LIMIT 148 | * 避免使用select * 149 | 150 | * 查询数据的方式 151 | 152 | * 通过EXPLAIN语句中的type列反应查询的是哪种方式 153 | * 通过添加合适的索引改善查询数据的方式,使其尽可能减少扫描的数据行,加快查询速度 154 | 155 | * 分解大的查询 156 | 157 | * 将大查询分解为多个小查询,每个小查询只完成整个查询任务的一小部分,每次只返回一小部分结果 158 | * 优点: 159 | * 缓存效率高 160 | * 减少锁竞争 161 | * 更容易对数据库进行拆分,更容易做到高性能和可扩展 162 | * 查询本身的效率也可能有提升 163 | 164 | * 优化MIN()和MAX() 165 | 166 | * 添加索引,B-Tree 167 | 168 | * 用IN() 取代OR 169 | 170 | * IN()先将自己列表中折数据进行排序,然后通过二分查找的方式确定列的值是是否在IN()的列表中,时间复杂度O(logn) 171 | 172 | * OR操作,时间复杂度为O(n) 173 | 174 | * 优化关联查询 175 | 176 | 在MySql中,任何一个查询都可以看成是一个关联查询,即使只有一个表的查询也是如此。 177 | MySql对任何关联都执行嵌套循环的关联操作,例如对于下面的SQL语句: 178 | 179 | ```sql 180 | SELECT tbl1.col1,tbl2.col2 181 | FROM tbl1 INNER JOIN tbl2 USING(col3) 182 | WHERE tbl1.col1 IN(5,6); 183 | ``` 184 | 185 | 下面的伪代码表示MySql将如何执行这个查询: 186 | 187 | ```c 188 | //先从第一个表中取出符合条件的所有行 189 | out_iter = iterator over tbl1 where col1 IN(5,6) 190 | outer_row = out_iter.next 191 | //在while循环中遍历第一个表结果集的每一行 192 | while outer_row 193 | //对于第一个表结果集中的每一行,在第二个表中找出符合条件的所有行 194 | inner_iter = iterator over tbl2 where col3 = outer_row.col3 195 | inner_row = inner_iter.next 196 | while inner_row 197 | //将第一个表的结果列和第二个表的结果列拼装在一起作为结果输出 198 | output[outer_row.col1, inner_row.col2] 199 | inner_row = inner_iter.next 200 | end 201 | //回溯,再根据第一个表结果集的下一行,继续上面的过程 202 | outer_row = outer_iter.next 203 | end 204 | ``` 205 | 206 | * 通常只需要在关联顺序的第二个表的相应列上创建索引 207 | * 确保任何的GROUP BY 和ORDER BY中的表达式只涉及到一个表中的列(这样才能使用索引优化这个过程) 208 | 209 | * 临时表(派生表) 210 | 211 | * 子查询 212 | * 先执行子查询并将结果放到一个临时表中,然后将这个临时表当作一个普通表对待 213 | * MySQL临时表是没有任何索引的,在编写复杂子查询时需要注意 214 | * UNION查询 215 | * 先将一个单表查询放到一个临时表中 216 | * 重新读出临时表数据来完成UNION查询 217 | 218 | * 排序优化 219 | 220 | * 尽量让MySQL使用索引进行排序 221 | * 若数量太大超过“排序缓冲区”大小,MySQL只能采用文件排序,消耗资源 222 | 223 | * 子查询优化 224 | 225 | * 用关联替换子查询 226 | 227 | * 优化COUNT()查询 228 | 229 | * COUNT()作用 230 | * 统计某个列值的数量,即统计某列值不为NULL的个数 231 | * COUNT(*)统计行数 232 | 233 | * 优化LIMIT分页 234 | 235 | * 使用索引覆盖扫描,而不是查询所有的列 236 | * 然后根据需要与万年青做一次关联操作返回所需要的列 237 | 238 | * 使用UNION查询 239 | 240 | * 除非确实需要服务器消除重复的行,否则一定要使用UNION ALL 241 | * 如果没有ALL关键字,MySQL会给临时表加上DISTINCT选项,这会导致对整个临时表做唯一性检查,代价很大 242 | 243 | # 视图(虚表) 244 | 245 | ## [视图的应用场景](https://blog.csdn.net/chuangxin/article/details/84574557) 246 | 247 | * 简化sql查询,提高开发效率 248 | * 如采购单:有价格、数量、税率、含税金额,多半没有不含税金额、税额,而这些字段在很多报表中有都会用到,所以我们可以创建一个含有计算列字段的视图来解决这个问题。 249 | 250 | ## [数据库改变视图中的数据是否改变](https://bbs.csdn.net/topics/392292047) 251 | 252 | * 若视图数据来自一个表时,修改视图中的数据,表数据会更新 253 | * 若视图数据来源多个表时,修改视图数据会报错,无法修改 254 | 255 | # [大表添加字段](https://blog.csdn.net/jiahao1186/article/details/81039613) 256 | 257 | * 创建一个临时表,首先复制旧表结构 258 | * 给新表加上新增的字段,此时新表是空表,加字段很快 259 | * 把旧表数据复制过来 260 | * 删除旧表,重命名新表名字不旧表 261 | * 注意 262 | * 会损失极少量的数据,如果表的数据特别大,同时又要保证数据完整性,最好停机操作 263 | 264 | # [连接池参数](https://zhuanlan.zhihu.com/p/69306001) 265 | 266 | 1. 最小连接数:是连接池一直保持的数据库连接,所以如果应用程序对数据库连接的使用量不大,将会有大量的数据库连接资源被浪费. 267 | 268 | 2. 最大连接数:是连接池能申请的最大连接数,如果数据库连接请求超过次数,后面的数据库连接请求将被加入到等待队列中,这会影响以后的数据库操作 269 | 270 | 3. 最大空闲时间 271 | 272 | 4. 获取连接超时时间 273 | 274 | 5. 超时重试连接次数 -------------------------------------------------------------------------------- /JVM/Java垃圾回收.md: -------------------------------------------------------------------------------- 1 | # 判断对象是否为垃圾 2 | 3 | * 引用计数算法 4 | 5 | * 通过判断对象的引用数量来决定对象是否可以被回收 6 | * 每个对象实例都有一个引用计数器,被引用则+1,完成引用则-1 7 | * 任何引用计数为0的对象实例可以被当作垃圾收集 8 | 9 | * 可达性分析算法 10 | 11 | * 通过判断对象的引用链是否可达来决定对象是否可以被回收 12 | 13 | 14 | ## [可以作为GC Root的对象](https://www.jianshu.com/p/4a1080373096) 15 | 16 | * 虚拟机栈中引用的对象(栈帧中的本地变量表)换句话说,**当前所有正在被调用的方法的引用类型的参数/局部变量/临时值**。 17 | * 方法区中的常量引用的对象 18 | * 方法区中的类静态属性引用的对象 19 | * 本地方法栈中JNI的引用对象 20 | 21 | * 活跃线程的引用对象 22 | 23 | # 垃圾回收算法 24 | 25 | * 标记-清除算法 26 | 27 | * 标记 28 | * 从根集合进行扫描,对存活的对象进行标记 29 | * 清除 30 | * 对堆内存从头到尾进行遍历,回收不可达对象内存 31 | 32 | **不足** 33 | 34 | * 碎片化 35 | 36 | * 复制算法(年轻代适用) 37 | 38 | * 分为对象面和空闲面 39 | * 对象在对象面上创建 40 | * 存活的对象被从对象面复制到空闲面 41 | * 将对象面所有对象内存清除 42 | 43 | **优点** 44 | 45 | * 解决碎片化问题 46 | * 顺序分配内存,简单高效 47 | * 适用于对象存活率低的场景 48 | 49 | * 标记-整理算法 50 | 51 | * 标记 52 | * 从根集合进行招描,对存活的对象进行标记 53 | * 清除 54 | * 移动所有存活的对象,且按照内存地址次序依次排列,然后将末端内存地址以后的内存全部回收 55 | 56 | * 分代收集算法 57 | 58 | * 垃圾回收算法的组合拳 59 | * 按照对象生命周期的不同划分区域以采用不同的垃圾回收算法 60 | * 目的:提高JVM的回收效率 61 | * 分类 62 | 63 | * Minor GC 64 | * Full GC 65 | * 新生代(1/3) 66 | * Eden区(8) 67 | * 两个Survior(1,1) 68 | * 老年代(2/3) 69 | * 常用调优参数 70 | * -XX:SurvivorRatio 71 | * Eden和Survivor比值,默认8:1 72 | * -XX:NewRatio 73 | * 老年代和新生代的内存大小比例 74 | * -XX:MaxTenuringThreshold 75 | * 对象从年轻代晋升到老年代经过GC次数的最大阈值 76 | 77 | 78 | 79 | # [触发Minor GC条件](https://blog.csdn.net/qq_23410909/article/details/90211521) 80 | 81 | * Eden(伊甸园)空间不足。 82 | 83 | # [触发Full GC的条件](https://blog.csdn.net/qq_23410909/article/details/90211521) 84 | 85 | * **老年代空间不足** 86 | * 永久代(JDK 8已无)空间不足 87 | * CMS GC时出现promotion failed,concurrent mode failure 88 | * **Minor GC晋升到老年代的平均大小大于老年代的剩余空间** 89 | * **调用`System.gc()`** 90 | * 使用RMI来进行RPC或管理JDK应用,每小时执行一次FullGC 91 | 92 | # Stop the World 93 | 94 | * JVM 由于要执行GC而停止了应用程序的执行 95 | * 任何一GC算法中都会发生 96 | * 多数GC优化通过减少Stop-the-world发生的时间来提高程序的性能 97 | 98 | # 垃圾收集器 99 | 100 | * 种类 101 | * 串行Serial 102 | * 单线程垃圾回收 103 | * 并行Parallel(java8默认) 104 | * 多个垃圾回收线程并行工作 105 | * 并发标记(CMS) 106 | * 用户线程与垃圾收集线程同时执行(不一定并行,可交替),不需用户暂停,适用对响应时间有要求的场景 107 | * G1(java1.9 默认) 108 | * 将堆内存分割,并发回收,不会产生碎片 109 | * `-XX:+UseG1GC`,复制+标记-整理算法 110 | * `stop the world`可控,用户可指定期望时间,增加预测机制 111 | * 查看垃圾收集器 112 | * `-XX:+printCommandLineFlags -version` 113 | 114 | ## 年轻代收集器 115 | 116 | * Serial收集器 117 | * `-XX:+UseSerialGC`,复制算法 118 | * 单线程收集,进行垃圾收集时,必须暂停所有工作线程 119 | * 简单高效,Client模式下默认的年轻代收集器 120 | * ParNew收集器 121 | * `-XX:+UseParNewGC`,复制算法 122 | * 多线程收集器,其余的行为,特点和Serial收集器一样 123 | * 单核执行效率不如Serial,在多核下执行才有优势 124 | * Parallel Scavenge收集器(1.8默认) 125 | * `-XX:+UseParallelGC`,复制算法 126 | * 吞吐量=运行用户代码时间/(运行用户代码时间+地方都用收集时间) 127 | * 比起关注用户线程停顿时间,更关注系统的吞吐量 128 | * 在多核下执行才有优势,Server模式下默认的年轻代收集器 129 | 130 | ## 老年代收集器 131 | 132 | * Serial Old收集器 133 | * `-XX:+UseSerialOldGC`,标记-整理算法 134 | * 单线程收集,进行垃圾收集时,必须暂停所有工作线程 135 | * 简单高效,Client模式下默认的老年代收集器 136 | * Parallel Old收集器(1.8默认) 137 | * `-XX:+UseParallelOldGC`,标记-整理算法 138 | * 多线程,吞吐量优先 139 | 140 | ### [CMS收集器](https://juejin.im/post/6844903974676463629#comment) 141 | 142 | * `-XX:+UseConcMarkSweepGC`,标记-清除算法 143 | * **初始标记** 144 | * stop-the-world(很快) 145 | * **初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快** 146 | * 并发标记 147 | * 并发追溯标记,程序不会停顿 148 | * **重新标记** 149 | * 修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录.**这个阶段的停顿时间一般会比初始阶段稍长一些,但远比并发标记的时间短** 150 | * stop the world 151 | * 并发清理 152 | * 清理垃圾对象,程序不会停顿 153 | 154 | | 优点 | 并发收集,停顿低 | 155 | | ---- | ------------------------------------------------------------ | 156 | | 缺点 | 会导致大量碎片 对CPU资源压力大 | 157 | | | 标记-清除算法将产生大量的内存碎片这对新生代来说是难以接受的,因此**新生代的收集器并未提供CMS版本** | 158 | 159 | * 安全点 160 | * **程序执行时并非在所有地方都能停顿下来开始GC,只有在到达安全点时才能暂停**。Safepoint的选定既不能太少以至于让GC等待时间太长,也不能过于频繁以致于过分增大运行时的负荷。 161 | 162 | ## [G1垃圾收集器](https://juejin.im/post/6844903974676463629#comment) 163 | 164 | * 核心思想 165 | 166 | * 将整个堆内存区域划分成大小相同的子区域(Region),在JVM启动时会自动设置这些子区域大小(1-32M) 167 | * 目的是在进行收集时不必在全堆范围内进行 168 | * 区域划分的好处就是带来了停顿时间可预测的收集模型:用户可以指定收集操作在多长时间内完成。即G1提供了接近实时的收集特性。 169 | * **初始标记(STW)** 170 | * 这个阶段是STW(Stop the World )的,所有应用线程会被暂停,标记出从GC Root开始直接可达的对象。 171 | * 并发标记 172 | * 从GC Roots开始对堆中对象进行可达性分析,找出存活对象,耗时较长。当并发标记完成后,开始最终标记(Final Marking )阶段 173 | * **最终标记(STW)** 174 | * 标记那些在并发标记阶段发生变化的对象,将被回收 175 | * **筛选回收(STW)** 176 | * 首先对各个Region的回收价值和成本进行排序,根据用户所期待的GC停顿时间指定回收计划,回收一部分Region 177 | 178 | | 优点 | **可以看到最后一步G1是停顿的而CMS不会停顿,这也是CMS会产生浮动垃圾的原因** | | 179 | | ---- | ------------------------------------------------------------ | ---- | 180 | | | G1能充分利用多CPU、多核环境下的硬件优势,使用多个CPU来缩短Stop-the-world停顿的时间,部分其他收集器原来需要停顿Java线程执行的GC操作,G1收集器仍然可以通过**并发**的方式让Java程序继续运行。 | | 181 | | | 更精确预测GC停顿时间 | | 182 | | | G1不会产生内存碎片 | | 183 | 184 | # [空间分配担保](https://www.nowcoder.com/discuss/504211?type=0&order=0&pos=179&page=0&source_id=discuss_center_0&channel=666) 185 | 186 | * 在发生 Minor GC 之前, **虚拟机先检查老年代最大可用的连续空间是否大于新生代所有对象总空间**,如果条件成立的话,那么 Minor GC 可以确认是安全的。 187 | * **老年代最大可用的连续空间小于新生代所有对象总空间**,如果不成立的话虚拟机会查看 HandlePromotionFailure 的值是否允许担保失败, 188 | 如果允许那么就会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试着进行一次 Minor GC; 189 | 190 | # finalize()方法 191 | 192 | * Object的protected方法,子类可以覆盖以实现资源清理工作,**GC在回收对象之前调用该方法**,如果内存充足,则该方法可能永远不会被调用 193 | * 主要用途是回收特殊渠道的内存(一般情况下有GC不用程序员操心) 194 | * 可用来清理本地对象JNI(Java Native Interface)调用非Java程序 195 | * 确保某非内存资源释放的一个补充,在finalize方法中显示调用其他资源释放方法 196 | * 对象再生 197 | * 将待回收对象赋值给GC Roots可达的对象引用,从而达到再生 198 | * 至多由GC执行一次 199 | 200 | # 强引用/软引用/弱引用/虚引用 201 | 202 | * 强引用 203 | 204 | * 最普遍的引用 205 | * `Object obj = new Object()` 206 | * 抛出OutOfMemoryError终止程序也不会回收具有强引用的对象 207 | * 通过将对象是设置为null来弱化引用,使其被回收 208 | 209 | * 软引用 210 | 211 | * 对象处在有用但非必须的状态 212 | 213 | * 只有当内存空间不足时,GC会回收该内存 214 | 215 | * 可以用来实现高速缓存 216 | 217 | ```java 218 | String str = new String("abc") //强引用 219 | SoftReference softRef = new SoftReference(str); //软引用 220 | ``` 221 | 222 | * 弱引用 223 | 224 | * 非必须的引用,比软引用更弱一些 225 | 226 | * GC时会被回收 227 | 228 | * 被回收的概率也不大,因为GC线程优先级比较低 229 | 230 | * 适用于引用偶尔被使用且不影响垃圾收集的对象 231 | 232 | ```java 233 | String str = new String("abc"); 234 | WeakReference abcWeakRef = new WeakReference(str) 235 | ``` 236 | 237 | * 虚引用 238 | 239 | * 不会决定对象的生命周期 240 | * 任何时候都可能被垃圾收集器回收 241 | * 跟踪对象被垃圾收集器回收的活动,起哨兵作用 242 | * 必须和引用队列ReferenceQueue联合使用,被回收时对象将被放到引用队列中保存 243 | 244 | ```java 245 | String str = new String("abc"); 246 | ReferenceQueue queue = new ReferenceQueue(); 247 | PhantomReference ref = new PhantomReference(str,queue); 248 | ``` 249 | 250 | | 引用类型 | 被垃圾回收时间 | 用途 | 生存时间 | 251 | | -------- | -------------- | -------------- | ----------------- | 252 | | 强引用 | 从来不会 | 对象的一般状态 | JVM停止运行时终止 | 253 | | 软引用 | 在内存不足时 | 对象缓存 | 内存不足时终止 | 254 | | 弱引用 | 在垃圾回收时 | 对象缓存 | gc运行后终止 | 255 | | 虚引用 | Unknow | 标记,哨兵 | Unknown | 256 | 257 | 258 | 259 | -------------------------------------------------------------------------------- /Java/Java异常.md: -------------------------------------------------------------------------------- 1 | # [异常体系](https://juejin.im/post/5e8d6b27f265da47c916fc4e) 2 | 3 | ![img](https://user-gold-cdn.xitu.io/2020/4/8/171586a8ed7d2c92?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) 4 | 5 | * 除了 `RuntimeException` 和其子类,以及`error`和其子类,其它的所有异常都是 `checkedException` 6 | * Exception 有两种异常,一种是 `RuntimeException` ;一种是 `CheckedException`,**这两种异常都应该去`捕获`。** 7 | 8 | ## 异常类型 9 | 10 | * 受检查的异常(checked) 11 | * 需要用throws语句在方法或构造函数上声明 12 | * IO异常及SQL异常 13 | * **需要catch,不管我们是否愿意,都要写** 14 | * **RuntimeException**(unchecked) 15 | * 不需在方法或构造函数上声明 16 | * 可传播到方法或构造函数外面 17 | 18 | ### [RuntimeException](https://juejin.im/post/5e8d6b27f265da47c916fc4e) 19 | 20 | |序号 | 异常名称 | 异常描述| 21 | | ---|--|--| 22 | | 1 | ArrayIndexOutOfBoundsException| 数组越界异常| 23 | | 2 | NullPointerException | 空指针异常 | 24 | | 3 | IllegalArgumentException|非法参数异常 | 25 | | 4 | NegativeArraySizeException| 数组长度为负异常| 26 | | 5 | IllegalStateException|非法状态异常 | 27 | | 6 | ClassCastException|类型转换异常 | 28 | 29 | ### Checked Exception 30 | 31 | | 序号 | 异常名称 | 异常描述 | 32 | | ---- | ---------------------- | -------------------------------- | 33 | | 1 | NoSuchFieldException | 表示该类没有指定名称抛出来的异常 | 34 | | 2 | NoSuchMethodException | 表示该类没有指定方法抛出来的异常 | 35 | | 3 | IllegalAccessException | 不允许访问某个类的异常 | 36 | | 4 | ClassNotFoundException | 类没有找到抛出异常 | 37 | 38 | ## [与 Exception 有关的 Java 关键字](https://juejin.im/post/5e8d6b27f265da47c916fc4e) 39 | 40 | ### throw和throws区别 41 | 42 | * 在 Java 中,异常也就是一个对象,它能够被程序员自定义抛出或者应用程序抛出,必须借助于 `throws` 和 `throw` 语句来定义抛出异常。 43 | 44 | * throws 和 throw 通常是成对出现的,例如 45 | 46 | ```java 47 | static void cacheException() throws Exception{ 48 | 49 | throw new Exception(); 50 | 51 | } 52 | ``` 53 | 54 | * throw 语句用在方法体内,表示抛出异常,由方法体内的语句处理。 throws 语句用在方法声明后面,表示再抛出异常,由该方法的调用者来处理。 55 | 56 | * throws 主要是声明这个方法会抛出这种类型的异常,使它的调用者知道要捕获这个异常。 throw 是具体向外抛异常的动作,所以它是抛出一个异常实例。 57 | 58 | ### [try 、finally 、catch](https://juejin.im/post/5e8d6b27f265da47c916fc4e) 59 | 60 | * 这三个关键字主要有下面几种组合方式 **try...catch 、try...finally、try...catch...finally** 61 | 62 | ### [try...with...resources](https://juejin.im/post/5e8d6b27f265da47c916fc4e) 63 | 64 | * JDK1.7 使用try...with...resources 优雅关闭资源 65 | * Java 类库中有许多资源需要通过 close 方法进行关闭。比如 InputStream、OutputStream,数据库连接对象 Connection,MyBatis 中的 SqlSession 会话等。作为开发人员经常会忽略掉资源的关闭方法,导致内存泄漏。 66 | * 要使用 try-with-resources 语句,**首先要实现 `AutoCloseable` 接口,此接口包含了单个返回的 close 方法**。Java 类库与三方类库中的许多类和接口,现在都实现或者扩展了 `AutoCloseable `接口。如果编写了一个类,它代表的是必须关闭的资源,那么这个类应该实现 `AutoCloseable `接口。 67 | * java 引入了 try-with-resources 声明,**将 try-catch-finally 简化为 try-catch,这其实是一种`语法糖`,在编译时会进行转化为 try-catch-finally 语句。** 68 | 69 | ### [异常处理的原则](https://juejin.im/post/5e8d6b27f265da47c916fc4e) 70 | 71 | * 不要捕获类似 Exception 之类的异常,而应该捕获类似特定的异常,比如 InterruptedException,方便排查问题,而且也能够让其他人接手你的代码时,会减少骂你的次数。 72 | * 不要生吞异常。这是􏲾异常处理中要特别注重􏱸的事情,因为很可能会􏱓􏱠非常难以􏰰􏰱正常􏳶􏲾结束情况。如果我们不把􏲾异常抛􏲏出来,或者也没有输􏳹出到 􏰩􏱥􏰛Logger􏰜 日志中,程序可能会在后面以不可控的方式结束。 73 | * 不要在函数式编程中使用 checkedException。 74 | 75 | ## [什么是 Error](https://juejin.im/post/5e8d6b27f265da47c916fc4e) 76 | 77 | * Error 是程序无法处理的错误,表示运行应用程序中较严重问题。**大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题**。这些错误是不可检查的,因为它们在应用程序的控制和处理能力之 外,而且绝大多数是程序运行时不允许出现的状况,比如 `OutOfMemoryError `和 `StackOverflowError` 78 | 79 | * 除了程序计数器外,其他区域:方**法区(Method Area)、虚拟机栈(VM Stack)、本地方法栈(Native Method Stack) 和 堆(Heap) 都是可能发生 OutOfMemoryError 的区域**。 80 | * 虚拟机栈:**如果线程请求的栈深度大于虚拟机栈所允许的深度,将会出现 StackOverflowError 异常**;**如果虚拟机动态扩展无法申请到足够的内存,将出现 OutOfMemoryError**。 81 | * 本地方法栈和虚拟机栈一样 82 | * 堆:Java 堆可以处于物理上不连续,逻辑上连续,就像我们的磁盘空间一样,如果堆中没有内存完成实例分配,并且堆无法扩展时,将会抛出 OutOfMemoryError。 83 | * 方法区:方法区无法满足内存分配需求时,将抛出 OutOfMemoryError 异常。 84 | 85 | ### [NoClassDefFoundError 和 ClassNotFoundException 有什么区别](https://juejin.im/post/5e8d6b27f265da47c916fc4e) 86 | 87 | * 在类的加载过程中, JVM 或者 ClassLoader 无法找到对应的类时,都可能会引起这两种异常/错误,由于不同的 ClassLoader 会从不同的地方加载类,有时是**错误的 CLASSPATH 类路径导致的这类错误**,有时是**某个库的 jar 包缺失引发这类错误**。**NoClassDefFoundError 表示这个类在编译时期存在,但是在运行时却找不到此类**,有时静态初始化块也会导致 `NoClassDefFoundError `错误。 88 | 89 | * ClassNotFoundException 与编译时期无关,**当你尝试在运行时使用反射加载类时,ClassNotFoundException 就会出现** 90 | 91 | * ClassNotFoundException 和 NoClassDefFoundError 都是由 CLASSPATH 中缺少类引起的,通常是由于缺少 JAR 文件而引起的,但是如果 JVM 认为应用运行时找不到相应的引用,就会抛出 NoClassDefFoundError 错误;当你在代码中显示的加载类比如 `Class.forName()` 调用时却没有找到相应的类,就会抛出 `java.lang.ClassNotFoundException`。 92 | 93 | * **NoClassDefFoundError 是 JVM 引起的错误,是 unchecked,未经检查的。因此不会使用 try-catch 或者 finally 语句块**;另外,**ClassNotFoundException 是受检异常,因此需要 try-catch 语句块或者 try-finally 语句块包围,否则会导致编译错误**。 94 | * 调用` Class.forName()、ClassLoader.findClass() 和 ClassLoader.loadClass()` 等方法时可能会引起 `java.lang.ClassNotFoundException`,如图所示 95 | * NoClassDefFoundError 是链接错误,发生在链接阶段,当解析引用找不到对应的类,就会触发;而 ClassNotFoundException 是发生在运行时的异常。 96 | 97 | 98 | 99 | # 异常处理框架 100 | 101 | 在用户看来,应用系统发生的所有异常都是应用系统内部的异常 102 | 103 | * 设计一个通用的继承自RuntimeException的异常来统一处理 104 | * 其余异常都统一转译为上述异常AppException 105 | * 在catch之后,抛出上述异常的子类,并提供足以定位的信息 106 | * 由前端接收AppException做统一处理 107 | 108 | # [JVM OOM排查](https://www.jianshu.com/p/91e2b102dd4c) 109 | 110 | ## 一、jdk 自带基础工具 111 | 112 | 1. jps(Java Virtual Machine Process Status Tool) 113 | 114 | 实际中这是最常用的命令,下面要介绍的小工具更多的都是**先要使用jps查看出当前有哪些Java进程,获取该Java进程的id后再对该进程进行处理**。 115 | 116 | 2. **jstack** 117 | 118 | * jstack 主要用来查看某个Java进程内的线程堆栈信息 119 | 120 | * ``` 121 | option 说明如下: 122 | 123 | -l,会打印出额外的锁信息,在发生死锁时可以用jstack -l pid来观察锁持有情况 124 | 125 | -m 不仅会输出Java堆栈信息,还会输出C/C++堆栈信息(比如Native方法) 126 | ``` 127 | 128 | * `jstack -l pid ` 129 | 130 | ![img](https://upload-images.jianshu.io/upload_images/14461475-42da5ed62aef45a8.png?imageMogr2/auto-orient/strip|imageView2/2/w/1200/format/webp) 131 | 132 | 3. jmap(Memory Map) 133 | 134 | > ​ **jmap导出堆内存,然后使用jhat来进行分析** 135 | 136 | ``` 137 | -heap:打印jvm heap的情况 138 | -histo:打印jvm heap的直方图。其输出信息包括类名,对象数量,对象占用大小。 139 | 140 | -histo:live :同上,但是只打印存活对象的情况 141 | 142 | -permstat:打印permanent generation heap情况(持久代) 143 | 144 | 输出 类加载器名称、对象是否存活、对象地址、父类加载器、已加载的类大小等信息 145 | 146 | -dump:    打印 dump(内存使用) 日志文件 147 | ``` 148 | 149 | * **jmap -heap pid** 150 | 151 | **查看进程堆内存使用情况:****包括使用的GC算法、堆配置参数和各代中堆内存使用 152 | 153 | * **jmap -histo[:live] pid** 154 | 155 | **查看堆内存中的对象数目、大小统计直方图,如果带上live则只统计活对象** 156 | 157 | ## 二、MAT 分析Dump 158 | 159 | ``` 160 | Dump是反应Java堆使用情况的内存镜像,其中主要包括系统信息、虚拟机属性、完整的线程Dump、所有类和对象的状态等。 一般,在内存不足、GC异常等情况下,我们就会怀疑有内存泄漏。这个时候我们就可以制作堆Dump来查看具体情况。分析原因。 161 | ``` 162 | 163 | * Dump 文件的分析有多种方式 164 | 165 | > ​ 1、命令jhat 分析(麻烦) 166 | > 167 | > ​ 2、**VisualVM** 工具分析 168 | > 169 | > ​ 3、MAT 分析 170 | 171 | ## [内存溢出[OOM]异常快速定位排查](https://xiaolong.li/2019/09/27/OOM-error/) 172 | 173 | # [CPU负载过高异常定位排查](https://xiaolong.li/2019/09/26/CPU-loading-hight-exception/) 174 | 175 | ## 什么样的场景会导致线上CPU负载过高? 176 | 177 | 代码层面常见的场景有: 178 | 179 | > 程序陷入死循环,不停地消耗CPU 180 | > 线程死锁,线程相互等待,导致假死状态,不停地消耗CPU 181 | 182 | 183 | 184 | ## 定位过程 185 | 186 | ### top查找占用CPU高的进程 187 | 188 | * 查看进程中最耗cpu的子线程 189 | 190 | ``` 191 | top -Hp 4369 192 | ``` 193 | 194 | 如下图:可看出PID为 **4372** 的线程占用cpu最高,达到了99.7% 195 | [![image](https://xiaolong.li/images/exception/2019-09-26-top-Hp.png)](https://xiaolong.li/images/exception/2019-09-26-top-Hp.png) 196 | 197 | * ##### 线程id转换为16进制 198 | 199 | ``` 200 | printf "%x \n" 4372 201 | ``` 202 | 203 | 得到16进制数 **1114** 。 204 | 205 | ### 定位问题代码 206 | 207 | 使用jstack查看进程堆栈信息,定位占cpu最高的线程对应问题代码。 208 | 209 | > jstack 4369 | grep 1114 -A 30 -------------------------------------------------------------------------------- /计算机网络/路由算法.md: -------------------------------------------------------------------------------- 1 | # 网络中的「动态路由算法」,你了解吗? 2 | 3 | 在计算机网络中,路由器的一个很重要责任就是要在端对端的节点中找出一条最佳路径出来,通过自己与相邻节点之间的信息,来计算出从自己位置到目的节点之间的最佳线路,这种算法我们可以理解为路由算法。 4 | 5 | 路由的模式又主要分为「静态路由」和「动态路由」。静态路由协议是由网络管理员手动输入配置的,适用于小型的不太复杂的网络环境中,或者有特定需求的网络场景中。而动态路由协议是现代计算机网络中最为常用的一种方式。动态路由算法能够根据网络拓扑结构去适应流量的变化。 6 | 7 | 动态路由算法大致可以分为两类: 8 | 9 | - **距离矢量路由算法** 10 | - **链路状态路由算法** 11 | 12 | ## 一、距离矢量路由算法 13 | 14 | **距离矢量路由算法**(Distance Vector Routing),它是网络上最早使用的动态路由算法,也称为Bellman-Ford或者Ford-Fulkerson算法。基于这类算法实现的协议有:RIP、BGP等。 15 | 16 | ![https://img1.mukewang.com/5ba456d20001a7fb04490311.jpg](https://img.mukewang.com/5ba456d20001a7fb04490311.jpg) 17 | 18 | 如图, 19 | 20 | 21 | 22 | 这类算法的基本思路是:网络中每一个路由器都要维护一张 矢量表 ,这个 矢量表 中的每一行都记录了从当前位置能到达的目标路由器的最佳出口(接口)和距离(跳数)。 23 | 24 | **每隔一段时间当前路由器会向所有的邻居节点发送自己的这个表,同时它也会接收每个邻居发来的它们的表。并会将邻居的表和自己的表做一个对比更新。** 25 | 比如当前 路由器X 离 邻居Y路由器 的距离是m,此时收到 邻居Y 发来的表中写到了“ 邻居Y离路由器Z的距离是n ”,那 当前路由器X 就知道它离 路由器Z 的距离可能就是 m+n 了,如图: 26 | 27 | ![https://img3.mukewang.com/5ba456e100014f6705180086.jpg](https://img4.mukewang.com/5ba456e100014f6705000084.jpg) 28 | 29 | 就这样继续类推,要不了多久,**每个路由器就可以将网络中所有路由节点和子网线路都汇聚起来了。这样的话,每个路由器只需要查找自己的表就可以很容易的知道到达目的地的最佳出口(接口)是哪个了。** 30 | 31 | 当然,当网络结构发生变化的时候,各个路由器中的矢量表也会随之动态更新。 32 | 33 | 好了,讲到这里,基本上对「距离矢量路由算法」大概原理有个认识了,现在我们再来仔细分析分析这个算法的名字,可以发现,它的名字取的还是蛮有意思的,非常贴切。“距离”这个词就基本表明了这个算法是通过 距离(跳数/时间)来度量2个路由网络之间的线路的,而“矢量”这个词,可以看出线路是有方向性的,且路由表中只记录了数据包去往目的地应该走哪个出口方向,并不会记录到达目的地的整条路径。 34 | 35 | 「距离矢量路由算法」的**优点**很明显:非常简单清晰,且任何加入到网络中的新节点都能很快的与其它节点建立起联系获得补充信息。 36 | 37 | **缺点**呢,首先就是每次发送信息的时候,要发送整个全局路由表,太大了,因为每个路由器需要在矢量表中记录下整个网络的信息,导致需要较大存储、CPU、网络开销,对资源的要求越来越高。还有一个问题就是收敛时间太慢,也就是路由器共享路由信息并使各台路由器掌握的网络情况达到一致所需的时间比较久,收敛速度慢会导致有些路由器的表更新慢,从而造成路由环路的问题。 38 | 39 | ### 路由信息协议(RIP) 40 | 41 | 路由信息协议RIP(Routing Information Protocol)是基于[距离矢量](https://baike.baidu.com/item/%E8%B7%9D%E7%A6%BB%E7%9F%A2%E9%87%8F)算法的[路由协议](https://baike.baidu.com/item/%E8%B7%AF%E7%94%B1%E5%8D%8F%E8%AE%AE/202634),利用跳数来作为计量标准。 42 | 43 | * 简介 44 | 45 | 路由信息协议RIP(Routing Information Protocol)是基于距离矢量算法的路由协议,利用跳数来作为计量标准。在带宽、配置和管理方面要求较低,主要适合于规模较小的网络中。 46 | 47 | * 工作原理 48 | 49 | (1)路由建立 50 | 51 | 路由器运行RIP后,会首先发送路由更新请求,收到请求的路由器会发送自己的RIP路由进行响应;网络稳定后,路由器会周期性发送路由更新信息。 52 | 53 | (2)距离矢量的计算 54 | 55 | RIP度量的单位是跳数,其单位是1,也就是规定每一条链路的成本为1,而不考虑链路的实际带宽、时延等因素,RIP最多允许15跳。 56 | 57 | RIP利用度量来表示它和所有已知目的地间的距离。 58 | 59 | 当一个RIP更新报文到达时,接收方路由器和自己的RIP路由表中的每一项进行比较,并按照距离矢量路由算法对自己的RIP路由表进行修正。 60 | 61 | (3)定时器 62 | 63 | 周期更新定时器:用来激发RIP路由器路由表的更新,每个RIP节点只有一个更新定时器,设为30s。每隔30s路由器会向其邻居广播自己的路由表信息。每个RIP路由器的定时器都独立于网络中其他路由器,因此它们同时广播的可能性很小。 64 | 65 | 超时定时器:用来判定某条路由是否可用。每条路由有一个超时定时器,设为180s。当一条路由激活或更新时,该定时器初始化,如果在180s之内没有收到关于那条路由的更新,则将该路由置为无效。 66 | 67 | 清除定时器:用来判定是否清除一条路由。每条路由有一个清除定时器,设为120s。当路由器认识到某条路由无效时,就初始化一个清除定时器,如果在120s内还没收到这条路由的更新,就从路由表中将该路由删除。 68 | 69 | 延迟定时器:为避免触发更新引起广播风暴而设置的一个随机的延迟定时器,延迟时间为1~5s。 70 | 71 | (4)环路 72 | 73 | 当网络发生故障时,RIP网络有可能产生路由环路。可以通过水平分割、毒性反转、触发更新、抑制时间等技术来避免环路的产生。 74 | 75 | ## 二、链路状态路由算法 76 | 77 | **链路状态路由算法**(Link State Routing ),基于Dijkstra算法,它是以图论作为理论基础,用图来表示网络拓扑结构,用图论中的最短路径算法来计算网络间的最佳路由。基于这类算法实现的协议有:OSPF 等。 78 | 如图, 79 | 80 | ![https://img.mukewang.com/5ba456ee00011a3205650357.jpg](https://img1.mukewang.com/5ba456ee00011a3205000316.jpg) 81 | 82 | 这类算法的基本思路是:采用的是不停的拼接地图的方式。每一个路由器首先都会发现自己身边的邻居节点,然后将自己与邻居节点之间的链路状态包广播出去,发送到整个网络。这样,当某个路由器收到从网络中其它路由器广播来的路由信息包(链路状态包)之后,会将这个包中的信息与自己路由器上的信息进行拼装,最终形成一个全网的拓扑视图。 83 | 84 | 当路由器中形成了全网的拓扑视图后,它就可以通过最短路径算法来计算当前节点到其它路由器之间的最短路径了。当某台路由器的链路状态发生变化时,路由器采用**洪泛法**向所有路由器发送此信息,其它路由器使用收到的信息重新计算最佳路径,重新生成路由表(拓扑图)。 85 | 86 | **这里可以做一个类比,有一个路人甲人去问路,然后本地人A只知道A自己生活方圆5公里的地图,本地人B只知道B自己生活的方圆5公里的地图,但是路人甲要去的地方需要穿过A和B所在区域,那么就把A和B的2份地图拿来拼装在一起,然后去往目的地的完整路线就可以查出来了。** 87 | 88 | 链路状态路由算法简单而言就是五个步骤: 89 | 90 | 1. 发现邻居节点,并了解邻居网络地址 91 | 2. 测量到邻居节点的距离或成本度量值 92 | 3. 构建一个包含自己所拥有信息的链路状态包 93 | 4. 将这个包广播到网络中,并接收其它路由器的链路状态包 94 | 5. 计算出当前节点到其它节点之间的最短路径(基于Dijkstra算法) 95 | 96 | ![https://img1.mukewang.com/5ba456f800011da407000185.jpg](https://img.mukewang.com/5ba456f800011da405000133.jpg) 97 | 98 | # 组播相关协议 99 | 100 | 多播路由的一种常见的思路就是在多播组成员之间构造一棵扩展分布树。在一个特定的“发送源,目的组”对上的IP多播路由协议流量都是通过这个扩展树从发送源传输到接受者的,这个扩展树连接了该多播组中所有主机。不同的IP多播[路由协议](http://network.51cto.com/art/200511/11236.htm)使用不同的技术来构造这些多播扩展树,一旦这个树构造完成,所有的多播流量都将通过它来传播。 101 | 102 | 总的说来IP多播路由协议可以分为以下两种基本类型。第一种假设多播组成员密集地分布在网络中,也就是说,网络大多数的子网都至少包含一个多播组成员,而且网络带宽足够大,这种被称作“**密集模式**”(Dense-Mode)的多播路由协议**依赖于广播技术来将数据“推”向网络中所有的路由器**。密集模式IP多播路由协议包括距离向量IP多播路由协议(DVMRP:Distance Vector Multicast Routing Protocol)、多播开放最短路径优先协议(MOSPF:Multicast Open Shortest Path First)和密集模式独立多播协议(PIM-DM:Protocol-Independent Multicast-Dense Mode)等。 103 | 104 | 多播路由的第二种类型则假设多播组成员在网络中是稀疏分散的,并且网络不能提供足够的传输带宽,比如Internet上通过**ISDN**线路连接分散在许多不同地区的大量用户。在这种情况下,广播就会浪费许多不必要的网络带宽从而可能导致严重的网络性能问题。于是**稀疏模式IP多播路由协议必须依赖于具有路由选择能力的技术来建立和维持多播树**。稀疏模式主要有基于核心树的多播协议(CBT:Core Based Tree)和稀疏模式独立协议多播(PIM-SM:Protocol-Independent Multicast-Sparse Mode)。 105 | 106 | ## 密集模式协议 107 | 108 | ### (1)距离向量IP多播路由协议 (DVMRP) 109 | 110 | 第一个支持多播功能的路由协议就是距离向量IP多播路由协议。它已经被广泛地应用在多播骨干网MBONE上。**DVMRP为每个发送源和目的主机组构建不同的分布树。每个分布树都是一个以多播发送源作为根,以多播接受目的主机作为叶的最小扩展分布树**。这个分布树为发送源和组中每个多播接受者之间提供了一个最短路径,这个以“跳数”为单位的最短路径就是DVMRP的量度。当一个发送源要向多播组中发送消息时,一个扩展分布树就根据这个请求而建立,并且使用“广播和修剪”的技术来维持这个扩展分布树。 111 | 112 | 扩展分布树构建过程中的选择性发送多播包的具体运作是:当一个路由器接收到一个多播包,它先检查它的单播路由表来查找到多播组发送源的最短路径的接口,如果这个接口就是这个多播包到达的接口,那么路由器就将这个多播组信息记录到它的内部路由表(指明该组数据包应该发送的接口),并且将这个多播包向除了接受到该数据包的路由器以外的其他临近路由器继续发送。如果这个多播包的到达接口不是该路由器到发送源的最短路径的接口,那么这个包就被丢弃。这种机制被称为“反向路径广播”(Reverse-Path Broadcasting)机制,保证了构建的树中不会出现环,而且从发送源到所有接受者都是最短路径。对子网中密集分布的多播组来说DVMRP能够很好的运作,但是**对于在范围比较大的区域上分散分布的多播组来说,周期性的广播行为会导致严重的性能问题。DVMRP不能支持大型网络中稀疏分散的多播组**。 113 | 114 | ### (2)多播开放最短路径优先 (MOSPF) 115 | 116 | 开放最短路径优先(OSPF)是一个IP多播路由协议,它将数据包在最小开销路径上进行路由传送,这里的开销是表示链路状态的一种量度。除了路径中的跳数以外,其他能够影响路径开销的网络性能参数还有负载平衡信息、应用程序需要的QoS等。**MOSPF是为单播路由多播使用设计的**。MOSPF依赖于OSPF作为单播路由协议,就象DVMRP也包含它自己的单播协议一样。**在一个OSPF/MOSPF网络中每个路由器都维持一个最新的全网络拓扑结构图。这个“链路状态”信息被用来构建多播分布树。** 117 | 118 | 每个MOSPF路由器都通过IGMP协议周期性的收集多播组成员关系信息。这些信息和这些链路状态信息被发送到其路由域中的所有其他路由器。路由器将根据它们从临近路由器接收到的这些信息更新他们的内部连接状态信息。**由于每个路由器都清楚整个网络的拓扑结构,就能够独立的计算出一个最小开销扩展树,将多播发送源和多播组成员分别作为树的根和叶。这个树就是用来将多播流从发送源发送到多播组成员的路径。** 119 | 120 | ### (3)独立多播密集模式协议(PIM-DM) 121 | 122 | 独立多播协议(PIM)是一种标准的IP多播路由协议,并能够在Internet上提供可扩展的域间多播路由而不依赖于任何单播协议。PIM有两种运行模式,一种是密集分布多播组模式,另一个是稀疏分布多播组模式,前者被称为独立多播密集模式协议(PIM-DM),后者被称为独立多播稀疏模式协议(PIM-SM)。PIM-DM有点类似于DVMRP,这两个协议都使用了反向路径多播机制来构建分布树。它们之间的主要不同在于PIM完全不依赖于网络中的单播路由协议而DVMRP依赖于某个相关的单播路由协议机制,并且PIM-DM比DVMRP简单。 123 | 124 | PIM-DM协议和所有的密集模式IP多播路由协议一样也是**数据驱动**的。但是既然PIM-DM不依赖于任何单播路由协议,路由器某个接收端口(就是返回到源的最短路径的端口)接收到的多播数据包被发送到所有下行接口直到不需要的分枝从树中被修剪掉。DVMRP在树构建阶段能够使用单播协议提供的拓扑数据有选择性的向下行发送数据包,PIM-DM则更加倾向于简单性和独立性,甚至不惜增加数据包复制引起的额外开销。 125 | 126 | ## 稀疏模式多播路由协议 127 | 128 | 当多播组在网络中集中分布或者网络提供足够大带宽的情况下,密集模式IP多播路由协议是一个有效的方法,当多播组成员在广泛区域内稀疏分布时,就需要另一种方法即稀疏模式IP多播路由协议将多播流量控制在连接到多播组成员的链路路径上,而不会“泄漏”到不相关的链路路径上,这样既保证了数据传输的安全,又能够有效的控制网络中的总流量和路由器的负载。 129 | 130 | ### (1)基于核心树的多播协议 (CBT) 131 | 132 | 和DVMRP和MOSPF为每个“发送源、目的组”对构建最短路径树不同的是,**CBT协议只构建一个树给组中所有成员共享,这个树也就被称为共享树**。**整个多播组的多播通信量都在这个共享树上进行收发而不论发送源有多少或者在什么位置。这种共享树的使用能够极大的减少路由器中的多播状态信息。** 133 | 134 | **CBT共享树有一个核心路由器用来构建这个树。要加入的路由器发送加入请求给这个核心路由器。核心路由器接收到加入请求后,沿反路径返回一个确认,这样就构成了树的一个分枝。**加入请求数据包在被确认之前不需要一直被传送到核心路由器。**如果加入请求包在到达核心路由器之前先到达树上的某个路由器,该路由器就接收下这个请求包而不继续向前发送并确认这个请求包。发送请求的路由器就连接到共享树上了**。 CBT将多播流量集中在最少数量的链路而不是在一个基于发送源的共享树上。集中在核心路由器上的流量可能会引起多播路由的某些问题。某些版本的CBT支持多个多播核心的使用,和单个多播核心相比多核心更能达到负载平衡。 135 | 136 | ### (2)独立多播稀疏模式协议 (PIM-SM) 137 | 138 | 和CBT相似,PIM-SM被设计成将多播限制在需要收发的路由器上。PIM-SM围绕一个被称为集中点(RP:Rendezvous Point)的IP多播路由协议构建多播分布树。这个集中点扮演着和CBT核心路由器相同的角色,接收者在集中点能查找到新的发送源。但是PIM-SM比CBT更灵活,CBT的树通常是多播组共享树,PIM-SM中的独立的接收者可以选择是构建组共享树还是最短路径树。PIM-SM协议最初先为多播组构建一个组共享树。这个树由连接到集中点的发送者和接收者共同构建,就像CBT协议围绕着核心路由器构建的共享树一样。这共享树建立以后,一个接受者(实际上是最接近这个接收者的路由器)可以选择通过最短路径树改变到发送源的连接。这个操作的过程是通过向发送源发送一个PIM加入请求完成的。一旦从发送源到接收者的最短路径建立了,通过RP的外部分枝就被修剪掉了。 139 | 140 | -------------------------------------------------------------------------------- /Java/java基础.md: -------------------------------------------------------------------------------- 1 | # Java特性 2 | 3 | ## 封装 4 | 5 | * 隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别。 6 | 7 | ## 继承 8 | 9 | * 实现代码的复用。 10 | 11 | ## 多态 12 | 13 | > 同一种事物表现出的多种形态。 14 | 15 | * 多态的实现方式 16 | * 基于继承实现的多态 17 | 18 | * 基于接口实现的多态 19 | 20 | * 多态的存在有三个前提 21 | * 要有继承关系 22 | * ==子类要重写(override)父类的方法== 23 | * 父类引用指向子类对象 24 | * 多态性主要表现在如下两个方面: 25 | 26 | * 方法重载 27 | * 通常指在同一个类中,相同的方法名对应着不同的方法实现,但是方法的参数不同. 28 | * 成员覆盖 29 | * 通常指在不同类(父类和子类)中,允许有相同的变量名,但是数据类型不同;也允许有相同的方法名,但是对应的方法实现不同. 30 | * 多态的好处 31 | 32 | * 程序的可扩展性及可维护性增强。 33 | * 成员变量 34 | 35 | * 编译和运行都参考左边。 36 | * 成员函数(非静态) 37 | 38 | * 编译看左边,运行看右边 39 | * 静态函数 40 | * 编译和运行都看左边。 41 | * 项目中多态的应用 42 | * 在物流管理系统中,有两个用户有不同的权限,但使用相同的login方法登陆后会进入到不同的页面 43 | 44 | # Java对象创建过程 45 | 46 | 类加载检查-->分配内存-->初始化零值-->设置对象头-->执行init方法 47 | 48 | # 访问修饰符作用域 49 | 50 | | 访问级别 | 访问控制修饰符 | 同类 | 同包 | 子类 | 不同包 | 51 | | :------: | :------------: | :--: | :--: | :--: | :----: | 52 | | 公开 | public | √ | √ | √ | √ | 53 | | 受保护 | protected | √ | √ | √ | | 54 | | 默认 | default | √ | √ | | | 55 | | 私有 | private | √ | | | | 56 | 57 | 58 | 59 | # Java对象在内存中布局 60 | 61 | * 对象头 62 | * 实现Synchronized锁对象基础 63 | * 2个机器码(32位是8字节)存储对象头,如果是数组,则为3机器(12字节)码,多出来一个记录数组长度 64 | * 实例数据 65 | * 类属性信息,包括父类属性信息 66 | * 若数组的实例部分要包括数组的长度 67 | * 4字节对齐 68 | * 对齐填充 69 | * 虚拟机要求对象起始地址为8字节整数倍 70 | * 填充数据不是必须存在 71 | 72 | # List,Set,Collection,Collections 73 | 74 | 1.List和Set都是接口,他们都继承于接口Collection,List是一个有序的可重复的集合,而Set的无序的不可重复的集合。Collection是集合的顶层接口,Collections是一个封装了众多关于集合操作的静态方法的工具类,因为构造方法是私有的,所以不能实例化。 75 | 76 | 2.List接口实现类有ArrayList,LinkedList,Vector。ArrayList和Vector是基于数组实现的,所以查询的时候速度快,而在进行增加和删除的时候速度较慢LinkedList是基于链式存储结构,所以在进行查询的时候速度较慢但在进行增加和删除的时候速度较快。又因为Vector是线程安全的,所以他和ArrayList相比而言,查询效率要低。 77 | 78 | # 创建对象的方式 79 | 80 | * 使用new 81 | 82 | * Class类的newInstance方法 83 | 84 | * `newInstance()`调用无参构造器(反射) 85 | 86 | * `Class.forName().newInstance()` 87 | 88 | ```java 89 | User user = User.class.newInstance(); 90 | User user = (User)Class.forName("根路径.User").newInstance(); 91 | ``` 92 | 93 | * 使用Constructor类的`newInstance()`方法 94 | 95 | ```java 96 | Constructor constructor = User.class.getConstructor(); 97 | User user = constructor.newInstance(); 98 | ``` 99 | 100 | * 使用`clone()` 101 | 102 | * 需要先实现Cloneable接口并实现`clone方法` 103 | 104 | * 反序列化 105 | 106 | * 需实现Serializable接口 107 | * 序列化和反序列化对象时,JVM会创建一个单独对象。 108 | * 反序列化时,JVM创建对象不会调用任何构造函数 109 | 110 | # 类的实例化顺序 111 | 112 | * 加载类 113 | 114 | 1. 为父类静态属性分配内存并赋值 / 执行父类静态代码段 (按代码顺序) 115 | 116 | 2. 为子类静态属性分配内存并赋值 / 执行子类静态代码段 (按代码顺序) 117 | * 创建对象 118 | 119 | 1. 为父类实例属性分配内存并赋值 / 执行父类非静态代码段 (按代码顺序) 120 | 2. 执行父类构造器 121 | 3. 为子类实例属性分配内存并赋值 / 执行子类非静态代码段 (按代码顺序) 122 | 4. 执行子类构造器 123 | 124 | 125 | # 重写(override)与重载(overload) 126 | 127 | * 重写 128 | 129 | * 重写是子类对父类的允许访问的方法的实现过程进行重新编写, 130 | * 返回值和形参都不能改变。 131 | * **即外壳不变,核心重写!** 132 | 133 | * 重载 134 | 135 | * 在一个类里面,**方法名字相同,而参数不同**。返回类型可以相同也可以不同。 136 | * 每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。 137 | * 最常用的地方就是构造器的重载。 138 | 139 | * 重载规则 140 | 141 | - 被重载的方法**必须改变参数列表**(参数个数或类型不一样); 142 | - 被重载的方法可以改变返回类型; 143 | - 被重载的方法可以改变访问修饰符; 144 | - 被重载的方法可以声明新的或更广的检查异常; 145 | - 方法能够在同一个类中或者在一个子类中被重载。 146 | - 无法以返回值类型作为重载函数的区分标准。 147 | 148 | * 重写与重载的区别 149 | 150 | | 区别点 | 重载方法 | 重写方法 | 151 | | :--------- | :-------------------- | ---------------------------------------------- | 152 | | 参数列表 | 必须修改 | 一定不能修改 | 153 | | 返回类型 | 可以修改 | 一定不能修改 | 154 | | 异常 | 可以修改 | 可以减少或删除,一定不能抛出新的或者更广的异常 | 155 | | 访问修饰符 | 可以修改 | 一定不能做更严格的限制(可以降低限制) | 156 | | 发生时机 | 同一类中,或继承关系中 | 子类与父类之间 | 157 | 158 | ![img](https://www.runoob.com/wp-content/uploads/2013/12/20171102-1.jpg) 159 | 160 | ## 是否可以重写Private或Static方法 161 | 162 | * static方法不能被重写 163 | * 重写是基于运行时绑定的,而static方法是编译时绑定 164 | * static方法跟类的实例不相关,概念上不适用 165 | * private方法不可重写 166 | * private修饰的变量和方法只能在当前类中使用 167 | * 若其他类继承当前类则无法访问到private方法 168 | 169 | # 运算符优先级 170 | 171 | 单目运算符:+,-,++,-- 172 | 173 | 算数运算符:+,-,*,/,% 174 | 175 | 移位运算符:<<,>> 176 | 177 | 关系运算符:>,<,>=,<=,==,!= 178 | 179 | 位运算符:&,|,~,^, 180 | 181 | 逻辑运算符:&&,|| 182 | 183 | 三目运算符:表达式1?表达式2:表达式3; 184 | 185 | 赋值运算符:=等 186 | 187 | 188 | 189 | # switch 190 | 191 | switch 语句中的变量类型可以是: 192 | 193 | byte、short、int 或者 char。 194 | 195 | 从 Java SE 7 开始,switch 支持字符串 String 类型了,同时 case 标签必须为字符串常量或字面量。 196 | 197 | 198 | 199 | # equals与hashCode() 200 | 201 | - 若两对象相同equals返回true,则hashCode值必相同 202 | - 若两对象hashCode相同,equals可能为false 203 | - hashCode 204 | - 对象比较时先进行hashCode比较.若不同,则没有后序比较必要.减少了equals比较次数,效率提高 205 | - 集合中的例子 206 | - set集合不重复且无序,在插入时会判断是否重复,若用equals则全都要比较一遍,使用hash表大大减少比较的次数 207 | - 为何必须重写hashCode 208 | - equals根据对象的特征重写的 209 | - 保证同一对象在equals相同时hashCode必相同 210 | 211 | # ==与equals的区别 212 | 213 | * equals由开发者自己写逻辑,默认为== 214 | * String重写了equals,比较字符是否相同 215 | * ==判断两个判断是否或实例是不是指向同一个内存空间 216 | * equals判断两个变量或实例所指向的内存空间的值是否相同 217 | * 基本数据类型用==比较的是值 218 | * `StringBuffer` 和`StringBuilder`特殊.==和equals都是比较地址 219 | 220 | # sleep和wait的区别 221 | 222 | ![](https://pic2.zhimg.com/80/bb4f380c79779c9dc1aea6f0a6c10b6d_hd.jpg) 223 | 224 | * sleep让线程阻塞,特定时间后转为非阻塞,重新获得CPU 225 | * wait调用时先获得该Object的锁,调用wait后将锁释放并阻塞.当调用notify/notifyAll后,可能获得CPU重新获得锁 226 | 227 | # [Clone()](https://segmentfault.com/a/1190000010648514) 228 | 229 | * 声明为`protected Object clone() CloneNotSupportedException` 230 | 231 | * 无论浅拷贝还是深拷贝,都需要实现clone()方法以及`Cloneable`接口来完成操作 232 | 233 | 234 | ## [浅拷贝](https://juejin.im/post/6844903929705136141) 235 | 236 | ![img](https://user-gold-cdn.xitu.io/2019/9/1/16ce894a1f1b5c32?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) 237 | 238 | * **对基本数据类型进行值传递,对引用数据类型进行引用传递** 239 | 240 | * 需要新建一个对象,该新对象有原对象中的所有属性值,位置一一对应,如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,所以其中一个对象改变了这个地址,就会影响到另一个对象。过程中修改了原对象不会影响到新对象的拷贝。 241 | 242 | 243 | 244 | ## [深拷贝](https://cloud.tencent.com/developer/news/594548) 245 | 246 | * ![img](https://user-gold-cdn.xitu.io/2019/9/1/16ce893a54f6c13d?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) 247 | * 将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象 248 | * 如果是原始类型,无需继续拷贝,直接返回 249 | * 如果是引用类型,创建一个新的对象,遍历需要克隆的对象,将需要克隆对象的属性执行**深拷贝后**依次添加到新对象上。 250 | 251 | # static 252 | 253 | * static方法是否能被覆盖 254 | * 不能,因方法覆盖是基于运行时动态绑定的,而static方法是编译时静态绑定的 255 | * 是否可在static中访问非static变量 256 | * 不能,Static属于类,在类加载时就被初始化,此时非静态变量未被加载 257 | * static 修饰的变量并发下怎么保证变量的安全 258 | * 静态变量位于方法区,为所有对象共享,修改对其他对象可见,非线程安全 259 | * 静态方法若无使用静态变量,则无线程安全问题 260 | * 因静态方法内声明的变量,每个线程调用时都会创建一份,而不会可使用一个存储单元 261 | * 加锁 262 | * static 修饰的变量什么时候赋值 263 | * static 什么时候使用 264 | 265 | # 序列化 266 | 267 | * 定义 268 | * 将实现Serializable接口的对象转换成一个字节序列,并在以后恢复成原来的对象,序列化可以弥补不同操作系统之间差异 269 | * 作用 270 | * Java远程方法调用RMI 271 | * 对Java Beans进行序列化 272 | 273 | ## 如何实现序列化与反序列化 274 | 275 | * 序列化 276 | * 实现Serializable接口 277 | * 若不改变方法中`readObject()`和`writeObject()`方法,则采取默认序列化机制 278 | * 可使用`transient`关键字修饰不必序列化的属性 279 | * 实现`ExternalSerializable`接口 280 | * 自己要对序列化内容进行控制,控制那些属性能被序列化 281 | * 反序列化 282 | * 不需调用构造方法,完全基于字节 283 | * 实现`ExternalSerializable`接口的方法在反序列化时会调用构造方法 284 | * 注 285 | * ==被static修饰属性不会序列化== 286 | * 父类实现序列化子类自动实现 287 | * 方法不会被序列化(只保存对象(不是类,因为static属性)的状态,不保存对象的方法) 288 | * 通过网络,文件序列化时,必须按照写入的顺序读取对象 289 | * 反序列化时须有序列化对象的class文件 290 | * 最好显示声明serializableID,因不同JVM间,默认生成serializableID可能不同 291 | * 当一个对象的实例变量引用其他变量时,序列化该对象时也要把其他对象序列化 292 | * 并非所有对象都可以序列化 293 | * 安全原因,在对象序列化过程中,private等域不受保护 294 | * 资源分配原因,如socket,thread类,如果可以序列化进行传输或者保存,也无法对它们进行资源重新分配 295 | * 序列化前和后对象关系是equal关系,深复制(拷贝) 296 | 297 | # [Comparable接口与Comparator接口区别](https://cloud.tencent.com/developer/article/1118794) 298 | 299 | * Comparable接口 300 | * 需要修改源码,在源码中实现`compareTo() `方法,是一个内比较器 301 | * Comparator接口 302 | * 不用修改源码,实现`compare()`方法,一个外比较器 303 | * 用Comparator 的好处是**不需要修改源代码**, 而是另外实现一个比较器, 当某个自定义的对象需要作比较的时候,把比较器和对象一起传递过去就可以比大小了, 并且在Comparator里面用户可以自己实现复杂的可以通用的逻辑,使其可以匹配一些比较简单的对象,那样就可以节省很多重复劳动了。 -------------------------------------------------------------------------------- /设计模式/设计模式.md: -------------------------------------------------------------------------------- 1 | # 单例模式 2 | 3 | * 保证全局的单例类只有一个实例 4 | * 数据库连接 5 | * Spring中的Bean(Singleton) 6 | 7 | - 优缺点 8 | 9 | - 确保全局至多只有一个对象 10 | - 用于:构造缓慢的对象,需要统一管理资源 11 | - 缺点: 很多全局状态,线程安全性 12 | 13 | - 单例模式的创建 14 | 15 | - 双重锁模式 Double checked locking 16 | - 作为Java类的静态变量 17 | - 使用框架提供的能力 18 | 19 | - 饿汉式 20 | 21 | ```java 22 | //缺点:类加载时完成实例化,浪费空间 23 | public class Singleton{ 24 | private static Singleton instance = new Singleton(); 25 | private Singleton(){} 26 | public static Singleton getInstance(){ 27 | return instance; 28 | } 29 | } 30 | ``` 31 | 32 | * 懒汉式 33 | 34 | ```java 35 | //DCL模式(Double Check Lock双端检锁机制) 36 | public class Singleton{ 37 | 38 | //加volatile是因为防止指令重排 39 | //memory = allocate(); //1.分配对象内存空间 40 | //instance(memory); //2.初始化对象 41 | //instance = memory; //3.设置instance指向刚分配的内存地址,此时Instance !=null,但instance还未完成初始化 42 | private static volatile Singleton instance; 43 | private Singleton(){} 44 | public static Singleton getInstance(){ 45 | if(null == instance){ 46 | synchronized(Singleton.class){ 47 | if(null == instance){ 48 | instance = new Singleton(); 49 | } 50 | } 51 | } 52 | return instance; 53 | } 54 | } 55 | ``` 56 | 57 | * 枚举 58 | 59 | * 省略了`private`类型构造函数 60 | * INSTANCE相当于Singleton的实例对象 61 | 62 | ```java 63 | public enum Singleton{ 64 | //相当于public static final Singleton INSTANCE; 65 | INSTANCE; 66 | } 67 | ``` 68 | 69 | 70 | 71 | ## 单例在多线程中的运行问题? 72 | 73 | * 多线程中调用懒汉式单例模式会存在线程安全问题 74 | 75 | ## 单例模式为何要私有化构造函数 76 | 77 | * 有实例化该对象时,会调用构造函数,会导致不断初始化该类.内存会很快耗尽 78 | * 通过将构造函数私有化,外部无法实例化该对象.提供一个静态方法将实例返回,使其他类不用实例化也可以获取该实例 79 | 80 | # [工厂模式](https://zhuanlan.zhihu.com/p/28338253) 81 | 82 | * 所谓**工厂模式**,简单的来说**,就是自己不再主动创建对象,而是让工厂来帮我们创建对象。** 83 | 84 | * **通常工厂提供一个getObject()方法**,程序员调用这个方法来获取自己实际想要的对象。 85 | 86 | * 这样的好处是什么呢?简单来说 ,**就是方便扩展。** 87 | 88 | * 工厂方法模式 89 | 90 | * 每种产品由一种工厂来创建 91 | 92 | ```java 93 | java.lang.Proxy#newProxyInstance() 94 | java.lang.Object#toString() 95 | java.lang.Class#newInstance() 96 | java.lang.reflect.Array#newInstance() 97 | java.lang.reflect.Constructor#newInstance() 98 | java.lang.Boolean#valueOf(String) 99 | java.lang.Class#forName() 100 | ``` 101 | 102 | 103 | 104 | * 抽象工厂模式 105 | 106 | ```java 107 | java.util.Calendar#getInstance() 108 | java.util.Arrays#asList() 109 | java.util.ResourceBundle#getBundle() 110 | java.sql.DriverManager#getConnection() 111 | java.sql.Connection#createStatement() 112 | java.sql.Statement#executeQuery() 113 | java.text.NumberFormat#getInstance() 114 | javax.xml.transform.TransformerFactory#newInstance() 115 | ``` 116 | 117 | * Spring IOC中,将对象创建交给工厂 118 | 119 | # 状态模式 120 | 121 | # 代理模式 122 | 123 | - 客户端不想直接访问实际对象,通过代理对象为桥梁,完成间接访问 124 | 125 | - 实现方式 126 | - 静态代理 127 | - 在程序运行前就已经存在代理类的字节码 128 | - 优点 129 | - 只需要关注业务本身,保证业务类的重用性 130 | - 缺点 131 | - 代理对象的一个接口只服务于一种类型的对象,若代理方法很多,必须为每一种方法进行代理,代理在程序规模大时无法胜任 132 | - 若接口增加一方法,则实现类和代理类都要实现此方法,增加复杂度 133 | - 动态代理 134 | - 在程序运行期间由JVM根据反射等机制动态生成 135 | - 优点 136 | - 接口中声明的方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke),在接口方法较多时可灵活处理,不需像静态代理一样对每一个方法中转 137 | 138 | ```java 139 | java.lang.reflect.Proxy 140 | ``` 141 | 142 | 143 | ## [代理模式与装饰器模式的区别](https://www.zhihu.com/question/41988550) 144 | 145 | * 装饰器模式应当为所装饰的对象提供**增强功能**,而代理模式对所代理对象的使用施加控制,并不提供对象本身的增强功能。 146 | 147 | 第一段说的是代理模式,==侧重于不能直接访问一个对象,只能通过代理来间接访问==,比如对象在另外一台机器上,或者对象被持久化了,对象是受保护的。对象在另外一台机器上,其实就是rpc,感兴趣的可以看看dubbo的源码本地反问的其实就是远程对象的代理,只不过代理帮你做了访问这个对象之前和之后的很多事情,但是对使用者是透明的了。对象被持久化了,比如mybatis的mapperProxy。通过mapper文件自动生成代理类。第三种,对内核对象的访问。 148 | 149 | 第二段说的是装饰器模式是因为没法在编译器就确定一个对象的功能,需要运行时动态的给对象添加职责,所以只能把对象的功能拆成一一个个的小部分,动态组装,感兴趣的可以看看dubbo的源码,里面的mock,cluster,failover都是通过装饰器来实现的。因为这些功能是由使用者动态配置的。但是代理模式在编译器其实就已经确定了和代理对象的关系。 150 | 151 | 第三段说的是,这个两个设计模式是为了解决不同的问题而抽象总结出来的。是可以混用的。可以在代理的基础上在加一个装饰,也可以在装饰器的基础上在加一个代理。感兴趣的去看看dubbo源码,里面就是这么实现的。 152 | 153 | # 观察者模式 154 | 155 | - <发面订阅模式/源-监听器模式> 156 | 157 | - 多个观察者同时**监听**一个主题,主题变化时会通知所有观察者。 158 | 159 | - 与发布订阅模式的区别 160 | - 发布者和订阅者不知对方存在,需一个第三方组件(信息中介),将发布者和订阅者串联起来 161 | - 发布订阅塔式中,组件松耦合,观察者模式相反 162 | - 发察者模式大多同步,发布订阅模式大多异步(消息队列) 163 | 164 | ```java 165 | Jdk : java.util.EventListener 166 | javax.servlet.http.HttpSessionBindingListener 167 | javax.servlet.http.HttpSessionAttributeListener 168 | javax.faces.event.PhaseListener 169 | ``` 170 | 171 | # [模板方法模式](https://blog.csdn.net/carson_ho/article/details/54910518) 172 | 173 | - 让子类可以重写方法的一部分,而不是整个重写,可以控制子类需要重写哪些操作 174 | - 模板方法模式是基于继承的代码复用技术,它体现了面向对象的诸多重要思想,是一种使用较为频繁的设计模式。模板方法模式广泛应用于框架设计(例如:Spring,JUnit等)中,以确保通过父类来控制处理流程的逻辑顺序(例如框架的寝化,测试流程和设置等) 175 | 176 | ## 应用场景 177 | 178 | * AQS的同步器,是典型的模板方法模式 179 | 180 | - 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现; 181 | - 各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复; 182 | - 控制子类的扩展。 183 | 184 | ## 缺点 185 | 186 | 引入了抽象类,每一个不同的实现都需要一个子类来实现,导致类的个数增加,从而增加了系统实现的复杂度 187 | 188 | # [策略模式](https://cloud.tencent.com/developer/article/1118794) 189 | 190 | * 用 Comparator 是策略模式(strategy design pattern),就是不改变对象自身,而用一个策略对象(strategy object)来改变它的行为。 191 | * [JDK的策略模式应用](https://juejin.im/post/6844903748788027400) 192 | * 其中我们可以找到RejectedExecutionHandler,这个参数代表的是拒绝策略(有四种具体的实现:直接抛出异常、使用调用者的线程来处理、直接丢掉这个任务、丢掉最老的任务) 193 | 194 | # 适配器模式 195 | 196 | * 将一个类的接口转换为客户希望的另一个接口,使得原不兼容接口兼容 197 | 198 | ```java 199 | java.util.Arrays#asList() 200 | java.io.InputStreamReader(InputStream) 201 | java.io.OutputStreamWriter(OutputStream) 202 | ``` 203 | 204 | 205 | 206 | # 迭代器模式 207 | 208 | * 提供一种方法顺序访问一个聚合对象中的各个元素,成果又不用暴露该对象的内部表示 209 | 210 | ```java 211 | java.util.Iterator 212 | java.util.Enumeration 213 | ``` 214 | 215 | # 装饰器模式 216 | 217 | * 动态地给一个对象增加一些客外的职责。就扩展功能而言,装饰器模式提供了一种比使用子类更加灵活的替代方案 218 | 219 | * 扩展一个对象的功能,装饰模式比继承更加灵活,不会导致类的个数急剧增加 220 | 221 | * 可以对一个对象进行多次装饰,通过使用不同的具体装饰类以及这些装饰类的排列组合可以创造出很多种不同行为和组合,得到功以能更强大的对象 222 | 223 | * 具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,原有类库代码无须改变,符合开闭原则。 224 | 225 | ```java 226 | //通过包含一个原有InputStream对象,并且将InputStream原有方法或直接暴露,或进行装饰后暴露,又或者添加了新的特性 227 | java.io.BufferedInputStream(InputStream) 228 | java.io.DataInputStream(InputStream) 229 | java.io.BufferedOutputStream(OutputStream) 230 | java.util.zip.ZipOutputStream(OutputStream) 231 | ``` 232 | 233 | # 建造者模式 234 | 235 | * 定义一个新的类来构建另一个类的实例,以简化复杂对象的创建,建造模式通常也使用方法链接来实现 236 | 237 | ```java 238 | java.lang.StringBuilder#append() 239 | java.lang.StringBuffer#append() 240 | java.sql.PreparedStatement 241 | javax.swing.GroupLayout.Group#addComponent() 242 | ``` 243 | 244 | # [责任链模式](https://juejin.im/post/6844904181963161608#heading-3) 245 | 246 | * 通过把请求从一个对象传递到链条中下一个对象的方式,直到请求被处理完毕以实现对象解耦 247 | 248 | ```java 249 | java.util.logging.Logger#log() 250 | javax.servlet.Filter#doFilter() 251 | ``` 252 | 253 | 254 | ## [责任链模式的优点](https://juejin.im/post/6844904181963161608#heading-3) 255 | 256 | * 1.如果要加一些过滤的关键字,只需要加一个过滤的类,然后再添加到过滤器的集合中,不需要对原来的代码进行侵入式的开发。符合`开闭原则`。 257 | 258 | * 2.执行顺序要变更的话,也不需要侵入式的改代码,只需要改一下添加过滤器的顺序。在`Servlet`中,过滤器的顺序就是按`xml`文件定义的顺序。在`SpringMVC`则是按注册的顺序。这就非常易于扩展。** 259 | 260 | 261 | 262 | # 享元模式 263 | 264 | * 当系统中存在大量相同或者相似的对象时,享元模式是一种值得考虑的解决方案,它通过共享技术实现相同或相似的细粒度对象的利用,从而节约了内存空间,提高了系统性能。 265 | 266 | * String类使用了享元模式 267 | 268 | ```java 269 | //使用缓存来加速大量小对象的访问时间。 270 | java.lang.Integer#valueOf(int) 271 | java.lang.Boolean#valueOf(boolean) 272 | java.lang.Byte#valueOf(byte) 273 | java.lang.Character#valueOf(char) 274 | ``` 275 | 276 | # 中介者模式 277 | 278 | * 使用一个中间对象来进行消息分发及减少类之间的直接依赖 279 | 280 | ```java 281 | java.util.Timer 282 | java.util.concurrent.Executor#execute() 283 | java.util.concurrent.ExecutorService#submit() 284 | java.lang.reflect.Method#invoke() 285 | ``` 286 | 287 | # 备忘录模式 288 | 289 | * 生成对象状态的一个快照,以便可以恢复原始状态而不用暴露自身内容 290 | 291 | ```java 292 | //Date对象通过自身内部的一个 long 值来实现备忘录模式。 293 | java.util.Date 294 | java.io.Serializable 295 | ``` 296 | 297 | # 组合模式 298 | 299 | * 组合模式又称为“部分-整体模式”,某个类型的方法同时也接受自身类型作为参数 300 | 301 | ```java 302 | javax.swing.JComponent#add(Component) 303 | java.util.Map#putAll(Map) 304 | java.util.List#addAll(Collection) 305 | java.util.Set#addAll(Collection) 306 | ``` 307 | 308 | # 命令模式 309 | 310 | 可以将开关理解成一个请求的发送者,用户通过它来发送一个“开灯”的请求,而电灯是“开灯请求”的最终接收者和处理者,开关和电灯之间并不存在直接耦合关系,它们通过电线连接在一起,使用不同的电线可以连接不同的请求接收者,只需更换一根电线,相同的发送者(开关)即可对应不同的接收者(电器) 311 | 312 | * 实例说明 313 | 314 | ```latex 315 | 为了用户使用方便,某系统提供了一系列功能键,用户可以自定义功能键的功能,例如功能键FunctionButton可以用于退出系统(由SystenExitClass类来实现),也可以用于显示帮助文档(由DisplayHelpClass类来实现) 316 | 317 | 用户可以通过修改配置文件改变功能键的用途,现使用命令模式设计该系统,使得功能键类与功能类之间解耦。可以为同一个功能键设置不同和功能。 318 | ``` 319 | 320 | # 解释器模式 321 | 322 | 解释器模式用于描述如何构成一个简单的语言解释器,主要用于使用面向对象语言开发的解释器的设计。当需要开发一个新的语言时可以考虑使用解释器模式。在实际应用中也许很少碰到构造一个语言的情况,虽然很少使用,但是对它的学习能够加深对面向对象思想的理解,并且掌握编程语言中语法规则解释的原理和过程。 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | --------------------------------------------------------------------------------