当前位置: 首页 > news >正文

joomla做类似赶集网的网站wordpress 文章 html

joomla做类似赶集网的网站,wordpress 文章 html,网站效果图制作,5 网站建设的基本步骤是一、JDK版本之间的关系 1.1、Oracle JDK与OpenJDK的区别 1.Oracle JDK是基于OpenJDK源代码构建的#xff0c;因此Oracle JDK和OpenJDK之间没有重大的技术差异。 2.Oracle JDK将更多地关注稳定性#xff0c;它重视更多的企业级用户#xff0c;而OpenJDK经常发布以支持其他性能… 一、JDK版本之间的关系 1.1、Oracle JDK与OpenJDK的区别 1.Oracle JDK是基于OpenJDK源代码构建的因此Oracle JDK和OpenJDK之间没有重大的技术差异。 2.Oracle JDK将更多地关注稳定性它重视更多的企业级用户而OpenJDK经常发布以支持其他性能这可能会导致不稳定。 3.Oracle JDK具有良好的GC选项和更好的渲染器而OpenJDK具有更少的GC选项并且由于其包含自己的渲染器的分布因此具有较慢的图形渲染器选项。 4.Oracle JDK以前的1.0版以前的版本是由Sun开发的后来被Oracle收购并为其他版本维护而OpenJDK最初只基于Java SDK或JDK版本7。 5.Oracle JDK发布时大多数功能都是开源的其中一些功能免于开源并且根据Sun的许可授权而OpenJDK发布了所有功能如开源和免费。 6.Oracle JDK完全由Oracle公司开发而Open JDK项目由IBMAppleSAP AGRedhat等顶级公司加入和合作。 添加图片注释不超过 140 字可选 结论 Oracle JDK可用于开发Java Web应用程序独立应用程序以及许多其他图形用户界面以及其他开发工具。Oracle JDK执行的所有操作或任务也可以由OpenJDK执行但只有Oracle与OpenJDK之间的区别在于Open JDK在现有Oracle JDK之上的许可和其他工具集成和实现。使用OpenJDK的优点是可以根据应用程序的要求修改性能可伸缩性和实现以根据需要调整Java虚拟机。 OpenJDK的优势更多Oracle JDK的使用在Oracle JDK实现中使用的标准方面也有一些好处这将确保应用程序稳定和良好维护。 1.2、openjdk和adoptopenjdk的区别 1.openjdk提供了源代码adoptopenjdk提供了该源代码的构建。 2.OpenJDK是一个open-source项目提供了Java platform实现的源代码而非内部版本 AdoptOpenJDK是由Java社区的一些著名成员创建的组织旨在为Java技术的用户免费提供二进制版本和安装程序。 1.3、openjdk和Alibaba DrAGonwell的关系 Alibaba DrAGonwell 是 OpenJDK 的下游每个 Alibaba DrAGonwell 发行版都会同步上游最新更新。同时阿里巴巴也会积极将 AJDK 上的技术积累贡献到 OpenJDK 二、java里几种加密方式 1.1、Java常用加密方式 Base64加密算法(编码方式) MD5加密(消息摘要算法验证信息完整性) 对称加密算法 非对称加密算法 数字签名算法 数字证书 1.2、分类 按加密算法是否需要key被分为两类 不基于key的有: Base64算法、MD5 基于key的有: 对称加密算法、非对称加密算法、数字签名算法、数字证书、HMAC、RC4(对称加密) 按加密算法是否可逆被分为两类 单向加密算法(不可解密)MD5、SHA、HMAC 非单向加密算法(可解密)BASE64、对称加密算法、非对称加密算法、数字签名算法、数字证书 1.3、应用场景 Base64应用场景图片转码(应用于邮件img标签http加密) MD5应用场景密码加密、imei加密、文件校验 非对称加密电商订单付款、银行相关业务 BASE64的加密解密是双向的可以求反解。MD5、SHA以及HMAC是单向加密任何数据加密后只会产生唯一的一个加密串通常用来校验数据在传输过程中是否被修改。其中HMAC算法有一个密钥增强了数据传输过程中的安全性强化了算法外的不可控因素。 单向加密的用途主要是为了校验数据在传输过程中是否被修改 三、Object类常用方法 object类中方法说明如下 1 registerNatives() //私有方法 2 getClass() //返回此 Object 的运行类。 3 hashCode() //用于获取对象的哈希值。 4 equals(Object obj) //用于确认两个对象是否“相同”。 5 clone() //创建并返回此对象的一个副本。 6 toString() //返回该对象的字符串表示。 7 notify() //唤醒在此对象监视器上等待的单个线程。 8 notifyAll() //唤醒在此对象监视器上等待的所有线程。 9 wait() //用于让当前线程失去操作权限当前线程进入等待序列 和equals区别 基本类型比较值是否相同 引用类型比较内存地址是否相同 equals:引用类型object类比较的是地址值但是其他类大都重写了equals方法比较成员变量的值是否相同 hashcode()和equals()的区别 hashCode()方法和equal()方法的作用其实一样在Java里都是用来对比两个对象是否相等一致 因为重写的equal里一般比较全面比较复杂这样效率就比较低而利用hashCode()进行对比则只要生成一个hash值进行比较就可以了效率很高那么hashCode()既然效率这么高为什么还要equal()呢 因为hashCode()并不是完全可靠有时候不同的对象他们生成的hashcode也会一样生成hash值得公式可能存在的问题所以hashCode()只能说是大部分时候可靠并不是绝对可靠 四、JAVA的基本数据类型 基本类型共有八种它们分别都有相对应的包装类 四种整数类型(byte、short、int、long) 两种浮点数类型(float、double) 一种字符类型(char) 一种布尔类型(boolean) 记忆8位Byte字节型 16位short短整型、char字符型 32位int整型、float单精度型/浮点型 64位long长整型、double双精度型 最后一个boolean(布尔类型 Integer和int的区别 int是java的8种内置的原始数据类型。Java为每个原始类型都提供了一个封装类Integer就是int的封装类。 int变量的默认值为0Integer变量的默认值为null这一点说明Integer可以区分出未赋值和值为0的区别 五、String, StringBuffer, StringBuilder的区别是什么 1、String是字符串常量StringBuffer和StringBuilder都是字符串变量。后两者的字符内容可变而前者创建后内容不可变。 2、String不可变是因为在JDK中String类被声明为一个final类。 3、StringBuffer是线程安全的而StringBuilder是非线程安全的。 补充说明线程安全会带来额外的系统开销所以StringBuilder的效率比StringBuffer高。如果对系统中的线程是否安全很掌握可用StringBuffer在线程不安全处加上关键字Synchronize。 六、Vector, ArrayList, LinkedList的区别是什么 1、Vector、ArrayList都是以类似数组的形式存储在内存中LinkedList则以链表的形式进行存储。 2、List中的元素有序、允许有重复的元素Set中的元素无序、不允许有重复元素。 3、Vector线程同步ArrayList、LinkedList线程不同步。 4、LinkedList适合指定位置插入、删除操作不适合查找ArrayList、Vector适合查找不适合指定位置的插入、删除操作。 5、ArrayList在元素填满容器时会自动扩充容器大小的约50%而Vector则是100%因此ArrayList更节省空间。 为什么java不推荐使用vector 因为vector是线程安全的所以效率低这容易理解类似StringBuffer Vector空间满了之后扩容是一倍而ArrayList仅仅是一半 Vector分配内存的时候需要连续的存储空间如果数据太多容易分配内存失败 只能在尾部进行插入和删除操作效率低 1. ArrayList 和 Vector 的区别。 这两个类都实现了 List 接口List 接口继承了 Collection 接口他们都是有序集 合即存储在这两个集合中的元素的位置都是有顺序的相当于一种动态的数组我 们以后可以按位置索引号取出某个元素并且其中的数据是允许重复的这是 HashSet 之类的集合的最大不同处HashSet 之类的集合不可以按索引号去检索其 中的元素也不允许有重复的元素本来题目问的与 hashset 没有任何关系但为了 说清楚 ArrayList 与 Vector 的功能我们使用对比方式更有利于说明问题。接 着才说 ArrayList 与 Vector 的区别这主要包括两个方面。  同步性 Vector 是线程安全的也就是说是它的方法之间是线程同步的而 ArrayList 是线 程序不安全的它的方法之间是线程不同步的。如果只有一个线程会访问到集合那 最好是使用 ArrayList因为它不考虑线程安全效率会高些如果有多个线程会访问 到集合那最好是使用 Vector因为不需要我们自己再去考虑和编写线程安全的代 码。 备注对于 VectorArrayList、HashtableHashMap要记住线程安全的问题 记住 Vector 与 Hashtable 是旧的是 java 一诞生就提供了的它们是线程安全 的ArrayList 与 HashMap 是 java2 时才提供的它们是线程不安全的。所以我 们讲课时先讲老的。  数据增长 ArrayList 与 Vector 都有一个初始的容量大小当存储进它们里面的元素的个数超 过了容量时就需要增加 ArrayList 与 Vector 的存储空间每次要增加存储空间 时不是只增加一个存储单元而是增加多个存储单元每次增加的存储单元的个数 在内存空间利用与程序效率之间要取得一定的平衡。Vector 默认增长为原来两倍而 ArrayList 的增长策略在文档中没有明确规定从源代码看到的是增长为原来的 1.5 倍。ArrayList 与 Vector 都可以设置初始的空间大小Vector 还可以设置增长的 空间大小而 ArrayList 没有提供设置增长空间的方法。 总结即 Vector 增长原来的一倍ArrayList 增加原来的 0.5 倍。 2. 说说 ArrayList,Vector, LinkedList 的存储性能和特性。 ArrayList 和 Vector 都是使用数组方式存储数据此数组元素数大于实际存储的数 据以便增加和插入元素它们都允许直接按序号索引元素但是插入元素要涉及数组 元素移动等内存操作所以索引数据快而插入数据慢Vector 由于使用了 synchronized 方法线程安全。 通常性能上较 ArrayList 差而 LinkedList 使用双向链表实现存储按序号索引数 据需要进行前向或后向遍历但是插入数据时只需要记录本项的前后项即可所以插 入速度较快 。 ArrayList 在查找时速度快LinkedList 在插入与删除时更具优势。 3. 快速失败 (fail-fast) 和安全失败 (fail-safe) 的区别是什么 Iterator 的安全失败是基于对底层集合做拷贝因此它不受源集合上修改的影响。 java.util 包下面的所有的集合类都是快速失败的而 java.util.concurrent 包下面的 所有的类都是安全失败的。快速失败的迭代器会抛出 ConcurrentModificationException 异常而安全失败的迭代器永远不会抛出这样的 异常。 4. hashmap 的数据结构。 在 java 编程语言中最基本的结构就是两种一个是数组另外一个是模拟指针 引用所有的数据结构都可以用这两个基本结构来构造的hashmap 也不例 外。Hashmap 实际上是一个数组和链表的结合体在数据结构中一般称之为 “链 表散列 “ 5. HashMap 的工作原理是什么? Java 中的 HashMap 是以键值对 (key-value) 的形式存储元素的。HashMap 需要 一个 hash 函数它使用 hashCode()和 equals()方法来向集合 / 从集合添加和检 索元素。当调用 put() 方法的时候HashMap 会计算 key 的 hash 值然后把键 值对存储在集合中合适的索引上。 如果 key 已经存在了value 会被更新成新值。 HashMap 的一些重要的特性是它的容量 (capacity)负载因子 (load factor) 和扩 容极限(threshold resizing)。 6. Hashmap 什么时候进行扩容呢 当 hashmap 中的元素个数超过数组大小 loadFactor 时就会进行数组扩容 loadFactor 的默认值为 0.75也就是说默认情况下数组大小为 16那么当 hashmap 中元素个数超过 16 0.7512 的时候就把数组的大小扩展为 2 1632 即扩大一倍然后重新计算每个元素在数组中的位置而这是一个非常消耗性能的操 作所以如果我们已经预知 hashmap 中元素的个数那么预设元素的个数能够有效 的提高 hashmap 的性能。比如说我们有 1000 个元素 new HashMap(1000), 但是理论上来讲 new HashMap(1024) 更合适不过上面 annegu 已经说过即使 是 1000hashmap 也自动会将其设置为 1024。 但是 new HashMap(1024) 还 不是更合适的因为 0.75*1000 1000, 也就是说为了让 0.75 * size 1000, 我们 必须这样 new HashMap(2048) 才最合适既考虑了 的问题也避免了 resize 的问题。 7. List、Map、Set 三个接口存取元素时各有什么特点 这样的题属于随意发挥题这样的题比较考水平两个方面的水平一是要真正明白 这些内容二是要有较强的总结和表述能力。如果你明白但表述不清楚在别人那 里则等同于不明白。 首先List 与 Set 具有相似性它们都是单列元素的集合所以它们有一个功共同 的父接口叫 Collection。Set 里面不允许有重复的元素所谓重复即不能有两个 相等注意不是仅仅是相同的对象 即假设 Set 集合中有了一个 A 对象现在 我要向 Set 集合再存入一个 B 对象但 B 对象与 A 对象 equals 相等则 B 对 象存储不进去所以Set 集合的 add 方法有一个 boolean 的返回值当集合中 没有某个元素此时 add 方法可成功加入该元素时则返回 true当集合含有与某 个元素 equals 相等的元素时此时 add 方法无法加入该元素返回结果为 false。 Set 取元素时没法说取第几个只能以 Iterator 接口取得所有的元素再逐一遍历 各个元素。 List 表示有先后顺序的集合 注意不是那种按年龄、按大小、按价格之类的排序。 当我们多次调用 add(Obj e) 方法时每次加入的对象就像火车站买票有排队顺序一 样按先来后到的顺序排序。有时候也可以插队即调用 add(int index,Obj e) 方 法就可以指定当前对象在集合中的存放位置。一个对象可以被反复存储进 List 中 每调用一次 add 方法这个对象就被插入进集合中一次其实并不是把这个对象 本身存储进了集合中而是在集合中用一个索引变量指向这个对象当这个对象被 add 多次时即相当于集合中有多个索引指向了这个对象如图 x 所示。List 除了 可以以 Iterator 接口取得所有的元素再逐一遍历各个元素之外还可以调用 get(index i) 来明确说明取第几个。 Map 与 List 和 Set 不同它是双列的集合其中有 put 方法定义如下 put(obj key,obj value)每次存储时要存储一对 key/value不能存储重复的 key这个重复的规则也是按 equals 比较相等。取则可以根据 key 获得相应的 value即 get(Object key) 返回值为 key 所对应的 value。另外也可以获得所有 的 key 的结合还可以获得所有的 value 的结合还可以获得 key 和 value 组合 成的 Map.Entry 对象的集合。 List 以特定次序来持有元素可有重复元素。Set 无法拥有重复元素, 内部排序。 Map 保存 key-value 值value 可多值。 HashSet 按照 hashcode 值的某种运算方式进行存储而不是直接按 hashCode 值的大小进行存储。例如abc --- 78def --- 62xyz --- 65 在 hashSet 中的存储顺序不是 62,65,78这些问题感谢以前一个叫崔健的学员提出 最后通过查看源代码给他解释清楚看本次培训学员当中有多少能看懂源码。 LinkedHashSet 按插入的顺序存储那被存储对象的 hashcode 方法还有什么作用 呢学员想想! hashset 集合比较两个对象是否相等首先看 hashcode 方法是否相 等然后看 equals 方法是否相等。new 两个 Student 插入到 HashSet 中看 HashSet 的 size实现 hashcode 和 equals 方法后再看 size。 同一个对象可以在 Vector 中加入多次。往集合里面加元素相当于集合里用一根绳 子连接到了目标对象。往 HashSet 中却加不了多次的。 8. Set 里的元素是不能重复的那么用什么方法来区分重复与否呢? 是用 还是 equals()? 它们有何区别? Set 里的元素是不能重复的元素重复与否是使用 equals() 方法进行判断的。 equals() 和 方法决定引用值是否指向同一对象 equals() 在类中被覆盖为的是 当两个分离的对象的内容和类型相配的话返回真值。 9. 两个对象值相同 (x.equals(y) true)但却可有不同的 hash code这句话对不对? 对。如果对象要保存在 HashSet 或 HashMap 中它们的 equals 相等那么它 们的 hashcode 值就必须相等。 如果不是要保存在 HashSet 或 HashMap则与 hashcode 没有什么关系了这时 候 hashcode 不等是可以的例如 arrayList 存储的对象就不用实现 hashcode当 然我们没有理由不实现通常都会去实现的。 10. heap 和 stack 有什么区别。 Java 的内存分为两类一类是 栈内存 一类是 堆内存 。栈内存是指程序进入一个方法 时会为这个方法单独分配一块私属存储空间用于存储这个方法内部的局部变量 当这个方法结束时分配给这个方法的栈会释放这个栈中的变量也将随之释放。 堆是与栈作用不同的内存一般用于存放不放在当前方法栈中的那些数据例如使 用 new 创建的对象都放在堆里所以它不会随方法的结束而消失。方法中的局部 变量使用 final 修饰后放在堆中而不是栈中。 11. Java 集合类框架的基本接口有哪些 集合类接口指定了一组叫做元素的对象。集合类接口的每一种具体的实现类都可以选 择以它 自己的方式对元素进行保存和排序。有的集合类允许重复的键有些不允许。 Java 集合类提供了一套设计良好的支持对一组对象进行操作的接口和类。Java 集合 类里面 最基本的接口有 Collection 代表一组对象每一个对象都是它的子元素。 Set 不包含重复元素的 Collection。 List 有顺序的 collection并且可以包含重复元素。 Map 可以把键 (key) 映射到值 (value) 的对象键不能重复。 12. HashSet 和 TreeSet 有什么区别 HashSet 是由一个 hash 表来实现的因此它的元素是无序的。add() remove()contains() TreeSet 是由一个树形的结构来实现的它里面的元素是有序的。因此add() remove()contains() 方法的时间复杂度是 O(logn)。 13. HashSet 的底层实现是什么? 通过看源码知道 HashSet 的实现是依赖于 HashMap 的HashSet 的值都是存储 在 HashMap 中的。在 HashSet 的构造法中会初始化一个 HashMap 对象 HashSet 不允许值重复因此HashSet 的值是作为 HashMap 的 key 存储在 HashMap 中的当存储的值已经存在时返回 false。 14. LinkedHashMap 的实现原理? LinkedHashMap 也是基于 HashMap 实现的不同的是它定义了一个 Entry header这个 header 不是放在 Table 里它是额外独立出来的。 LinkedHashMap 通过继承 hashMap 中的 Entry, 并添加两个属性 Entry before,after, 和 header 结合起来组成一个双向链表来实现按插入顺序或访问顺序 排序。LinkedHashMap 定义了排序模式 accessOrder该属性为 boolean 型变 量对于访问顺序为 true对于插入顺序则为 false。一般情况下不必指定排 序模式其迭代顺序即为默认为插入顺序。 15. 为什么集合类没有实现 Cloneable 和 Serializable 接口 克隆 (cloning) 或者是序列化 (serialization) 的语义和含义是跟具体的实现相关的。 因此应该 由集合类的具体实现来决定如何被克隆或者是序列化。 16. 什么是迭代器 (Iterator) Iterator 接口提供了很多对集合元素进行迭代的方法。每一个集合类都包含了可以返 回迭代 器实例的迭代方法。迭代器可以在迭代的过程中删除底层集合的元素, 但是不 可以直接调用集合的 remove(Object Obj) 删除可以通过迭代器的 remove() 方法 删除。 17. Iterator 和 ListIterator 的区别是什么 下面列出了他们的区别 Iterator 可用来遍历 Set 和 List 集合但是 ListIterator 只能用来遍历 List。 Iterator 对集合只能是前向遍历ListIterator 既可以前向也可以后向。 ListIterator 实现了 Iterator 接口并包含其他的功能比如增加元素替换元 素获取前一个和后一个元素的索引等等。 18. 数组 (Array) 和列表 (ArrayList) 有什么区别什么时候应该使用 Array 而不是 ArrayList Array 可以包含基本类型和对象类型ArrayList 只能包含对象类型。 Array 大小是固定的ArrayList 的大小是动态变化的。 ArrayList 处理固定大小的基本数据类型的时候这种方式相对比较慢。 19. Java 集合类框架的最佳实践有哪些  假如元素的大小是固 定的而且能事先知道我们就应该用 Array 而不是 ArrayList。  有些集合类允许指定初始容量。因此如果我们能估计出存储的元素的数目 我们可以设置 初始容量来避免重新计算 hash 值或者是扩容。  为了类型安全可读性和健壮性的原因总是要使用泛型。同时使用泛型还可 以避免运行时的 ClassCastException。  使用 JDK 提供的不变类 (immutable class) 作为 Map 的键可以避免为我们 自己的类实现 hashCode()和 equals()方法。  编程的时候接口优于实现。  底层的集合实际上是空的情况下返回长度是 0 的集合或者是数组不要返 回 null。 20. Set 里的元素是不能重复的那么用什么方法来区分重复与否呢是用 还是 equals()它们有何区别 Set 里的元素是不能重复的那么用 iterator() 方法来区分重复与否。equals() 是判 读两个 Set 是否相等 equals() 和 方法决定引用值是否指向同一对象 equals() 在类中被覆盖为的是 当两个分离的对象的内容和类型相配的话返回真值 21. Comparable 和 Comparator 接口是干什么的列出它们的区别。 Java 提供了只包含一个 compareTo() 方法的 Comparable 接口。这个方法可以个 给两个对象排序。具体来说它返回负数0正数来表明输入对象小于等于大于 已经存在的对象。 Java 提供了包含 compare() 和 equals() 两个方法的 Comparator 接口。 compare() 方法用来给两个输入参数排序返回负数0正数表明第一个参数是小 于等于大于第二个参数。equals() 方法需要一个对象作为参数它用来决定输入 参数是否和 comparator 相等。只有当输入参数也是一个 comparator 并且输入参 数和当前 comparator 的排序结果是相同的时 候这个方法才返回 true。 22. Collection 和 Collections 的区别。 collection 是集合类的上级接口, 继承与它的接口主要是 set 和 list。 collections 类是针对集合类的一个帮助类. 它提供一系列的静态方法对各种集合的搜 索, 排序, 线程安全化等操作。 七、反射讲一讲主要是概念,都在哪需要反射机制 反射机制的定义是在运行状态中对于任意的一个类都能够知道这个类的所有属性和方法对任意一个对象都能够通过反射机制调用一个类的任意方法这种动态获取类信息及动态调用类对象方法的功能称为java的反射机制。 反射的作用 1、动态地创建类的实例将类绑定到现有的对象中或从现有的对象中获取类型。 2、应用程序需要在运行时从某个特定的程序集中载入一个特定的类 八、继承是什么多态是什么 继承是使用已存在的类的定义作为基础建立新类的技术新类的定义可以增加新的数据或新的功能也可以用父类的功能但不能选择性地继承父类。通过使用继承我们能够非常方便地复用以前的代码能够大大的提高开发的效率。 继承的特点   1、子类拥有父类非private的属性和方法 2、子类可以拥有自己属性和方法即子类可以对父类进行扩展 3、子类可以用自己的方式实现父类的方法方法重写    4、构造函数不能被继承    5、继承使用extends关键字实现 多态的定义指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。发送消息就是函数调用 实现多态的技术称为动态绑定dynamic binding是指在执行期间判断所引用对象的实际类型根据其实际的类型调用其相应的方法。 多态的作用消除类型之间的耦合关系。 现实中关于多态的例子不胜枚举。比方说按下 F1 键这个动作如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档如果当前在 Word 下弹出的就是 Word 帮助在 Windows 下弹出的就是 Windows 帮助和支持。同一个事件发生在不同的对象上会产生不同的结果。 多态存在的三个必要条件 1要有继承或实现即父类引用变量指向了子类的对象或父类引用接受自己的子类对象 2要有重写 3父类引用指向子类对象。 多态弊端 提高扩展性但是只能使用父类引用指向父类成员。 注意   在多态的情况下字符类存在同名的成员成员变量和成员函数时访问的是父类的成员只有是同名的非静态成员函数时才访问子类的成员函数   多态用于形参类型时可以接受多个类型的数据   多态用于返回类型时可以返回多个类型的数据使用了多态的方法定义的变量类型要与返回的类型一致。 九、接口的幂等性问题 幂等的意思是重复操作,接口的幂等性也就是接口被重复调用了,在前端不进行限制的情况下,同一个接口可能重复调用多次,为了避免类似重复下单的问题,可以通过以下几种方式来解决幂等性问题: A.全局唯一ID,根据业务操作和内容生成全局唯一的ID,然后在执行操作前先判断是否已经存在该ID,如果不存在则将该ID进行持久化(存在数据库或者redis中),如果已经存在则证明该接口已经被调用过了.比如下单时可以生产一个流水号来作为该订单的唯一标识. B.可以使用selectinsert来进行判断,因为一般订单的ID都是唯一索引,在高并发场景下不推荐. C.可以使用乐观锁解决,在表中可以添加一个version字段. D.token机制,将token放在redis中. 十、JWT原理 JWT组成 headerpayloadsignature 三者通过点【.】连接起来就是JWT了 aheader头部包含token类型和采用的加密算法  {alg:HS256, typ:JWT} bpayload负载存放信息的地方可以把用户ID等信息存放在payload中。   常用的信息有iss(签发者), exp(过期时间), sub(面向用户), aud(接收方), iat(签发时间)等。 csignature签名使用编码后base64编码的header和payload再加上我们提供的一个公钥然后使用header中指定的签名算法进行签名。作用是保证JWT没有被窜改过。 JWT只适合向web端传递一些非敏感信息因为base64编码是可逆的很容易被破解 JWT的使用过程 1前端通过表单将用户名和密码发送到后端接口。   2后端核对用户名和密码后将用户的id及其他非敏感信息作为JWT Payload将其与头部分别进行base64编码后签名生成JWT     具体源代码见rest_framework_jwt下面的serializer中有兴趣研究的可以去跟踪看看 添加图片注释不超过 140 字可选   3后端将JWT字符串作为登录成功的结果返回给前端前端可以将JWT存到localStorage或者sessionStorage中退出登录时前端删除保存的JWT信息即可。   4前端每次在请求时将JWT放到header中的Authorization   5后端验证JWT的有效性   6验证通过后进行其他逻辑操作 十一、锁 悲观锁、乐观锁 悲观锁:悲观的认为所有的线程都会导致数据错误每一个线程都需要排队等待。优点数据一致性缺点效率低 Synchronized、Lock 二乐观锁AtomicInteger、CAS算法 Synchronized底层实现原理 同步方法通过ACC_SYNCHRONIZED 关键字隐式的对方法进行加锁。当线程要执行的方法被标注上ACC_SYNCHRONIZED时需要先获得锁才能执行该方法。 同步代码块通过monitorenter和monitorexit执行来进行加锁。当线程执行到monitorenter的时候要先获得锁才能执行后面的方法。当线程执行到monitorexit的时候则要释放锁。每个对象自身维护着一个被加锁次数的计数器当计数器不为0时只有获得锁的线程才能再次获得锁。 锁膨胀/锁升级 添加图片注释不超过 140 字可选 偏向锁 - markword 上记录当前线程指针下次同一个线程加锁的时候不需要争用只需要判断线程指针是否同一个所以偏向锁偏向加锁的第一个线程 。hashCode备份在线程栈上 线程销毁锁降级为无锁 轻量级锁 - 多个线程竞争的时候锁升级为轻量级锁 - 每个线程有自己的LockRecord在自己的线程栈上用CAS去争用markword的LR的指针指针指向哪个线程的LR哪个线程就拥有锁 重量级锁 自旋超过10次升级为重量级锁 - 如果太多线程自旋 CPU消耗过大不如升级为重量级锁进入等待队列不消耗CPU-XX:PreBlockSpin synchronized 关键字 synchronized关键字可以保证被它修饰的方法或者代码块在任意时刻只能有一个线程执行。 synchronized关键字最主要的三种使用方式修饰实例方法:、修饰静态方法、修饰代码块。 对于普通同步方法锁是当前实例对象。 对于静态同步方法锁是当前类的Class对象。 对于同步代码块锁是synchronized括号里配置的对象。 当一个线程试图访问同步代码块时它首先必须得到锁退出或抛出异常时必须释放锁 Lock对比synchronized的优势 能够显示地获取和释放锁锁的运用更灵活 可以方便地实现公平锁 能够响应中断非阻塞获取锁 synchronized和 Lock 的区别 1类型不同Lock是一个接口而synchronized是Java中的关键字synchronized是内置的语言实现 2异常处理方式不同synchronized在发生异常时会自动释放线程占有的锁因此不会导致死锁现象发生而Lock在发生异常时如果没有主动通过unLock()去释放锁则很可能造成死锁现象因此使用Lock时需要在finally块中释放锁 3等待方式不同Lock可以让等待锁的线程响应中断而synchronized却不行使用synchronized时等待的线程会一直等待下去不能够响应中断 4判断方式不同通过Lock可以知道有没有成功获取锁tryLock()方法如果获取锁成功则返回true而synchronized却无法办到。 5效率不同Lock可以提高多个线程进行读操作的效率。 在性能上来说如果竞争资源不激烈两者的性能是差不多的而当竞争资源非常激烈时即有大量线程同时竞争此时Lock的性能要远远优于synchronized。所以说在具体使用时要根据适当情况选择 锁粗化 锁粗化的作用如果检测到同一个对象执行了连续的加锁和解锁的操作则会将这一系列操作合并成一个更大的锁从而提升程序的执行效率 添加图片注释不超过 140 字可选 自适应自旋锁 添加图片注释不超过 140 字可选 CAS是什么缺点和解决办法 cas是另一个无锁解决方案更准确的是采用乐观锁技术实现线程安全的问题。cas有三个操作数----内存对象V、预期原值A、新值B 预期值和原值比较 CAS缺点 自循环时间长开销大 解决方法破坏掉for死循环当超过一定时间或者一定次数时return退出。JDK8新增的LongAddr,和ConcurrentHashMap类似的方法。当多个线程竞争时将粒度变小将一个变量拆分为多个变量达到多个线程访问多个资源的效果最后再调用sum把它合起来 只能保证一个共享变量的原子操作 解决方法CAS操作是针对一个变量的如果对多个变量操作 可以加锁来解决。 封装成对象类解决。 3、ABA问题 解决方法CAS还是类似于乐观锁同数据乐观锁的方式给它加一个版本号或者时间戳如AtomicStampedReference 锁性能优化的几种思路 减少线程持有锁的时间 可以把同步方法修改为同步代码块可以减少线程持有锁的时间 减少锁粒度锁分段技术、 将一个对象的数据分割成多个部分并为每个部分分配一把锁 操作互不影响锁分离技术 锁分离的应用就是 读写锁ReentranceReadWriteLock读读互不影响可以同时有多个线程读取数据 还有锁粗化和锁消除。 锁粗化就是把执行时间非常短的方法直接加入到同步方法中减少重新线程重新因为竞争同步锁带来的资源损耗。 锁消除就是消除掉 JDK 代码中自带的锁比如消除掉StringBuffer中的同步锁 十二、集合 HashMap 的工作原理 HashMap基于hashing原理我们通过put()和get()方法储存和获取对象。当我们将键值对传递给put()方法时它调用键对象的hashCode()方法来计算hashcode然后找到bucket位置来储存值对象。当获取对象时通过键对象的equals()方法找到正确的键值对然后返回值对象。HashMap使用链表来解决碰撞问题当发生碰撞了对象将会储存在链表的下一个节点中。 HashMap在每个链表节点中储存键值对对象 JDK1.7的时候是使用一个Entry数组来存储数据用key的hashcode取模来决定key会被放到数组里的位置如果hashcode相同或者hashcode取模后的结果相同hash collision那么这些key会被定位到Entry数组的同一个格子里这些key会形成一个链表。在hashcode特别差的情况下比方说所有key的hashcode都相同这个链表可能会很长那么put/get操作都可能需要遍历这个链表。也就是说时间复杂度在最差情况下会退化到O(n) 所以jdk8就引入了红黑树这个概念如果同一个格子里的key不超过8个使用链表结构存储。如果超过了8个那么会调用treeifyBin函数将链表转换为红黑树时间复杂度就只有 O(log n) 总结hashmap的初始容量是16在第一次put的时候进行的扩容初始化链表长度大于8时才会转换为红黑树红黑树长度小于6时会退化为链表扩容因子是0.75初始化扩容阈值为大于12。 hashmap为什么是二倍扩容 容量n为2的幂次方n-1的二进制会全为1位运算时可以充分散列避免不必要的哈希冲突。 HashMap 为什么线程不安全 主要是两方面, 第一如果多个线程同时使用put方法添加元素而且假设正好存在两个put的key发生了碰撞(hash值一样)那么根据HashMap的实现这两个key会添加到数组的同一个位置这样最终就会发生其中一个线程的put的数据被覆盖。 第二就是如果多个线程同时检测到元素个数超过数组大小*loadFactor这样就会发生多个线程同时对Node数组进行扩容都在重新计算元素位置以及复制数据但是最终只有一个线程扩容后的数组会赋给table也就是说其他线程的都会丢失并且各自线程put的数据也丢失 为什么ConcurrentHashMap是线程安全的 JDK1.7中ConcurrentHashMap使用的锁分段技术将数据分成一段一段的存储然后给每一段数据配一把锁当一个线程占用锁访问其中一个段数据的时候其他段的数据也能被其他线程访问 JDK1.8放弃了锁分段的做法采用CAS和synchronized方式处理并发。以put操作为例CAS方式确定key的数组下标synchronized保证链表节点的同步效果 好处减少内存开销 HashTable, HashMap,TreeMap的区别是什么 1、HashTable线程同步HashMap非线程同步。 2、HashTable不允许键,值有空值HashMap允许键,值有空值。 3、HashTable使用EnumerationHashMap使用Iterator。 4、HashTable中hash数组的默认大小是11增加方式的old*21HashMap中hash数组的默认大小是16增长方式一定是2的指数倍。 List、Set和Map的常见集合类型总结 添加图片注释不超过 140 字可选 LIST 有序、可以重复。 ArrayList 底层是数组查询快增删慢线程不安全效率高适合get和set方法 Vector 底层是数组查询快增删慢线程安全效率低 LinkedList 底层是双向循环链表查询慢增删快线程不安全效率高适合增加和删除方法。 SET 无序、不可重复。 HashSet:无序唯一底层是哈希表通过 hashCode和 equals保证元素唯一 LinkedHashSet有序唯一底层是链表和哈希表 链表保证元素的有序 哈希表证元素的唯一性 TreeSet有序唯一底层是红黑树排序通过自然排序和比较强排序。 ArrayList的自动扩容机制实现原理 ArrayList是一个数组结构的存储容器默认情况下数组长度是10个也可以在创建ArrayList对象的时候指定初始长度随着在程序里面不断往ArrayList里面添加数据超过十个的时候ArrayList中就没有足够的容量去存储后续的数据这时候ArrayList会触发自动扩容机制自动扩容机制流程是 首先创建一个新的数据这个数组的长度是原来数组长度的1.5倍 然后使用Arrays.copyOf方法把老数组里面的数据拷贝到新的数组里面 扩容完成以后再把当前需要添加的元素加入到新的数组里面从而完成动态扩容这样一个过程 ArrayList 为什么线程不安全 ArrayList 的 add 操作源码 elementData[size] e; ArrayList 的不安全主要体现在两个方面 其一 elementData[size] e;不是一个原子操作是分两步执行的 elementData[size] e; size; 单线程执行这段代码完全没问题可是到多线程环境下可能就有问题了。可能一个线程会覆盖另一个线程的值 其二 ArrayList 默认数组大小为 10。假设现在已经添加进去 9 个元素了size 9 但因为数组还没有扩容最大的下标才为 9所以会抛出数组越界异常 十三、Spring Spring 优点 1方便解耦便于开发Spring就是一个大工厂可以将所有对象的创建和依赖关系维护都交给spring管理 2.spring支持aop编程spring提供面向切面编程可以很方便的实现对程序进行权限拦截和运行监控等功能 3.声明式事务的支持通过配置就完成对事务的支持不需要手动编程 4.方便程序的测试spring 对junit4支持可以通过注解方便的测试spring 程序 5.方便集成各种优秀的框架 6.降低javaEE API的使用难度Spring 对javaEE开发中非常难用的一些API 例如JDBC,javaMail,远程调用等都提供了封装使这些API应用难度大大降低 Spring 事物的传播策略和隔离级别 七种传播行为和四种隔离级别 七种传播行为RSMRNNN REQUIRED(spring默认的) 如果当前存在事务则加入该事务如果当前没有事务则创建一个新的事务。 SUPPORTS 如果当前存在事务则加入该事务如果当前没有事务则以非事务的方式继续运行。 MANDATORY 如果当前存在事务则加入该事务如果当前没有事务则抛出异常。 REQUIRES_NEW 创建一个新的事务如果当前存在事务则把当前事务挂起。 NOT_SUPPORTED 以非事务方式运行如果当前存在事务则把当前事务挂起。 NEVER 以非事务方式运行如果当前存在事务则抛出异常。 NESTED 如果当前存在事务则创建一个事务作为当前事务的嵌套事务来运行如果当前没有事务则该取值等价于 REQUIRED 。 指定方法通过使用 propagation 属性设置例如Transactional(propagation Propagation.REQUIRED) 事务传播 - Propagation REQUIRED: 使用当前的事务如果当前没有事务则自己新建一个事务子方法是必须运行在一个事务中的 如果当前存在事务则加入这个事务成为一个整体。 举例领导没饭吃我有钱我会自己买了自己吃领导有的吃会分给你一起吃。 SUPPORTS: 如果当前有事务则使用事务如果当前没有事务则不使用事务。 举例领导没饭吃我也没饭吃领导有饭吃我也有饭吃。 MANDATORY: 该传播属性强制必须存在一个事务如果不存在则抛出异常 举例领导必须管饭不管饭没饭吃我就不乐意了就不干了抛出异常 REQUIRES_NEW: 如果当前有事务则挂起该事务并且自己创建一个新的事务给自己使用 如果当前没有事务则同 REQUIRED 举例领导有饭吃我偏不要我自己买了自己吃 NOT_SUPPORTED: 如果当前有事务则把事务挂起自己不适用事务去运行数据库操作 举例领导有饭吃分一点给你我太忙了放一边我不吃 NEVER: 如果当前有事务存在则抛出异常 举例领导有饭给你吃我不想吃我热爱工作我抛出异常 NESTED: 如果当前有事务则开启子事务嵌套事务嵌套事务是独立提交或者回滚 如果当前没有事务则同 REQUIRED。 但是如果主事务提交则会携带子事务一起提交。 如果主事务回滚则子事务会一起回滚。相反子事务异常则父事务可以回滚或不回滚。 举例领导决策不对老板怪罪领导带着小弟一同受罪。小弟出了差错领导可以推卸责任。 四种隔离级别 DEFAULT 默认值表示使用底层数据库的默认隔离级别。大部分数据库为READ_COMMITTED(MySql默认隔离级别为REPEATABLE_READ) READ_UNCOMMITTED 该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读和不可重复读因此很少使用该隔离级别。 READ_COMMITTED 该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读这也是大多数情况下的推荐值。 REPEATABLE_READ 该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询并且每次返回的记录都相同。即使在多次查询之间有新增的数据满足该查询这些新增的记录也会被忽略。该级别可以防止脏读和不可重复读。 SERIALIZABLE 所有的事务依次逐个执行这样事务之间就完全不可能产生干扰也就是说该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。 Transactional失效场景汇总 1.数据库引擎不支持事务 2.异常被catch没有抛出异常 导致Transactional失效 3.如果Transactional注解应用在非public 修饰的方法上Transactional将会失效。 同一个类中没有被Transactional注解的方法A调用注解了的方法B则改注解不生效 4.Transactional 注解属性 propagation 设置错误以下三种 propagation事务将不会发生回滚。 5.TransactionDefinition.PROPAGATION_SUPPORTS如果当前存在事务则加入该事务如果当前没有事务则以非事务的方式继续运行。 6.TransactionDefinition.PROPAGATION_NOT_SUPPORTED以非事务方式运行如果当前存在事务则把当前事务挂起。 7.TransactionDefinition.PROPAGATION_NEVER以非事务方式运行如果当前存在事务则抛出异常。 8.Transactional 注解属性 rollbackFor 设置错误 Spring默认在抛出了未检查unchecked异常继承自 RuntimeException 的异常或者 Error时才回滚事务其他异常不会触发回滚事务。如果在事务中抛出其他类型的异常但却期望 Spring 能够回滚事务就需要指定 rollbackFor属性。 Transactional原理 这个事务注解很简单。其实就是通过拦截器拦截注解然后加载注解参数根据隔离级别来判断是否需要创建事务 如果有多个事务隔离级别就会涉及到事务保存点 或者是不同事务之间还会涉及掉事务挂起 1事务开始时通过AOP机制生成一个代理connection对象并将其放入DataSource实例的某个与DataSourceTransactionManager相关的某处容器中。 在接下来的整个事务中客户代码都应该使用该connection连接数据库执行所有数据库命令[不使用该connection连接数据库执行的数据库命令在本事务回滚的时候得不到回滚]物理连接connection逻辑上新建一个会话sessionDataSource与TransactionManager配置相同的数据源 2事务结束时回滚在第1步骤中得到的代理connection对象上执行的数据库命令然后关闭该代理connection对象事务结束后回滚操作不会对已执行完毕的SQL操作命令起作用 IOC容器的原理 原理就是通过Java的反射技术来实现的通过反射(三种反射方式new对象、通过路径、通过类名)我们可以获取类的所有信息(成员变量、类名等等等) 再通过配置文件(xml)或者注解来描述类与类之间的关系 我们就可以通过这些配置信息和反射技术来构建出对应的对象和依赖关系了使用 IOC的好处: 不用自己组装拿来就用。 享受单例的好处效率高不浪费空间。 便于单元测试方便切换mock组件。 便于进行AOP操作对于使用者是透明的。 统一配置便于修改。 aop的实现原理 aop底层是采用动态代理机制实现的接口实现类 接口spring采用jdk的动态代理proxy 实现类spring采用cglib实现字节码增强 就是由代理创建出一个和impl实现类平级的一个对象但是这个对象不是一个真正的对象只是一个代理对象但它可以实现和impl相同的功能这个就是aop的横向机制原理这样就不需要修改源代码 SpringMVC 工作原理 1客户端发送请求到 DispatcherServlet 2DispatcherServlet 查询 handlerMapping 找到处理请求的 Controller 3Controller 调用业务逻辑后返回 ModelAndView 4DispatcherServlet 查询 ModelAndView找到指定视图 5视图将结果返回到客户端 SpringBOOT 工作原理 Spring Boot启动的时候会通过EnableAutoConfiguration注解找到META-INF/spring.factories配置文件中的所有自动配置类并对其进行加载而这些自动配置类都是以AutoConfiguration结尾来命名的它实际上就是一个JavaConfig形式的Spring容器配置类它能通过以Properties结尾命名的类中取得在全局配置文件中配置的属性如server.port而XxxxProperties类是通过ConfigurationProperties注解与全局配置文件中对应的属性进行绑定的 在spring程序main方法中 添加SpringBootApplication或者EnableAutoConfiguration 会自动去maven中读取每个starter中的spring.factories文件 该文件里配置了所有需要被创建spring容器中的bean autowired注解和resource注解区别 1.AutowiredSpring注解| ResourceJDK注解 (推荐使用Resource) 2.Autowired 通过zhi类型dao,zhuan动装配(byType 默认按shu照Bean中的daoClass类型) Resource 先通过参数名(byName 例如默认按照Bean中的id...)而后是类型 3.Autowired Qualifier(...) Resource(name...) 通常情况下,我们只会写一个实现类,所以建议使用autowire注解 简单方便 Spring中的设计模式 工厂设计模式 : Spring使用工厂模式通过 BeanFactory、ApplicationContext 创建 bean 对象。 代理设计模式 : Spring AOP 功能的实现。 单例设计模式 : Spring 中的 Bean 默认都是单例的。 模板方法模式 : Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库操作的类它们就使用到了模板模式。 包装器设计模式 : 我们的项目需要连接多个数据库而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。 观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用。 适配器模式 :Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller。 策略模式枚举 客户端创建一个Context对象a,创建策略对象并当做参数传递给a,然后客户端使用a方法通过某种方法得到想要的值返回给客户端。 工厂模式和策略模式的区别 一 它们的用途不一样。简单工厂模式是创建型模式它的作用是创建对象。策略模式是行为型模式作用是在许多行为中选择一种行为关注的是行为的多样性。 二 解决的问题不同。简单工厂模式是解决资源的统一分发将对象的创立同客户端分离开来。策略模式是为了解决策略的切换和扩展。 三 工厂相当于黑盒子策略相当于白盒子 简单工厂模式 又叫做静态工厂方法StaticFactory Method模式但不属于23种GOF设计模式之一。 简单工厂模式的实质是由一个工厂类根据传入的参数动态决定应该创建哪一个产品类。 spring中的BeanFactory就是简单工厂模式的体现根据传入一个唯一的标识来获得bean对象但是否是在传入参数后创建还是传入参数前创建这个要根据具体情况来定。如下配置就是在 HelloItxxz 类中创建一个 itxxzBean。 单例模式 保证一个类仅有一个实例并提供一个访问它的全局访问点。 spring中的单例模式完成了后半句话即提供了全局的访问点BeanFactory。但没有从构造器级别去控制单例这是因为spring管理的是是任意的java对象。 Spring下默认的bean均为singleton可以通过singleton“true|false” 或者 scope“”来指定 代理模式 在Spring的Aop中使用的Advice通知来增强被代理类的功能。Spring实现这一AOP功能的原理就使用代理模式1、JDK动态代理。2、CGLib字节码生成技术代理。对类进行方法级别的切面增强即生成被代理类的代理类 并在代理类的方法前设置拦截器通过执行拦截器重的内容增强了代理方法的功能实现的面向切面编程 策略模式 Spring中的策略模式使用多如牛毛所谓策略模式就是定义了算法族分别封装起来让他们之前可以互相转换此模式然该算法的变化独立于使用算法的客户。Spring的事务管理机制就是典型的策略模式Spring事务策略是通过PlatformTransactionManager接口实现的 SpringSecurityOauth原理 SpringSecurityOauth2包含了认证服务器EnableAuthorizationServer和资源服务器认证服务器EnableResourceServer是用来生成令牌token资源服务器是验证该请求是否存在令牌如果存在才能通过否则不通过 认证服务器有4中授权模式 1.用户名和密码模式 2.授权码模式 3.客户端模式 4.简化模式 原理 用户发起获取token的请求。 过滤器会验证path是否是认证的请求/oauth/token如果为false则直接返回没有后续操作。 过滤器通过clientId查询生成一个Authentication对象。 然后会通过username和生成的Authentication对象生成一个UserDetails对象并检查用户是否存在。 以上全部通过会进入地址/oauth/token即TokenEndpoint的postAccessToken方法中。 postAccessToken方法中会验证Scope然后验证是否是refreshToken请求等。 之后调用AbstractTokenGranter中的grant方法。 grant方法中调用AbstractUserDetailsAuthenticationProvider的authenticate方法通过username和Authentication对象来检索用户是否存在。 然后通过DefaultTokenServices类从tokenStore中获取OAuth2AccessToken对象。 然后将OAuth2AccessToken对象包装进响应流返回。 Spring上下文中的Bean生命周期 添加图片注释不超过 140 字可选 添加图片注释不超过 140 字可选 1、实例化一个Bean也就是我们常说的new 2、按照Spring上下文对实例化的Bean进行配置也就是IOC注入 3、如果这个Bean已经实现了BeanNameAware接口会调用它实现的setBeanName(String)方法此处传递的就是Spring配置文件中Bean的id值 4、如果这个Bean已经实现了BeanFactoryAware接口会调用它实现的setBeanFactory(setBeanFactory(BeanFactory)传递的是Spring工厂自身可以用这个方式来获取其它Bean只需在Spring配置文件中配置一个普通的Bean就可以 5、如果这个Bean已经实现了ApplicationContextAware接口会调用setApplicationContext(ApplicationContext)方法传入Spring上下文同样这个方式也可以实现步骤4的内容但比4更好因为ApplicationContext是BeanFactory的子接口有更多的实现方法 6、如果这个Bean关联了BeanPostProcessor接口将会调用postProcessBeforeInitialization(Object obj, String s)方法BeanPostProcessor经常被用作是Bean内容的更改并且由于这个是在Bean初始化结束时调用那个的方法也可以被应用于内存或缓存技术 7、如果Bean在Spring配置文件中配置了init-method属性会自动调用其配置的初始化方法。 8、如果这个Bean关联了BeanPostProcessor接口将会调用postProcessAfterInitialization(Object obj, String s)方法、 注以上工作完成以后就可以应用这个Bean了那这个Bean是一个Singleton的所以一般情况下我们调用同一个id的Bean会是在内容地址相同的实例当然在Spring配置文件中也可以配置非Singleton这里我们不做赘述。 9、当Bean不再需要时会经过清理阶段如果Bean实现了DisposableBean这个接口会调用那个其实现的destroy()方法 10、最后如果这个Bean的Spring配置中配置了destroy-method属性会自动调用其配置的销毁方法。 数据库 Sql语句优化 避免对索引字段进行计算操作 避免在索引字段上使用not! 避免在索引列上使用IS NULL和IS NOT NULL 避免在索引列上出现数据类型转换 避免在索引字段上使用函数 避免建立索引的列中使用空值 为什么官方建议使用自增长主键作为索引 结合BTree的特点自增主键是连续的在插入过程中尽量减少页分裂即使要进行页分裂也只会分裂很少一部分。并且能减少数据的移动每次插入都是插入到最后。总之就是减少分裂和移动的频率 说一说间隙锁 间隙锁锁的就是两个值之间的空隙。间隙锁是在可重复读隔离级别Repeatable Read下才会生效。在普通索引列上不管是何种查询只要加锁都会产生间隙锁这跟唯一索引不一样在普通索引和唯一索引中数据间隙的分析数据行是优先根据普通索引排序再根据唯一索引排序 ACID靠什么保证的 A原子性由undo log日志保证它记录了需要回滚的日志信息事务回滚时撤销已经执行成功的sql C一致性一般由代码层面来保证 I隔离性由MVCC来保证 D持久性由内存redo log来保证mysql修改数据同时在内存和redo log记录这次操作事务提交的时候通过redo log刷盘宕机的时候可以从redo log恢复 myisam和innodb两种存储引擎的不同之处 1、事务的支持不同innodb支持事务myisam不支持事务 2、锁粒度innodb行锁应用myisam表锁 3、存储空间innodb既缓存索引文件又缓存数据文件myisam只能缓存索引文件.bdl .myl,.myi 4、存储结构 myisam数据文件的扩展名为.MYD myData 索引文件的扩展名是.MYI myIndex innodb所有的表都保存在同一个数据文件里面 即为.Ibd 数据库自增ID用完了会怎么样 自增ID达到上限用完了之后分为两种情况 1如果设置了主键那么将会报错主键冲突。 2如果没有设置主键数据库则会帮我们自动生成一个全局的row_id新数据会覆盖老数据解决方案 表尽可能都要设置主键主键尽量使用bigint类型21亿的上限还是有可能达到的比如魔兽虽然说row_id上限高达281万亿但是覆盖数据显然是不可接受的 索引的分类 1、唯一索引:确保数据唯一性 2、非唯一索引:这些字段可以重复,不要求唯一. 3、主键索引:是唯一索引的特定类型,创建主键时自动创建. 4、聚簇索引: 表中记录的物理顺与键值顺序相同,表数据和主键一起存储. 5、非聚簇索引: 表数据和索引分两部分存储 主键和唯一索引的区别 1、主键一定会创建一个唯一索引但是有唯一索引的列不一定是主键 2、主键不允许为空值唯一索引列允许空值 3、一个表只能有一个主键但是可以有多个唯一索引 4、主键可以被其他表引用为外键唯一索引列不可以 5、主键是一种约束而唯一索引是一种索引是表的冗余数据结构两者有本质的差别 都在哪些字段加索引 1、表的主键、外键必须有索引 2、数据量超过300的表应该有索引 3、经常与其他表进行连接的表,在连接字段上应该建立索引 4、经常出现在Where子句中的字段,特别是大表的字段,应该建立索引 5、索引应该建在选择性高的字段上 怎么使用索引才能提高索引的命中 1、如果条件中有or,即使其中有条件带索引也不会使用(这也是为什么尽量少用or的原因) 注意:要想使用or,又想让索引生效,只能将or条件中的每个列都加上索引 2、如果是聚合索引根据最左前缀原则如果不用第一个字段则不会使用索引 3、如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引 4、如果mysql估计使用全表扫描要比使用索引快,则不使用索引 索引的最左前缀了解吗 索引index1:(a,b,c)有三个字段索引是有序的index1索引在索引文件中的排列是有序的首先根据a来排序然后才是根据b来排序最后是根据c来排序 索引是越多越好吗为什么 1、合理的建立索引能够加速数据读取效率不合理的建立索引会拖慢数据库的响应速度。 2、索引越多更新数据的速度越慢。 不要在选择的栏位上放置索引这是无意义的。应该在条件选择的语句上合理的放置索引比如whereorder by。 例子 SELECT id,title,content,cat_id FROM article WHERE cat_id 1; 上面这个语句你在id/title/content上放置索引是毫无意义的对这个语句没有任何优化作用。但是如果你在外键cat_id上放置一个索引那作用就相当大了 为什么索引 结构默认使用B-Tree而不是hash二叉树红黑树 hash虽然可以快速定位但是没有顺序IO复杂度高。 二叉树树的高度不均匀不能自平衡查找效率跟数据有关(树的高度)并且IO代价高。 红黑树树的高度随着数据量增加而增加IO代价高 B-Tree索引B-Tree能加快数据的访问速度因为存储引擎不再需要进行全表扫描来获取数据数据分布在各个节点之中 BTree索引B -Tree的改进版本同时也是数据库索引索引所采用的存储结构。数据都在叶子节点上并且增加了顺序访问指针每个叶子节点都指向相邻的叶子节点的地址。相比B-Tree来说进行范围查找时只需要查找两个节点进行遍历即可。而B-Tree需要获取所有节点相比之下BTree效率更高 为什么MySQL的索引要使用B树而不是其它树形结构?比如B树 因为B树不管叶子节点还是非叶子节点都会保存数据这样导致在非叶子节点中能保存的指针数量变少有些资料也称为扇出 指针少的情况下要保存大量数据只能增加树的高度导致IO操作变多查询性能变低 B树的数据都存储在叶子节点 B树能显著减少IO次数提高效率 B树的查询效率更加稳定因为数据放在叶子节点 B树能提高范围查询的效率因为叶子节点指向下一个叶子节点 使用B-Tree和BTree各自的好处 使用B-Tree的好处 B树可以再内部节点存储键值和相关记录数据因此把频繁访问的数据放在靠近根节点的位置将大大提高热点数据的查询效率。B树一般在特定数据重复多次查询的场景中更加高效 使用BTree的好处 B树内部节点不存储数据只存储键值这样每个节点就能存储更多的键值一次性也就能将更多的键值读入内存减少了对磁盘的IO操作次数且B树的叶节点有一条链相连所以对于区间内查询数据比较高效 为什么索引结构默认使用B树而不是B-TreeHash哈希二叉树红黑树 简单版回答如下 Hash哈希只适合等值查询不适合范围查询。 一般二叉树可能会特殊化为一个链表相当于全表扫描。 红黑树是一种特化的平衡二叉树MySQL 数据量很大的时候索引的体积也会很大内存放不下的而从磁盘读取树的层次太高的话读取磁盘的次数就多了。 B-Tree叶子节点和非叶子节点都保存数据相同的数据量B树更矮壮也是就说相同的数据量B树数据结构查询磁盘的次数会更少。 B-树和B树的区别 B-树内部节点是保存数据的;而B树内部节点是不保存数据的只作索引作用它的叶子节点才保存数据。 B树相邻的叶子节点之间是通过链表指针连起来的B-树却不是。 查找过程中B-树在找到具体的数值以后就结束而B树则需要通过索引找到叶子结点中的数据才结束 B-树中任何一个关键字出现且只出现在一个结点中而B树可以出现多次。 索引的底层数据结构知道吗 B±Tree定义 其定义基本与B-Tree相同 除了 非叶子节点仅用来做索引数据都保存在叶子节点中。 所有叶子节点均有一个链指针指向下一个叶子节点 3、非叶子节点的子树指针与关键字个数相同。 非叶子节点的子树指针p[i]指向关键字值K[i]K[i1]的子树。 MSQL锁 间隙锁 间隙锁Gap Lock锁加在不存在的空闲空间可以是两个索引记录之间也可能是第一个索引记录之前或最后一个索引之后的空间 中心思想 间隙锁锁的是索引叶子结点的next指针 解决的问题 解决了mysql RR REPEATABLE_READ可重复读级别下是幻读的问题 四种隔离级别 产生间隙锁的条件 使用普通索引锁定 使用多列唯一索引 使用唯一索引锁定多行记录。 打开间隙锁设置 innodb_locks_unsafe_for_binlog默认值为OFF即启用间隙锁 行锁升级表锁 行锁是建立在索引的基础上。 普通索引的数据重复率过高导致索引失效行锁升级为表锁 多线程 线程和进程区别 线程是进程的子集一个进程可以有很多线程每条线程并行执行不同的任务。 不同的进程使用不同的内存空间而线程共享同一进程的内存空间。别把它和栈内存搞混每个线程都拥有单独的栈内存用来存储本地数据。 线程作为操作系统能够进行运算调度的最小单位进程作为资源分配的最小单位。 线程更轻量线程上下文切换成本一般上要比进程上下文切换低 创建线程的几种方式 有4种方式继承Thread类、实现Runnable接口、实现Callable接口、使用Executor框架来创建线程池 sleep() 方法和 wait() 方法区别和共同点 sleep()方法没有释放锁而 wait()方法释放了锁。 sleep()方法属于Thread类的静态方法作用于当前线程而wait()方法是Object类的实例方法作用于对象本身。 执行sleep()方法后可以通过超时或者调用interrupt()方法唤醒休眠中的线程执行wait()方法后通过调用notify()或notifyAll()方法唤醒等待线程 start()和run()的区别 start() 可以启动一个新线程run() 不能 start() 不能被重复调用run() 可以 start() 中的 run 代码可以不执行完就继续执行下面的代码进行线程切换而调用 run() 方法必须等待其代码全部执行完才能继续执行下面的代码 start() 实现了多线程run() 没有 线程池参数 ①corePoolSize线程池的基本大小当提交一个任务到线程池时线程池会创建一个线程来执行任务即使其他空闲的基本线程能够执行新任务也会创建线程等到需要执行的任务数大于线程池基本大小时就不再创建。说白了就是即便是线程池里没有任何任务也会有corePoolSize个线程在候着等任务。 ②maximumPoolSize:最大线程数不管你提交多少任务线程池里最多工作线程数就是maximumPoolSize。 ③keepAliveTime:线程的存活时间。当线程池里的线程数大于corePoolSize时如果等了keepAliveTime时长还没有任务可执行则线程退出。 ⑤unit这个用来指定keepAliveTime的单位比如秒:TimeUnit.SECONDS。 ⑥workQueue用于保存等待执行任务的阻塞队列提交的任务将会被放到这个队列里。 ⑦threadFactory线程工厂用来创建线程。主要是为了给线程起名字默认工厂的线程名字pool-1-thread-3。 ⑧handler拒绝策略即当线程和队列都已经满了的时候应该采取什么样的策略来处理新提交的任务。默认策略是AbortPolicy抛出异常其他的策略还有CallerRunsPolicy(只用调用者所在线程来运行任务)、DiscardOldestPolicy(丢弃队列里最近的一个任务并执行当前任务)、DiscardPolicy(不处理丢弃掉) 线程池执行流程 添加图片注释不超过 140 字可选 如何保证多个线程按一定顺序执行 添加图片注释不超过 140 字可选 需要依赖线程的执行结果可以在这里调用join方法等待线程执行结束,用join来保证线程的顺序性的 Threadlocal内存泄漏原因 首先是因为 ThreadLocal 是基于 ThreadLocalMap 实现的其中 ThreadLocalMap 的 Entry 继承了 WeakReference 而 Entry 对象中的 key 使用了 WeakReference 封装也就是说 Entry 中的 key 是一个弱引用类型对于弱引用来说它只能存活到下次 GC 之前 ;如果此时一个线程调用了 ThreadLocalMap 的 set 设置变量当前的 ThreadLocalMap 就会新增一条记录但由于发生了一次垃圾回收这样就会造成一个结果: key 值被回收掉了但是 value 值还在内存中而且如果线程一直存在的话那么它的 value 值就会一直存在 Redis 内存淘汰机制 redis 内存淘汰机制有以下几个 • noeviction: 当内存不足以容纳新写入数据时新写入操作会报错这个一般没人用吧实在是太恶心了。 • allkeys-lru当内存不足以容纳新写入数据时在键空间中移除最近最少使用的 key这个是最常用的。 • allkeys-random当内存不足以容纳新写入数据时在键空间中随机移除某个 key这个一般没人用吧为啥要随机肯定是把最近最少使用的 key 给干掉啊。 • volatile-lru当内存不足以容纳新写入数据时在设置了过期时间的键空间中移除最近最少使用的 key这个一般不太合适。 • volatile-random当内存不足以容纳新写入数据时在设置了过期时间的键空间中随机移除某个 key。 • volatile-ttl当内存不足以容纳新写入数据时在设置了过期时间的键空间中有更早过期时间的 key 优先移除 一个不做处理 直接报异常 两个从redis内存中删除 1 移除最少使用的 2 一个是随机移除 三个从redis内存中快要过期的兼空间里移除 1移除最少使用 2 随机移除 3移除快要过期的 Lfu 根据次数清理 如何保证redis中数据都是热点数据 限定 Redis 占用的内存Redis 会根据自身数据淘汰策略留下热数据到内存。所以计算一下 50W 数据大约占用的内存然后设置一下 Redis 内存限制即可并将淘汰策略为volatile-lru或者allkeys-lru redis集群方式 主从复制、哨兵模式、集群 缓存穿透、缓存击穿、缓存雪崩解决方案 缓存穿透指查询一个一定不存在的数据如果从存储层查不到数据则不写入缓存这将 导致这个不存在的数据每次请求都要到 DB 去查询可能导致 DB 挂掉。 解决方案1.查询返回的数据为空仍把这个空结果进行缓存但过期时间会比较短2.布 隆过滤器将所有可能存在的数据哈希到一个足够大的 bitmap 中一个一定不存在的数据 会被这个 bitmap 拦截掉从而避免了对 DB 的查询。 缓存击穿对于设置了过期时间的 key缓存在某个时间点过期的时候恰好这时间点对 这个 Key 有大量的并发请求过来这些请求发现缓存过期一般都会从后端 DB 加载数据并 回设到缓存这个时候大并发的请求可能会瞬间把 DB 压垮。解决方案1.使用互斥锁当缓存失效时不立即去 load db先使用如 Redis 的 setnx 去设 置一个互斥锁当操作成功返回时再进行 load db 的操作并回设缓存否则重试 get 缓存的 方法。2.永远不过期物理不过期但逻辑过期后台异步线程去刷新。 缓存雪崩设置缓存时采用了相同的过期时间导致缓存在某一时刻同时失效请求全部 转发到 DBDB 瞬时压力过重雪崩。与缓存击穿的区别雪崩是很多 key击穿是某一个 key 缓存。 解决方案将缓存失效时间分散开比如可以在原有的失效时间基础上增加一个随机值 比如 1-5 分钟随机这样每一个缓存的过期时间的重复率就会降低就很难引发集体失效 的事件 讲一下redis的事务 redis的事务先以MULTI开启事务,将多个命令入队到事务中,然后通过EXEC命令触发执行队伍中的所有命令,如果想取消事务可以执行discard命令 Redis的持久化有两种方式,AOF和RDB AOF:以独立日志记录写命令方式存储日志,重启时再重新执行日志中记录的数据即可完成恢复.优势是数据安全,不容易丢数据,而且aof中的内容可以读懂,如果不小心敲了flushall命令,还可以将aof文件尾部的flushall命令删掉,然后就可以恢复数据了.缺点是占用存储空间大,数据恢复较慢. RDB:将内存中的数据以快照的方式写进二进制文件中.优势是数据恢复快,方便备份,缺点是比较耗内存,可能会造成数据丢失 Redis6.0多线程 流程简述如下 1、主线程负责接收建立连接请求获取 socket 放入全局等待读处理队列 2、主线程处理完读事件之后通过 RR(Round Robin) 将这些连接分配给这些 IO 线程 3、主线程阻塞等待 IO 线程读取 socket 完毕 4、主线程通过单线程的方式执行请求命令请求数据读取并解析完成但并不执行 5、主线程阻塞等待 IO 线程将数据回写 socket 完毕 6、解除绑定清空等待队列 HTTP TCP三次握手 第一次握手建立连接时客户端发送syn包synj到服务器并进入SYN_SENT状态等待服务器确认SYN同步序列编号Synchronize Sequence Numbers。 第二次握手服务器收到syn包必须确认客户的SYNackj1同时自己也发送一个SYN包synk即SYNACK包此时服务器进入SYN_RECV状态 第三次握手客户端收到服务器的SYNACK包向服务器发送确认包ACK(ackk1此包发送完毕客户端和服务器进入ESTABLISHEDTCP连接成功状态完成三次握手 TCP四次挥手 第一次挥手客户端发送一个FIN报文报文中指定一个序列号seqx2此时客户端处于FIN_WAIT状态 第二次挥手服务端收到FIN,会发送一个ACK报文且把客户端的序列号值1(x3)作为ACK报文的序列号表明已经收到客户端的报文了此时客户端的处于CLOSE_WAIT状态 第三次挥手如果服务器也想断开连接和客户端第一次挥手一样发送FIN报文且指定一个序列号(seqy1)此时服务端处于LAST_ACK的状态 第四次挥手客户端收到FIN后一样发送一个ACK作为应答且把服务端的序列号值1(y2)作为自己ACK报文的序列号值此时客户端处于RIME_WAIT状态。需要过一阵子以确保服务端收到自己的ACK报文之后才会进入CLOSED状态 服务端收到ACK报文之后就处于关闭连接了处于CLOSED状态 TCP、UDP协议及两者的区别 两者区别 1 TCP提供面向连接的传输通信前要先建立连接三次握手机制 UDP提供无连接的传输通信前不需要建立连接。 2 TCP提供可靠的传输有序无差错不丢失不重复 UDP提供不可靠的传输。 3 TCP面向字节流的传输因此它能将信息分割成组并在接收端将其重组 UDP是面向数据报的传输没有分组开销。 4 TCP提供拥塞控制和流量控制机制 UDP不提供拥塞控制和流量控制机制。 HTTP与HTTPS有什么区别  1、https协议需要到ca申请证书一般免费证书较少因而需要一定费用。  2、http是超文本传输协议信息是明文传输https则是具有安全性的ssl加密传输协议。  3、http和https使用的是完全不同的连接方式用的端口也不一样前者是80后者是443。  4、http的连接很简单是无状态的HTTPS协议是由SSLHTTP协议构建的可进行加密传输、身份认证的网络协议比http协议安全。 Cloud微服务 微服务的优缺点 优点 1、服务拆分粒度更细有利于资源重复利用有利于提高开发效率 2、可以更精准的制定优化服务方案提高系统的可维护性 3、微服务架构采用去中心化思想服务之间采用Restful等轻量级通讯比ESB更轻量 4、适于互联网时代产品迭代周期更短 缺点 1、微服务过多治理成本高不利于维护系统 2、分布式系统开发的成本高容错分布式事务等对团队挑战大 总的来说优点大过于缺点目前看来SpringCloud是一套非常完善的分布式框架目前很多企业开始用微服务、Spring Cloud 的优势是显而易见的。因此对于想研究微服务架构的同学来说学习 Spring Cloud 是一个不错的选择。 Eureka工作原理 Eureka : 就是服务注册中心(可以是一个集群),对外暴露自己地址; 提供者 : 启动后向Eureka注册自己信息(地址,提供什么服务) 消费者 : 向Eureka 订阅服务,Eureka会将对应服务的服务列表发送给消费者,并且定期更新 心跳(续约): 提供者定期通过http方式向Eureka刷新自己的状态 config原理介绍 springCloudConfig分服务端和客户端服务端负责将本地git或者svn中存储的配置文件发布成REST风格的接口客户端可以从服务端REST接口获取配置。但客户端并不能主动感知到配置的变化从而主动去获取新的配置这需要每个客户端通过POST方法触发各自的/refresh接口。而我们上面说的SpringCloudBus就发挥了其作用了 SpringCloudBus通过一个轻量级消息代理连接分布式系统的节点有点像消息队列那种。这可以用于广播状态更改如配置更改或其他管理指令。SpringCloudBus提供了通过post方法访问的endpoint/bus/refreshspring boot 有很多监控的endpoint比如/health这个接口通常由git的钩子功能监听触发调用用以通知各个SpringCloudConfig的客户端去服务端更新配置。 Feign的工作原理 一 第一步 在开发微服务时会在主程序入口添加EnableFeignClients注解开启对Feign Client扫描加载处理。根据Feign Client的开发规范定义接口并加FeignClient注解。 二 第二步 当程序启动时会进行包扫描扫描所有FeignClient注解的类并将这些信息注入Spring IoC容器中。当定义的Feign接口中的方法并调用时通过JDK的代理方式来生成具体的RequestTemplate。当生成代理时Feign会为每个接口方法创建一个RequestTemplate对象该对象封装了HTTP请求需要的全部信息如请求参数名、请求方法等信息都在这个过程中确定。 三 第三步 然后又RequestTemplate生成Request然后把这个Request交给client处理这里指的Client可以是JDK原生的URLConnection、Apache的Http Client也可以是Okhttp。最后Client被封装到LoadBalanceClient类这个类结合Ribbon负载均衡发起服务之间的调用。 Feign远程调用核心就是通过一系列的封装和处理将以JAVA注解的方式定义的远程调用API接口基于重试器发送HTTP请求Feign 内置了一个重试器当HTTP请求出现IO异常时Feign会有一个最大尝试次数发送请求 Feign使用中遇到的相关问题 1使用feign客户端调用其他微服务时发送POST请求时对象信息没有传递成功。关键在于加上注解RequestBody 2使用feign客户端调用其他微服务时报错超时efeign.RetryableException: Read timed out executing POST ribbon.ReadTimeout60000 ribbon.ConnectTimeout60000 nacos服务注册与发现的原理 ali 我不用 服务注册与发现是是针对于三大角色的①服务提供者 ②服务消费者 ③注册中心 针对他们之间的关系描述就是服务的注册与发现的运行原理 1、各微服务在服务启动的时候服务提供者将服务的网络地址IP地址和端口服务名称服务自身状态以及访问协议等信息注册到注册中心注册中心存储该数据 2、服务消费者从注册中心查询到服务提供者的实例信息并通过该地址调用服务提供者的接口 3、各个微服务与注册中心通过一定的机制通信例如心跳检测机制如果注册中心与某微服务长时间无法通信就会注销该实例即该服务对应的实例会被注册中心剔除 4、微服务网络地址发生变化例如增加实例或IP变动等会重新注册到注册中心这样服务消费者就无需人工修改提供者的网络地址了 Nacos 宕机后仍然可以调用成功注册中心宕机不影响已运行的提供者和消费者消费者在本地缓存了提供者列表 Nacos的AP模型还是CP模型 Nacos支持CPAP模式即Nacos可以根据配置识别为CP模式或AP模式默认是AP模式。如果注册Nacos的client节点注册时ephemeraltrue那么Nacos集群对这个client节点的效果就是AP采用distro协议实现而注册Nacos的client节点注册时ephemeralfalse那么Nacos集群对这个节点的效果就是CP的采用raft协议实现。根据client注册时的属性APCP同时混合存在只是对不同的client节点效果不同。Nacos可以很好的解决不同场景的业务需求。 Nginx与Ribbon的区别 Nginx是反向代理同时可以实现负载均衡nginx拦截客户端请求采用负载均衡策略根据upstream配置进行转发相当于请求通过nginx服务器进行转发。Ribbon是客户端负载均衡从注册中心读取目标服务器信息然后客户端采用轮询策略对服务直接访问全程在客户端操作 Ribbon底层实现原理 Ribbon使用discoveryClient从注册中心读取目标服务信息对同一接口请求进行计数使用%取余算法获取目标服务集群索引返回获取到的目标服务信息 Ribbon负载均衡算法 RoundRobinRule 默认轮询的方式 RandomRule 随机方式 WeightedResponseTimeRule 根据响应时间来分配权重的方式响应的越快分配的值越大。 BestAvailableRule 选择并发量最小的方式 RetryRule 在一个配置时间段内当选择server不成功则一直尝试使用subRule的方式选择一个可用的server ZoneAvoidanceRule 根据性能和可用性来选择。 AvailabilityFilteringRule 过滤掉那些因为一直连接失败的被标记为circuit tripped的后端server并过滤掉那些高并发的的后端serveractive connections 超过配置的阈值 Dubbo dubbo工作原理 第一层service层接口层给服务提供者和消费者来实现的 第二层config层配置层主要是对dubbo进行各种配置的 第三层proxy层服务代理层透明生成客户端的stub和服务单的skeleton 第四层registry层服务注册层负责服务的注册与发现 第五层cluster层集群层封装多个服务提供者的路由以及负载均衡将多个实例组合成一个服务 第六层monitor层监控层对rpc接口的调用次数和调用时间进行监控 第七层protocol层远程调用层封装rpc调用 第八层exchange层信息交换层封装请求响应模式同步转异步 第九层transport层网络传输层抽象mina和netty为统一接口 第十层serialize层数据序列化层 工作流程 添加图片注释不超过 140 字可选 Provider(提供者)绑定指定端口并启动服务 指供者连接注册中心并发本机IP、端口、应用信息和提供服务信息发送至注册中心存储 Consumer(消费者连接注册中心 并发送应用信息、所求服务信息至注册中心 注册中心根据 消费 者所求服务信息匹配对应的提供者列表发送至Consumer 应用缓存。 Consumer 在发起远程调用时基于缓存的消费者列表择其一发起调用。 Provider 状态变更会实时通知注册中心、在由注册中心实时推送至Consumer 1第一步provider提供者向注册中心去注册 2第二步consumer消费者从注册中心订阅服务注册中心会通知consumer注册好的服务 3第三步consumer消费者调用provider提供者 4第四步consumer消费者和provider提供者都异步的通知监控中心 2注册中心挂了可以继续通信吗 可以因为刚开始初始化的时候消费者会将提供者的地址等信息拉取到本地缓存所以注册中心挂了可以继续通信 Dubbo有哪些负载均衡策略 一致性Hash均衡算法,轮询,随机调用,最少活动调用法. 分布式 Zookeeper的分布式锁原理 获取分布式锁的流程 在获取分布式锁的时候在locker节点(locker节点是Zookeeper的指定节点)下创建临时顺序节点释放锁的时候删除该临时节点。 客户端调用createNode方法在locker下创建临时顺序节点然后调用getChildren(“locker”)来获取locker下面的所有子节点注意此时不用设置任何Watcher。 客户端获取到所有的子节点path之后如果发现自己创建的子节点序号最小那么就认为该客户端获取到了锁。 如果发现自己创建的节点并非locker所有子节点中最小的说明自己还没有获取到锁此时客户端需要找到比自己小的那个节点然后对其调用exist()方法同时对其注册事件监听器。 之后让这个被关注的节点删除则客户端的Watcher会收到相应通知此时再次判断自己创建的节点是否是locker子节点中序号最小的如果是则获取到了锁如果不是则重复以上步骤继续获取到比自己小的一个节点并注册监听。 我的解释 A在Locker下创建了Node_n —循环 ( 每次获取Locker下的所有子节点 — 对这些节点按节点自增号排序顺序 — 判断自己创建的Node_n是否是第一个节点 — 如果是则获得了分布式锁 — 如果不是监听上一个节点Node_n-1 等它释放掉分布式锁。) redis的分布式锁原理setnx和redisson 分布式锁要解决的是分布式环境下并行相同代码的加锁功能了解过redis分布式锁的人肯定知道一开始redis作为分布式锁用的是setnx再这基础上设置个定时过期时间但这种方式有什么问题呢 实际上看懂上图的人也就明白了那有什么问题首先是原子性问题setnx过期时间这两个操作必须是原子性的所以这可以用lua脚本解决 再然后是释放锁的时机该如何定 不管我们定多少过期时间都不能保证在这段时间内锁住的代码执行完成了所以这个时间定多少都不好 如果不定时间当执行完成后释放锁问题就是如果执行到一半机器宕机那这把锁就永远放不掉了 那Redisson是如何解决上述问题的呢 它对代码进行了精简的封装我们的使用非常简单甚至我们不用主动设置过期时间 它设计了个watch dog看门狗每隔10秒会检查一下是否还持有锁若持有锁就给他更新过期时间30秒通过这样的设计可以让他在没有释放锁之前一直持有锁哪怕宕机了也能自动释放锁 而不能获得锁的客户端则是不断循环尝试加锁 通过记录锁的客户端id可以把它设计成可重入锁 存在的问题 redis作为分布式锁再大多数情况下是没问题的但是我们知道CAP原理一致性可用性分区容错性 在redis分布式架构中我们其实保证的是AP模型也就是尽可能的保证了redis的可用性这在一般系统中当然是没问题的哪怕有时候一致性有点问题实际读到的数据不正确或已经写入没读到毕竟是作为缓存的存在一定延迟可以接受没读到可以再读数据库这是没问题的。 但在分布式锁中一旦出现该读到没读到那就是重复锁的问题了相当于分布式锁没起到作用。 这种情况发生在什么时候呢redis集群主节点再获取锁后没来得及复制数据给从节点此时宕机了从节点接替主节点进行读写此时新的主节点没有持有该锁那么其他想要获取该锁的服务也可以获取到该锁导致了重复锁的问题。 一般来讲这种情况发生的概率是很小的看你系统的规模而定我觉得像阿里这种规模就应该不会用redis来作为分布式锁了 CP模型的分布式锁可以用zookeeper可能性能略低于redis但能保证安全可以提供顺序锁等额外功能 2PC和3PC的区别是什么 一、2PC提交协议是什么 1.1准备阶段 1.2 提交阶段 二、2PC提交协议有什么缺点 单点故障 同步阻塞 三、3PC提交协议是什么 3.1CanCommit阶段 3.PreCommit阶段 3.doCommit阶段 Seata分布式事务框架实现原理 XID一个全局事务的唯一标识由ip:port:sequence组成 Transaction Coordinator (TC) 事务协调器维护全局事务的运行状态负责协调并驱动全局事务的提交或回滚。 Transaction Manager ™ 控制全局事务的边界负责开启一个全局事务并最终发起全局提交或全局回滚的决议。 Resource Manager (RM) 控制分支事务负责分支注册、状态汇报并接收事务协调器的指令驱动分支本地事务的提交和回滚。 Seata有三个组成部分事务协调器TC协调者、事务管理器TM发起方、资源管理器RM参与方 1发起方会向协调者申请一个全局事务id并保存到ThreadLocal中为什么要保存到ThreadLocal中弱引用线程之间不会发生数据冲突 2Seata数据源代理发起方和参与方的数据源将前置镜像和后置镜像写入到undo_log表中方便后期回滚使用 3发起方获取全局事务id通过改写Feign客户端请求头传入全局事务id。 4参与方从请求头中获取全局事务id保存到ThreadLocal中并把该分支注册到SeataServer中。 5如果没有出现异常发起方会通知协调者协调者通知所有分支通过全局事务id和本地事务id删除undo_log数据如果出现异常通过undo_log逆向生成sql语句并执行然后删除undo_log语句。如果处理业务逻辑代码超时也会回滚。 分布式事务的解决方案有哪些? XA:XA是基于二阶段事务实现的一种标准协议,目前主流数据库都已支持该协议.由于是二阶段提交,缺点很明显,不适合高并发场景. 补偿机制TCC:try,commit,cancel的缩写,try阶段进行检测,commit提交执行,只要try阶段成功了commit就一定会被执行,cancel业务出现错误时执行,回滚事务,释放资源. 消息中间件MQ:可以通过阿里的消息中间件RocketMQ来进行解决.RocketMQ支持带事务的消息,具体思路大概是这样的: 第一步:消息生产者向消息集群发送prepared消息,获取消息地址. 第二步:本地提交事务,并向集群发送确认消息. 第三步:通过第一步获取到的地址,访问消息并改变消息状态. JSP jsp内置对象和作用 有九个内置对象request、response、out、session、application、pageContext、config、page、exception 作用如下 (1) HttpServletRequest类的Request对象 作用代表请求对象主要用于接受客户端通过HTTP协议连接传输到服务器端的数据。 (2) HttpServletResponse类的Respone对象 作用代表响应对象主要用于向客户端发送数据 (3) JspWriter类的out对象 作用主要用于向客户端输出数据; Out的基类是JspWriter (4) HttpSession类的session对象 作用主要用于来分别保存每个用户信息与请求关联的会话 会话状态维持是Web应用开发者必须面对的问题。 (5) ServletContex类的application对象 作用主要用于保存用户信息代码片段的运行环境 它是一个共享的内置对象即一个容器中的多个用户共享一个application对象故其保存的信息被所有用户所共享. (6) PageContext类的PageContext对象 作用管理网页属性为JSP页面包装页面的上下文管理对属于JSP中特殊可见部分中已命名对象的访问它的创建和初始化都是由容器来完成的。 (7) ServletConfig类的Config对象 作用代码片段配置对象表示Servlet的配置。 (8) Object类的Page相当于this对象 作用处理JSP网页是Object类的一个实例指的是JSP实现类的实例即它也是JSP本身只有在JSP页面范围之内才是合法的。 (9)Exception 作用处理JSP文件执行时发生的错误和异常 servlet的生命周期 1.加载和实例化 2.初始化 3.请求处理 4.服务终止 当第一个用户请求到来时服务器根据部署描述符找到所访问的Servlet类并查找当前容器发现没有此类的实例说明是第一次访问此Servlet所以容器开始加载Servlet并实例化此对象实例化之后会立即调用init()方法而且init()方法由始至终只被调用一次所以比较适合进行对象的初始化工作比如读取配置文件初始化属性等。当调用完init()方法后Servlet实例处于ready状态这时开始调用其service()方法并等待着下一次请求的到来 service()方法是服务方法只要再有请求到来服务器都会产生一个新的线程调用service()方法 如果实例长时间未被访问或者web服务器关闭则容器会负责调用destroy()方法该方法可以将一些资源释放 JVM 类的加载机制 虚拟机把描述类的数据从Class文件加载到内存并对数据进行校验、转换解析和初始化最终形成可以被虚拟机直接使用的Java类型这就是虚拟机的类加载机制。 类的加载指的是将类的.class文件中的二进制数据读入到内存中将其放在运行时数据区的方法区内然后在堆区创建一个java.lang.Class对象用来封装类在方法区内的数据结构。类的加载的最终产品是位于堆区中的Class对象Class对象封装了类在方法区内的数据结构并且向Java程序员提供了访问方法区内的数据结构的接口 GC是什么为什么要有GC? GC是垃圾收集的意思内存处理是开发人员容易出现问题的地方忘记或者错误地内存回收会导致程序或者系统的不稳定甚至崩溃Java提供的垃圾回收机制可以自动检测对象是否超过作用域从而达到自动回收的目的 回收机制有分代复制垃圾回收和标记垃圾回收增量垃圾回收 GC回收器的基本原理是什么 对于GC来说当创建对象时GC就开始监控这个对象的地址、大小以及使用情况。通常GC采用有向图的方式记录和管理堆(heap)中的所有对象。通过这种方式确定哪些对象是可达的哪些对象是不可达的。当GC确定一些对象为不可达时GC就有责任回收这些内存空间。可以。程序员可以手动执行System.gc()通知GC运行但是Java语言规范并不保证GC一定会执行 GC的具体作用 GC是垃圾回收机制java中申请的内存可以被垃圾回收装置进行回收GC可以一定程度的避免内存泄漏但是会引入一些额外的开销。 GC回收的特点 GC中主要回收的是堆和方法区中的内存栈中内存的释放要等到线程结束或者是栈帧被销毁而程序计数器中存储的是地址不需要进行释放。 有哪些 GC 算法 标记-清除算法 分为标记和清除阶段首先从每个 GC Roots 出发依次标记有引用关系的对象最后清除没有标记的对象。 执行效率不稳定如果堆包含大量对象且大部分需要回收必须进行大量标记清除导致效率随对象数量增长而降低。 存在内存空间碎片化问题会产生大量不连续的内存碎片导致以后需要分配大对象时容易触发 Full GC。 标记-复制算法 为了解决内存碎片问题将可用内存按容量划分为大小相等的两块每次只使用其中一块。当使用的这块空间用完了就将存活对象复制到另一块再把已使用过的内存空间一次清理掉。主要用于进行新生代。 实现简单、运行高效解决了内存碎片问题。代价是可用内存缩小为原来的一半浪费空间。 HotSpot 把新生代划分为一块较大的 Eden 和两块较小的 Survivor每次分配内存只使用 Eden 和其中一块 Survivor。垃圾收集时将 Eden 和 Survivor 中仍然存活的对象一次性复制到另一块 Survivor 上然后直接清理掉 Eden 和已用过的那块 Survivor。HotSpot 默认Eden 和 Survivor 的大小比例是 8:1即每次新生代中可用空间为整个新生代的 90%。 标记-整理算法 标记-复制算法在对象存活率高时要进行较多复制操作效率低。如果不想浪费空间就需要有额外空间分配担保应对被使用内存中所有对象都存活的极端情况所以老年代一般不使用此算法。 老年代使用标记-整理算法标记过程与标记-清除算法一样但不直接清理可回收对象而是让所有存活对象都向内存空间一端移动然后清理掉边界以外的内存。 标记-清除与标记-整理的差异在于前者是一种非移动式算法而后者是移动式的。如果移动存活对象尤其是在老年代这种每次回收都有大量对象存活的区域是一种极为负重的操作而且移动必须全程暂停用户线程。如果不移动对象就会导致空间碎片问题只能依赖更复杂的内存分配器和访问器解决。 GC是什么时候触发的 由于对象进行了分代处理因此垃圾回收区域、时间也不一样。GC有两种类型Scavenge GC和Full GC Scavenge GC 一般情况下当新对象生成并且在Eden申请空间失败时就会触发Scavenge GC对Eden区域进行GC清除非存活对象并且把尚且存活的对象移动到Survivor区。然后整理Survivor的两个区。这种方式的GC是对年轻代的Eden区进行不会影响到年老代。因为大部分对象都是从Eden区开始的同时Eden区不会分配的很大所以Eden区的GC会频繁进行。因而一般在这里需要使用速度快、效率高的算法使Eden去能尽快空闲出来 Full GC 对整个堆进行整理包括Young、Tenured和Perm。Full GC因为需要对整个堆进行回收所以比Scavenge GC要慢因此应该尽可能减少Full GC的次数。在对JVM调优的过程中很大一部分工作就是对于Full GC的调节。有如下原因可能导致Full GC a) 年老代Tenured被写满 b) 持久代Perm被写满 c) System.gc()被显示调用 d) 上一次GC之后Heap的各域分配策略动态变化 Minor GC、Major GC、Full GC有什么不一样 1Minor GC 即新生代GC指的是发生在新生代的垃圾收集。当年轻代空间不足的时候会触发 Minor GC这里指的是伊甸区空间不足因为Java对象大多都具备朝生夕灭的特性因此Minor GC非常频繁一般回收速度也比较快采用复制算法 2Major GC 即老年代GC指的是发生在老年代的垃圾收集。当老年代空间不足的时候会先尝试触发 Minor GC如果之后空间仍然不足则触发 Major GC。经常会伴随至少一次的Minor GC(并非绝对在Parallel Scavenge收集器中就有直接进行Major GC的策略选择过程)。Major GC的速度一般会比Minor GC慢10倍以上。采用标记算法 3Full GC 针对新生代、老年代的GC 只不过一般 Minior GC 工作量比较小. 开销也小, 对于程序影响不大. 一般我们可以把 Major GC 近似视为 Full GC 1、如何开启和查看 GC 日志 常见的 GC 日志开启参数包括 1、 -Xloggc:filename指定日志文件路径 2、 -XX:PrintGC打印 GC 基本信息 3、 -XX:PrintGCDetails打印 GC 详细信息 4、 -XX:PrintGCTimeStamps打印 GC 时间戳 5、 -XX:PrintGCDateStamps打印 GC 日期与时间 6、 -XX:PrintHeapAtGC打印 GC 前后的堆、方法区、元空间可用容量变化 7、 -XX:PrintTenuringDistribution打印熬过收集后剩余对象的年龄分布信息有助于 MaxTenuringThreshold 参数调优设置 8、 -XX:PrintAdaptiveSizePolicy打印收集器自动设置堆空间各分代区域大小、收集目标等自动调节的相关信息 9、 -XX:PrintGCApplicationConcurrentTime打印 GC 过程中用户线程并发时间 10、 -XX:PrintGCApplicationStoppedTime打印 GC 过程中用户线程停顿时间 11、 -XX:HeapDumpOnOutOfMemoryError堆 oom 时自动 dump 12、 -XX:HeapDumpPath堆 oom 时 dump 文件路径 Java 9 JVM 日志模块进行了重构参数格式发生变化这个需要知道。 GC 日志输出的格式会随着上面的参数不同而发生变化。关注各个分代的内存使用情况、垃圾回收次数、垃圾回收的原因、垃圾回收占用的时间、吞吐量、用户线程停顿时间。 借助工具可视化工具可以更方便的分析在线工具 GCeasy离线版可以使用 GCViewer。 如果现场环境不允许可以使用 JDK 自带的 jstat 工具监控观察 GC 情况。 2、Parallel Scavenge 收集器多线程复制算法、高效 Parallel Scavenge 收集器也是一个新生代垃圾收集器同样使用复制算法也是一个多线程的垃圾收集器 它重点关注的是程序达到一个可控制的吞吐量Thoughput CPU 用于运行用户代码的时间/CPU 总消耗时间即吞吐量运行用户代码时间/(运行用户代码时间垃圾收集时间)高吞吐量可以最高效率地利用 CPU 时间尽快地完成程序的运算任务主要适用于在后台运算而不需要太多交互的任务。自适应调节策略也是 ParallelScavenge 收集器与 ParNew 收集器的一个重要区别。 3、说下有哪些类加载器 Bootstrap ClassLoader启动类加载器 Extention ClassLoader扩展类加载器 App ClassLoader应用类加载器 4、你做过 JVM 调优说说如何查看 JVM 参数默认值 1、 jps -v 可以查看 jvm 进程显示指定的参数 2、 使用 -XX:PrintFlagsFinal 可以看到 JVM 所有参数的值 3、 jinfo 可以实时查看和调整虚拟机各项参数 5、什么是双亲委派机制 双亲委派机制的意思是除了顶层的启动类加载器以外其余的类加载器在加载之前都会委派给它的父加载器进行加载。这样一层层向上传递直到祖先们都无法胜任它才会真正的加载。 6、内存溢出和内存泄漏的区别 内存溢出 OutOfMemory指程序在申请内存时没有足够的内存空间供其使用。 内存泄露 Memory Leak指程序在申请内存后无法释放已申请的内存空间内存泄漏最终将导致内存溢出。 7、强引用、软引用、弱引用、虚引用是什么有什么区别 1、 强引用就是普通的对象引用关系如 String s new String(ConstXiong) 2、 软引用用于维护一些可有可无的对象。只有在内存不足时系统则会回收软引用对象如果回收了软引用对象之后仍然没有足够的内存才会抛出内存溢出异常。SoftReference 实现 3、 弱引用相比软引用来说要更加无用一些它拥有更短的生命周期当 JVM 进行垃圾回收时无论内存是否充足都会回收被弱引用关联的对象。WeakReference 实现 4、 虚引用是一种形同虚设的引用在现实场景中用的不是很多它主要用来跟踪对象被垃圾回收的活动。PhantomReference 实现 8、垃圾回收的优点和原理。说说2种回收机制 Java 语言中一个显著的特点就是引入了垃圾回收机制使 C 程序员最头疼的内存管理的问题迎刃而解它使得 Java 程序员在编写程序的时候不再需要考虑内存管理。由于有个垃圾回收机制Java 中的对象不再有“作用域”的概念只有对象的引用才有作用域。垃圾回收可以有效的防止内存泄露有效的使用可以使用的内存。垃圾回收器通常是作为一个单独的低级别的线程运行不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清楚和回收程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。 回收机制有分代复制垃圾回收和标记垃圾回收增量垃圾回收。 9、说一下垃圾分代收集的过程 分为新生代和老年代新生代默认占总空间的 1/3老年代默认占 2/3。 新生代使用复制算法有 3 个分区Eden、To Survivor、From Survivor它们的默认占比是 8:1:1。 当新生代中的 Eden 区内存不足时就会触发 Minor GC过程如下 1、 在 Eden 区执行了第一次 GC 之后存活的对象会被移动到其中一个 Survivor 分区 2、 Eden 区再次 GC这时会采用复制算法将 Eden 和 from 区一起清理存活的对象会被复制到 to 区 3、 移动一次对象年龄加 1对象年龄大于一定阀值会直接移动到老年代 4、 Survivor 区相同年龄所有对象大小的总和 (Survivor 区内存大小 * 这个目标使用率)时大于或等于该年龄的对象直接进入老年代。其中这个使用率通过 -XX:TargetSurvivorRatio 指定默认为 50% 5、 Survivor 区内存不足会发生担保分配 6、 超过指定大小的对象可以直接进入老年代 Major GC指的是老年代的垃圾清理但并未找到明确说明何时在进行Major GC FullGC整个堆的垃圾收集触发条件 1、 每次晋升到老年代的对象平均大小老年代剩余空间 2、 MinorGC后存活的对象超过了老年代剩余空间 3、 元空间不足 4、 System.gc() 可能会引起 5、 CMS GC异常promotion failed:MinorGC时survivor空间放不下对象只能放入老年代而老年代也放不下造成concurrent mode failure:GC时同时有对象要放入老年代而老年代空间不足造成 6、 堆内存分配很大的对象 10、JVM 运行时内存 Java 堆从 GC 的角度还可以细分为: 新生代(Eden 区、 From Survivor 区和 To Survivor 区)和老年代。 新生代 是用来存放新生的对象。一般占据堆的 1/3 空间。由于频繁创建对象所以新生代会频繁触发MinorGC 进行垃圾回收。新生代又分为 Eden区、 ServivorFrom、 ServivorTo 三个区。 Eden 区 Java 新对象的出生地如果新创建的对象占用内存很大则直接分配到老年代。当 Eden 区内存不够的时候就会触发 MinorGC对新生代区进行一次垃圾回收。 ServivorFrom 上一次 GC 的幸存者作为这一次 GC 的被扫描者。 ServivorTo 保留了一次 MinorGC 过程中的幸存者。 MinorGC 的过程复制-清空-互换 MinorGC 采用复制算法。 eden、 servicorFrom 复制到 ServicorTo年龄1 首先把 Eden 和 ServivorFrom 区域中存活的对象复制到 ServicorTo 区域如果有对象的年龄以及达到了老年的标准则赋值到老年代区同时把这些对象的年龄1如果 ServicorTo 不够位置了就放到老年区 清空 eden、 servicorFrom 然后清空 Eden 和 ServicorFrom 中的对象 ServicorTo 和 ServicorFrom 互换 最后 ServicorTo 和 ServicorFrom 互换原 ServicorTo 成为下一次 GC 时的 ServicorFrom区。 11、ZGC 了解吗 JDK11 中加入的具有实验性质的低延迟垃圾收集器目标是尽可能在不影响吞吐量的前提下实现在任意堆内存大小都可以把停顿时间限制在 10ms 以内的低延迟。 基于 Region 内存布局不设分代使用了读屏障、染色指针和内存多重映射等技术实现可并发的标记-整理以低延迟为首要目标。 ZGC 的 Region 具有动态性是动态创建和销毁的并且容量大小也是动态变化的。 12、safepoint是什么 STW并不会只发生在内存回收的时候。现在程序员这么卷碰到几次safepoint的问题几率也是比较大的。 当发生GC时用户线程必须全部停下来才可以进行垃圾回收这个状态我们可以认为JVM是安全的safe整个堆的状态是稳定的。 如果在GC前有线程迟迟进入不了safepoint那么整个JVM都在等待这个阻塞的线程造成了整体GC的时间变长。 13、JVM 提供的常用工具 jps 用来显示本地的 Java 进程可以查看本地运行着几个 Java 程序并显示他们的进程号。 命令格式jps jinfo 运行环境参数Java System 属性和 JVM 命令行参数Java class path 等信息。 命令格式jinfo 进程 pid jstat 监视虚拟机各种运行状态信息的命令行工具。 命令格式jstat -gc 123 250 20 jstack 可以观察到 JVM 中当前所有线程的运行情况和线程当前状态。 命令格式jstack 进程 pid jmap 观察运行中的 JVM 物理内存的占用情况如产生哪些对象及其数量。 命令格式jmap [option] pid 14、CMS 收集器多线程标记清除算法 Concurrent mark sweep(CMS)收集器是一种年老代垃圾收集器其最主要目标是获取最短垃圾回收停顿时间 和其他年老代使用标记-整理算法不同它使用多线程的标记-清除算法。最短的垃圾收集停顿时间可以为交互比较高的程序提高用户体验。CMS 工作机制相比其他的垃圾收集器来说更复杂。整个过程分为以下 4 个阶段 初始标记 只是标记一下 GC Roots 能直接关联的对象速度很快仍然需要暂停所有的工作线程。 并发标记 进行 GC Roots 跟踪的过程和用户线程一起工作不需要暂停工作线程。 重新标记 为了修正在并发标记期间因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录仍然需要暂停所有的工作线程。 并发清除 清除 GC Roots 不可达对象和用户线程一起工作不需要暂停工作线程。由于耗时最长的并发标记和并发清除过程中垃圾收集线程可以和用户现在一起并发工作 所以总体上来看CMS 收集器的内存回收和用户线程是一起并发地执行。 15、对象都是优先分配在年轻代上的吗 不是。当新生代内存不够时老年代分配担保。而大对象则是直接在老年代分配。 17、有什么堆外内存的排查思路 进程占用的内存可以使用top命令看RES段占用的值。如果这个值大大超出我们设定的最大堆内存则证明堆外内存占用了很大的区域。 使用gdb可以将物理内存dump下来通常能看到里面的内容。更加复杂的分析可以使用perf工具或者谷歌开源的gperftools。那些申请内存最多的native函数很容易就可以找到。 18、SWAP会影响性能么 当操作系统内存不足的时候会将部分数据写入到SWAP交换分中但是SWAP的性能是比较低的。如果应用的访问量较大需要频繁申请和销毁内存就容易发生卡顿。一般高并发场景下会禁用SWAP。 19、你知道哪些JVM性能调优 设定堆内存大小 1、 -Xmx堆内存最大限制。设定新生代大小。新生代不宜太小否则会有大量对象涌入老年代 2、 -XX:NewSize新生代大小 3、 -XX:NewRatio 新生代和老生代占比 4、 -XX:SurvivorRatio伊甸园空间和幸存者空间的占比 5、 设定垃圾回收器 年轻代用 -XX:UseParNewGC 年老代用-XX:UseConcMarkSweepGC 20、你都有哪些手段用来排查内存溢出 这个话题很大可以从实践环节中随便摘一个进行总结下面举例一个最普通的 你可以来一个中规中矩的回 内存溢出包含很多种情况我在平常工作中遇到最多的就是堆溢出。有一次线上遇到故障重新启动后使用jstat命令发现Old区在一直增长。我使用jmap命令导出了一份线上堆栈然后使用MAT进行分析。通过对GC Roots的分析我发现了一个非常大的HashMap对象这个原本是有位同学做缓存用的但是一个无界缓存造成了堆内存占用一直上升。后来将这个缓存改成 guava的Cache并设置了弱引用故障就消失了。 这个回答不是十分出彩但着实是常见问题让人挑不出毛病。 21、类加载有几个过程 加载、验证、准备、解析、初始化。 22、简述Java的对象结构 Java对象由三个部分组成对象头、实例数据、对齐填充。 对象头由两部分组成第一部分存储对象自身的运行时数据哈希码、GC分代年龄、锁标识状态、线程持有的锁、偏向线程ID一般占32/64 bit。第二部分是指针类型指向对象的类元数据类型即对象代表哪个类。如果是数组对象则对象头中还有一部分用来记录数组长度。 实例数据用来存储对象真正的有效信息包括父类继承下来的和自己定义的 对齐填充JVM要求对象起始地址必须是8字节的整数倍8字节对齐 ) 23、怎么查看服务器默认的垃圾回收器是哪一个 这通常会使用另外一个参数-XX:PrintCommandLineFlags可以打印所有的参数包括使用的垃圾回收器。 24、JAVA 强引用 在 Java 中最常见的就是强引用 把一个对象赋给一个引用变量这个引用变量就是一个强引用。当一个对象被强引用变量引用时它处于可达状态它是不可能被垃圾回收机制回收的即使该对象以后永远都不会被用到 JVM 也不会回收。因此强引用是造成 Java 内存泄漏的主要原因之一。 25、详细介绍一下JVM内存模型 根据 JVM 规范JVM 内存共分为虚拟机栈、堆、方法区、程序计数器、本地方法栈五个部分。 具体可能会聊聊jdk1.7以前的PermGen永久代替换成Metaspace元空间 1、 原本永久代存储的数据符号引用(Symbols)转移到了native heap字面量(interned strings)转移到了java heap类的静态变量(class statics)转移到了java heap 2、 Metaspace元空间存储的是类的元数据信息metadata 3、 元空间的本质和永久代类似都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于元空间并不在虚拟机中而是使用本地内存。 4、 替换的好处一、字符串存在永久代中容易出现性能问题和内存溢出。二、永久代会为 GC 带来不必要的复杂度并且回收效率偏低。 26、32 位 JVM 和 64 位 JVM 的最大堆内存分别是多数 理论上说上 32 位的 JVM 堆内存可以到达 2^32即 4GB但实际上会比这个小很多。不同操作系统之间不同如 Windows 系统大约 1.5GBSolaris 大约3GB。64 位 JVM 允许指定最大的堆内存理论上可以达到 2^64这是一个非常大的数字实际上你可以指定堆内存大小到 100GB。甚至有的 JVM如 Azul堆内存到 1000G 都是可能的。 27、HashMap中的key可以是普通对象么需要什么注意的地方 Map的key和value都可以是任何类型。但要注意的是一定要重写它的equals和hashCode方法否则容易发生内存泄漏。 28、你熟悉哪些垃圾收集算法 标记清除缺点是碎片化 复制算法缺点是浪费空间 标记整理算法效率比前两者差 分代收集算法老年代一般使用“标记-清除”、“标记-整理”算法年轻代一般用复制算法 29、GC 垃圾收集器 Java 堆内存被划分为新生代和年老代两部分新生代主要使用复制和标记-清除垃圾回收算法年老代主要使用标记-整理垃圾回收算法因此 java 虚拟中针对新生代和年老代分别提供了多种不同的垃圾收集器 JDK1.6 中 Sun HotSpot 虚拟机的垃圾收集器 30、什么情况发生栈溢出 -Xss可以设置线程栈的大小当线程方法递归调用层次太深或者栈帧中的局部变量过多时会出现栈溢出错误 java.lang.StackOverflowError
http://www.tj-hxxt.cn/news/134537.html

相关文章:

  • 网站建设 南昌适合seo优化的网站制作
  • 找一个网站做搜索引擎分析专业做网站上海
  • 黑龙江省建设会计协会网站上海集团平台
  • 网站显示wordpresswordpress防盗图
  • 中小型企业 公司网站建设啤酒免费代理0元铺货
  • 外贸行销网站网站设计需求模板
  • 做网站需要注意的问题成为直播人的app有哪些
  • 服装公司网站建设开题报告简历模板免费下载word格式
  • 网上做国外兼职网站手机端网站html好看的单页模板
  • 网站页面模板页面布局网站建设注意问题
  • word用来做网站的提高网站关键词排名
  • js做网站统计古镇网站建设公司
  • 做网站 公司有哪些wordpress自己制作主题
  • 太原seo网站排名有没有做兼职的网站吗
  • 建设网站公司哪里好网站如何做地面推广
  • 东莞免费网站建站模板长沙网站大全
  • 高邮建设网站巢湖市网站建设优化
  • 网站现在怎么做排名wordpress 插件官网
  • 什么网站可以学习建设工程法律实践软件开发的工作内容
  • seo外贸网站长沙网页设计哪个公司好
  • 官方网站建设银行在什么网站可以接活做
  • 社保局网站建设意义网站在别人那里已经建好了_公司里要进行修改_怎么做
  • 网站开发需要学什么技能wordpress修改登录地址
  • 做版权保护的网站seo查询seo
  • 中国企业网站西安手机网站建设动力无限
  • 长沙企业建站招聘信息网站搜索引擎收录
  • 公司要做网站网站建设代理网站
  • 资阳的网站建设奉城网站建设
  • 杭州拱墅区网站建设小浣熊做单网站
  • 建设网站用图片需要版权做可视化的网站