2023年 Java 面试八股文下(20w字)

目录

1.1 面试过程最关键的是什么?

1.2 面试时该怎么说?

1.3 面试技巧

1.3.1 六个常见问题

1.3.2 两个注意事项

1.3.3 自我介绍(控制在4分半以内,不超过5分钟)

手写代码

2.1 冒泡排序(Bubble Sort)

2.2 快速排序(Quick Sort)

2.3 归并排序(Merge Sort)

2.4 二分查找(Binary Search)

2.5 单例模式(Binary Search)

2.5.1单例模式定义

2.5.2 单例模式的特点

2.5.3 单例的四大原则

2.5.4 实现单例模式的方式

第3章 Java SE

3.1 你是怎样理解面向对象的

3.2 int和Integer有什么区别,以及以下程序结果

3.3 ==和Equals区别

3.4谈谈你对反射的理解

3.5 ArrarList和LinkedList区别

3.6 HashMap底层源码,数据结构

3.7 HashMap和HashTable区别

3.8 TreeSet和HashSet区别

3.9 String buffer和String builder区别

3.11 什么是 Java 序列化,如何实现 Java 序列化?

3.12 Object中有哪些方法

3.13线程有几种状态,产生的条件是什么

3.14产生死锁的基本条件

3.15什么是线程池,如何使用?

3.16 Java自带有哪几种线程池?

3.17 Java 中有几种类型的流

3.18字节流如何转为字符流

3.19请写出你最常见的5个RuntimeException

3.20JDK和JRE有什么区别?

3.21两个对象的 hashCode()相同,则 equals()也一定为 true,对吗?

3.22final 在 java 中有什么作用?

3.23Java 中的 Math.round(-1.5) 等于多少?

3.24String 属于基础的数据类型吗?

3.25 Java 中操作字符串都有哪些类?它们之间有什么区别?

3.26 Is String str="i" the same as String str=new String("i")?

3.28 What are the commonly used methods of the String class?

3.29 Must an abstract class have abstract methods?

3.30 What are the differences between ordinary classes and abstract classes?

3.31 Can an abstract class be decorated with final?

3.32 What is the difference between an interface and an abstract class?

3.33 How many types of IO streams are there in Java?

3.34 What is the difference between BIO, NIO, and AIO?

3.35 What are the common methods of Files?

3.36 What are the Java containers?

3.37 What is the difference between Collection and Collections?

3.38 What is the difference between List, Set, and Map?

3.39 Tell me about the implementation principle of HashSet?

3.40 How to decide to use HashMap or TreeMap?

3.41 How to realize the conversion between array and List?

3.42 Which collection classes are thread-safe?

3.43 How to use Iterator? What are the characteristics?

3.44 What is the difference between Iterator and ListIterator?

3.45 How many ways are there to create threads?

3.46 What is the difference between runnable and callable?

3.47 What is the difference between sleep() and wait()?

3.48 What is the difference between notify() and notifyAll()?

3.49 What is the difference between run() and start() of a thread?

3.50 What is the difference between the submit() and execute() methods in the thread pool?

3.51 How to ensure the safety of multi-threaded operation in java programs?

3.52 What is deadlock?

3.53 How to prevent deadlock?

3.54 What is the difference between synchronized and volatile?

3.55 What is the difference between synchronized and Lock?

3.56 What is the difference between synchronized and ReentrantLock?

3.57 What is reflection?

3.58 What is a dynamic proxy? What are the applications?

3.59 What is the difference between deep copy and shallow copy?

3.60 What is the difference between throw and throws?

3.61final、finally、finalize 有什么区别?

3.64 Java中CyclicBarrier 和 CountDownLatch有什么不同?

3.65为什么说 Synchronized 是一个悲观锁?乐观锁的实现原理 又是什么?什么是 CAS,它有什么特性?

3.66 Java中Semaphore是什么?

3.67现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行?

3.68你如何在Java中获取线程堆栈?

3.69提交任务时线程池队列已满会时发会生什么?

3.70什么是乐观锁和悲观锁?

第4章 JVM

4.1 JVM内存分哪几个区,每个区的作用是什么?

4.2 heap 和stack 有什么区别

4.3 java类加载过程?

4.4 什么是类加载器,类加载器有哪些?

4.5 java中垃圾收集的方法有哪些?

4.6 如何判断一个对象是否存活?(或者GC对象的判定方法)

4.7 简述java内存分配与回收策略以及Minor GC和Major GC(full GC)

4.8什么情况下会发生栈内存溢出。

4.9 JVM中一次完整的GC流程是怎样的,对象如何晋升到老年代

4.10你知道哪几种垃圾收集器,各自的优缺点,重点讲下cms和G1,包括原理,流程,优缺点。

4.11 JVM内存模型的相关知识了解多少,比如重排序,内存屏障,happen-before,主内存,工作内存。

4.12简单说说你了解的类加载器,可以打破双亲委派么,怎么打破。

4.13说说你知道的几种主要的JVM参数

4.15垃圾收集算法

4.16调优工具用过哪些

4.17你知道哪些JVM性能调优

4.18 Eden和Survivor的比例分配等

4.19说一说你对环境变量classpath的理解?如果一个类不在classpath下,为什么会抛出ClassNotFoundException异常,如果在不改变这个类路径的前期下,怎样才能正确加载这个类?

 设计模式

5.1你所知道的设计模式有哪些

5.2单例设计模式

5.3工厂设计模式(Factory)

5.3.1什么是工厂设计模式?

5.3.2简单工厂(Simple Factory)

5.3.3工厂方法(Factory Method)

5.3.4抽象工厂(Abstract Factory)

5.3.5三种工厂方式总结

5.4代理模式(Proxy)

5.4.1什么是代理模式?

5.4.2为什么要用代理模式?

5.4.3有哪几种代理模式?

5.4.4静态代理(Static Proxy)

5.4.5 JDK动态代理(Dynamic Proxy)

5.4.6 CGLib动态代理(CGLib Proxy)

5.4.7 简述动态代理的原理, 常用的动态代理的实现方式

第6章 MySql

6.1 jdbc 操作数据库流程

6.2关系数据库中连接池的机制是什么?

6.3 SQL 的select 语句完整的执行顺序

6.3 MySQL的事务

6.4行锁,表锁

6.5索引

6.6 b-tree和b+tree的区别

6.7简述在MySQL数据库中MyISAM和InnoDB的区别

6.8你们公司有哪些数据库设计规范

6.9 MySQL性能优化

6.10 SQL 语句优化案例

6.11 常见面试sql

6.12联合索引是什么?为什么需要注意联合索引中的顺序?

6.13什么是聚簇索引和非聚簇索引

6.14 delete、drop、truncate区别

6.15 mysql主从复制

6.16 MySQL中的varchar和char的区别以及varchar(50)中的50代表的涵义

6.17一张表里面有ID自增主键,当insert了17条记录之后,删除了第15,16,17条记录,再把mysql重启,再insert一条记录,这条记录的ID是18还是15 ?

6.18为什么使用数据索引能提高效率

6.19 B+树索引和哈希索引的区别

6.20什么情况下应不建或少建索引

6.21行级锁定的优点缺点

6.22创建的索引有没有被使用到?或者说怎么才可以知道这条语句运行很慢的原因?

6.23 varchar(10)和int(10)代表什么含义?

6.24 Have you ever cared about the time-consuming SQL in the business system? Have you counted the slow queries? How have you optimized the slow queries?

6.25 What is a stored procedure? What are the pros and cons?

6.26 Why should the field be defined as NOT NULL?

6.27 What type of currency field is used?

6.28 What type of time field is used?

6.29 Why not directly store large-capacity content such as pictures, audio, and video?

6.30 Why must a primary key be set?

6.31 Do you use auto-increment or UUID for your primary key?

6.32 What should I do if the auto-increment primary key is used up?

6.33 Why is it not recommended that the primary key has business meaning?

Chapter 7 The Java Web

7.1 Long connection and short connection of http

7.2 What are the common status codes of HTTP?

7.3 What is the difference between GET and POST?

7.4 Difference between Cookie and Session

7.5 What should I do if cookies are disabled in single sign-on?

7.6 What is jsp, what is Servlet? What is the difference between jsp and Servlet?

7.7 servlet life cycle

7.8 servlet features

7.9 Are servlets single-instance?

7.10 Are servlets thread-safe? Why?

7.11 How to solve the problem of unsafe Servlet thread?

7.12 Talk about the role of filters

7.13 Talk about the role of interceptors

7.14 What is the difference between an interceptor and a filter

7.15 Execution order of interceptors and filters

7.16 Tell me about the 4 scopes of jsp?

7.17 What built-in objects does jsp have? What are the functions?

7.18 What is the difference between Forward and Redirect?

7.19 What are the main methods of the Request object?

7.20 What is the difference between request.getAttribute() and request.getParameter()?

7.21 What is the difference between dynamic include and static include in JSP?

7.22 How to solve JSP garbled characters?

7.23 What is Tomcat?

7.24 Describe MVC in detail

7.25 What are the three parts of an Http request?

7.26 How to achieve cross domain?

7.27 Briefly describe the difference between tcp and udp?

7.28 Why does tcp need to shake hands three times, can't it be done twice? Why?

SSM framework

8.1 Please write down the commonly used dependency injection methods in spring.

8.2 Briefly describe the commonly used interfaces and specific implementation classes of IOC containers in Spring

8.3 Briefly describe how to configure beans and assemble beans based on annotations in Spring

8.4 Name the 5 annotations commonly used in Spring or Springmvc, and explain the meaning

8.5 Please explain the life cycle of Spring Bean?

8.6 Briefly talk about the workflow of SpringMVC?

8.7 How to solve the Chinese garbled problem of POST request in SpringMVC

8.8 Briefly describe how the interceptor in SpringMvc is defined, how to configure, and three important methods in the interceptor

8.9 What is the difference between #{} and ${} in MyBatis?

8.10 There are several mapping methods for Mybatis result sets, and explain how to use each mapping method.

8.11 Briefly describe how to pass a single parameter and multiple parameters of MyBatis and how to get a value.

8.12 How does MyBatis obtain the automatically generated (primary) key value?  

8.13 Briefly describe the dynamic SQL of Mybatis, and list the 6 commonly used tags and their functions

8.14 In the Xml mapping file of Mybatis, can the id of different Xml mapping files be repeated?

8.15 How Mybatis completes the batch operation of MySQL, with examples

8.17 Briefly describe the scope of beans in Spring

8.18 Briefly describe the two assembly modes commonly used in automatic assembly in Spring

8.19 Please explain the working mechanism of the @Autowired annotation and the role of the required attribute

8.20 Briefly describe the role and implementation principle of ContextLoaderListener in Springmvc

8.21 Briefly describe the two-level cache provided by Mybatis and the search order of the cache

8.22 Briefly describe how to solve the problem that beans are created twice when integrating Spring and Springmvc

8.23 Briefly describe the two main integration places when Spring and Mybatis are integrated

8.24 Briefly describe the two transaction propagation behaviors commonly used in @Transaction in Spring declarative transactions

8.25 Briefly describe the function of the @RequestMapping annotation, the position that can be marked, and the commonly used attributes

8.26 Briefly describe the two ways of processing model data in Springmvc

8.27 Briefly describe the four request methods and corresponding operations in REST

8.28 Briefly describe the relationship and function of view and view resolution

8.29 Name three commonly used view classes

8.30简述REST中HiddenHttpMethodFilter过滤器的作用

8.31简述Springmvc中如何返回JSON数据

8.32简述如何在myBatis中的增删改操作获取到对数据库的影响条数

8.33 Springmvc中的控制器的注解用哪个,可以是否用别的注解代替

8.34如何在Springmvc中获取客户端提交的请求参数

8.35简述Springmvc中InternalResourceViewResolver解析器的工作机制

8.36 Springmvc中如何完成重定向

8.37简述Spring中切面中常用的几种通知,并简单解释

8.38解释MyBatis中 @Param注解的作用

8.39简述Mybatis中使用Mapper接口开发,如何完成Mapper接口与SQL映射文件、方法与SQL语句的绑定

8.40 SpringMVC的工作原理

8.41谈谈你对Spring 的理解

8.42 Spring中常用的设计模式

8.43请描述一下Spring的事务管理

8.45说出SpringMVC常用的5个注解?如何使用 SpringMVC完成JSON操作?

8.46Spring 支持的事务管理类型有哪些?你在项目中使用哪种方式?怎么理解全局事务和局部事务?

8.47JDBC编程有哪些不足之处,MyBatis是如何解决这些问题的?

8.48SqlMapConfig.xml中配置有哪些内容?

8.49简单的说一下MyBatis的一级缓存和二级缓存?

8.50Mybatis是否支持延迟加载?如果支持,它的实现原理是什么?

SpringBoot

9.1什么是 Spring Boot?

9.2为什么要用 Spring Boot?

9.3 Spring Boot有哪些缺点?

9.4 Spring Boot 的核心配置文件有哪几个?它们的区别是什么?

9.5 Spring Boot 的配置文件有哪几种格式?它们有什么区别?

9.6 Spring Boot 的核心注解是哪个?它主要由哪几个注解组成的?

9.7 What are the ways to enable Spring Boot features?

9.8 Does Spring Boot need a separate container to run?

9.9 What are the ways to run Spring Boot?

9.10 What is the principle of Spring Boot automatic configuration?

9.12. How to run some specific code when Spring Boot starts?

9.13. How many ways does Spring Boot have to read configuration?

9.14. Which logging frameworks does Spring Boot support? Which is the recommended and default logging framework?

9.15. How many ways does SpringBoot implement hot deployment?

9.16. How do you understand the Spring Boot configuration loading order?

9.17. How does Spring Boot define multiple sets of different environment configurations?

9.18 Can Spring Boot be compatible with old Spring projects, and how?

9.19 What's new in Spring Boot 2.X? How is it different from 1.X?

9.20 What is the difference between Spring Boot, Spring MVC and Spring?

9.21 What is Spring Boot Stater?

9.22 What is Spring Data REST?

9.23 What is the difference between RequestMapping and GetMapping?

 SpringCloud

10.1 What is the relationship between Spring Boot and Spring

10.2 What is the relationship between Spring Boot and Spring Cloud

10.3 The difference between Eureka and zookeeper

10.4 How does springcloud implement service registration?

10.5 What is eureka's self-protection mechanism?

10.6 What is a service circuit breaker? What is service downgrade?

10.7 What is the difference between Ribbon and Feign?

10.8 What can a Hystrix circuit breaker do?

10.9 What can the distributed configuration center do?

10.10 How do microservices communicate?

10.11 What is Swagger? Have you implemented it with Spring Boot?

10.11 What microservice technology stacks do you know? Please list one or two

10.12 What can Ribbon load balancing do?

10.13什么是SpringCloud Config分布式配置中心

第11章 Redis

11.1什么是Redis?

11.2 redis有哪些数据类型

11.3一个字符串类型的值能存储最大容量是多少?

11.4 怎么理解Redis事务?

11.5 Redis事务相关的命令有哪几个?

11.6 Redis key的过期时间和永久有效分别怎么设置?

11.7 Redis 集群如何选择数据库?


11.8 Redis持久化数据和缓存怎么做扩容?

11.9 为什么Redis需要把所有数据放到内存中?

11.10 Redis如何做内存优化?

11.11缓存穿透

11.12 哨兵模式

11.13 悲观锁

11.14 乐观锁

11.15 持久化

11.16 Redis提供了哪几种持久化方式?

11.17如何选择合适的持久化方式?

11.18分布式Redis是前期做还是后期规模上来了再做好?为什么?

11.19 Redis的内存占用情况怎么样?

11.20都有哪些办法可以降低Redis的内存使用情况呢?

11.21查看Redis使用情况及状态信息用什么命令?

11.22 Redis的内存用完了会发生什么?

11.23 redis是单线程的,为什么那么快

11.24 Redis是单线程的,如何提高多核CPU的利用率?

11.25一个Redis实例最多能存放多少的keys?List、Set、Sorted Set他们最多能存放多少元素?

11.26 Redis常见性能问题和解决方案?

11.27 Redis相比memcached有哪些优势?

11.28 MySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据?

11.29 Redis有哪几种数据淘汰策略?

11.30 Redis集群方案应该怎么做?都有哪些方案?

11.31说说Redis哈希槽的概念?

11.32 Redis集群最大节点个数是多少?

11.33 怎么测试Redis的连通性?

11.34修改配置不重启Redis会实时生效吗?

11.35 Redis有哪些适合的场景?

 MQ

12.1 What should I do if ActiveMQ fails to send a message?

12.2 How to use ActiveMQ to solve distributed transactions?

12.3 How to prevent ActiveMQ messages from being sent repeatedly?

12.4 What are the disadvantages of using message queues?

12.5 What are the functions and usage scenarios of message queues?

12.6 How to ensure the sequence of messages?

12.7 How to ensure the high availability of the message queue?

12.8 Where do messages that cannot be routed go?

12.9 Message Queue Expiration and Failure Problem

12.10 What should I do if the message queue is full?

12.11 What are the important components of RabbitMQ?

12.12 How many broadcast types does RabbitMQ have?

12.14 How are messages distributed?

12.15 How to ensure that messages are sent to RabbitMQ correctly? How to ensure that the receiver of the message consumes the message?

12.16 Why shouldn't the persistence mechanism be used for all messages?

12.16 What is the difference between ActiveMQ and RabbitMQ?

12.17 What is the broker in RabbitMQ? What does cluster mean?

12.18 What is metadata? What are the types of metadata? What is included? What metadata is associated with the cluster? How is metadata stored? How is metadata distributed in the cluster?

12.19 Is there a limit to the number of messages stored in a queue on RabbitMQ?

12.20 Are the channel, exchange, and queue in the RabbitMQ concept logical concepts, or do they correspond to process entities? What are the functions of these things?

When will a 12.21 message become Dead Letter?

12.22 How does RabbitMQ implement a delayed queue?

12.23 In SpringBoot, consumers start to listen for messages before the bean is initialized, resulting in a null pointer exception. How can consumers start listening after the container is started?

ElasticSearch

13.1 What is ElasticSearch? 

13.2 What is an inverted index in Elasticsearch? 

13.3 How much do you know about elasticsearch? Tell me about your company's es cluster architecture, index data size, number of fragments, and some tuning methods.

13.4 What to do, how to tune and deploy when there is too much elasticsearch index data

13.5. How does elasticsearch implement master election

13.6 Describe in detail the process of Elasticsearch indexing documents

13.7 Describe the Elasticsearch search process in detail?

13.8 How to optimize the Linux settings when Elasticsearch is deployed

13.9 Among the nodes in Elasticsearch (for example, there are 20 in total), 10 of them choose a master, and the other 10 choose another master, what should I do?

13.10 Regarding GC, what should be paid attention to when using Elasticsearch?

13.11 In the case of concurrency, if Elasticsearch guarantees read and write consistency?


1.1 What is the most critical part of the interview process?

1 ) It's not what you say, it's how you say it

2 ) Chat freely and relax

1.2 What should I say during the interview?

1 ) Clear language expression

       ( 1 ) Logical thinking and smooth expression

       ( 2 ) One, two, three levels of expression

2 ) The stated content does not make mistakes

       ( 1 ) Don't speak ill of your former club or yourself

       ( 2 ) Talk about what you are good at

       ( 3 ) Essence: content heard, self-affirmation; not heard, learning process.

1.3 Interview Skills

1.3.1 Six common problems

1 ) What are your strengths?

       Boldly state your strengths and strengths in all aspects

2 ) What are your weaknesses?

       Don't talk about reducing points for yourself; use " disadvantages " to set off your own advantages

3 ) What is your reason for leaving?

    • Don't speak ill of your former club, even if you've been hurt
    • reasonable and legal
    • Do not give more than 1 reason

4 ) What are your salary expectations?

    • Don't discuss salary in depth
    • Only talk about intervals, not specific numbers
    • The bottom line is no less than current salary
    • Specific numbers are required, the middle value of the range, or +20% of the current salary

5 ) Do you have any other questions?

    • This is a matter of personal vision and level
    • The question itself is not what kind of answer the interviewer wants, but how you compare to other candidates
    • standard answer:

What kind of problems does the company expect me to solve for the company within 3-6 months after joining the company?

What does the future strategic plan for the company (or for this department) look like?

Based on what you know about me now, how long do you think it will take me to integrate into the company?

6 ) How soon can you join the job?

       About one week, if the company needs, it can be properly advanced

1.3.2 Two Notes

1 ) Professional language

2 ) Professional image

1.3.3 Self-introduction (control within 4 and a half minutes, no more than 5 minutes)

1 ) Basic personal information

2 ) Work history

       Time, company name, position, main work content, work performance, reason for leaving

3 ) In-depth communication (also called stress interview)

       Get to the bottom of the problem and ask questions in a sinking style (note that it is a sinking type, not a divergent one)

       Basic skills: speak in the direction you are familiar with

handwritten code

2.1 Bubble Sort (Bubble Sort)

Algorithm Description:

  1. Compare adjacent elements. If the first is greater than the second, swap them both;
  2. Do the same for each pair of adjacent elements, from the first pair at the beginning to the last pair at the end, so the element at the end should be the largest number;
  3. Repeat the above steps for all elements except the last one;
  4. Repeat steps 1~3 until sorting is complete.

If two elements are equal, they will not exchange positions, so bubble sort is a stable sorting algorithm.

Code:

  1. package com.atguigu.interview.chapter02;  
  2.   
  3. /** 
  4.  * @author atguigu
  5.  *  bubble sort 
  6.  */  
  7. public class BubbleSort {  
  8.   
  9.     /** 
  10.      * @param data  sorted array 
  11.      */  
  12.     public static void bubbleSort(int[] data) {  
  13.   
  14.         int arrayLength = data.length;  
  15.   
  16.         for (int i = 1; i < arrayLength; i++) { //第i次排序  
  17.   
  18.             for  ( int  j =  0 ; j < arrayLength - i; j++) { // Start from the number with index j  
  19.                 if  (data[j] > data[j +  1 ]) {  // Pairwise comparison of adjacent elements  
  20.                     int  temp = data[j +  1 ];   //  element exchange  
  21.                     data[j + 1] = data[j];  
  22.                     data[j] = temp;  
  23.                 }  
  24.             }  
  25.   
  26.             System.out.println( " th"  + i +  " sorting:\n"  + java.util.Arrays.toString(data));  
  27.         }  
  28.     }  
  29.   
  30.     public static void main(String[] args) {  
  31.   
  32.         int[] data = { 34438547153626272464195048};  
  33.   
  34.         System.out.println( " Before sorting:\n"  + java.util.Arrays.toString(data));  
  35.   
  36.         bubbleSort(data);  
  37.   
  38.         System.out.println( " After sorting:\n"  + java.util.Arrays.toString(data));  
  39.     }  
  40. }  

2.2 Quick sort (Quick Sort)

Algorithm Description:

Use the divide-and-conquer method to divide a string (list) into two sub-strings (sub-lists). The specific algorithm is described as follows:

  1. 从数列中挑出一个元素,称为 “基准”(pivot);
  2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
  3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

key值的选取可以有多种形式,例如中间数或者随机数,分别会对算法的复杂度产生不同的影响。

代码实现:

  1. package com.atguigu.interview.chapter02;  
  2.   
  3. /** 
  4.  * @author atguigu
  5.  * 快速排序 
  6.  */  
  7. public class QuickSort {  
  8.   
  9.     public static void quickSort(int[] data, int low, int high) {  
  10.         int i, j, temp, t;  
  11.         if (low > high) {  
  12.             return;  
  13.         }  
  14.         i = low;  
  15.         j = high;  
  16.         //temp就是基准位  
  17.         temp = data[low];  
  18.         System.out.println( " Basic bit: "  + temp);  
  19.   
  20.         while (i < j) {  
  21.             // Look at the right first, and then decrease to the left  
  22.             while (temp <= data[j] && i < j) {  
  23.                 j--;  
  24.             }  
  25.             // Look at the left again, and increase to the right in turn  
  26.             while (temp >= data[i] && i < j) {  
  27.                 i++;  
  28.             }  
  29.             // swap if condition is met  
  30.             if (i < j) {  
  31.                 System.out.println( " Exchange: "  + data[i] +  " and "  + data[j]);  
  32.                 t = data[j];  
  33.                 data[j] = data[i];  
  34.                 data[i] = t;  
  35.                 System.out.println(java.util.Arrays.toString(data));  
  36.   
  37.             }  
  38.         }  
  39.         // Finally exchange the reference position with the number at the equal position of i and j  
  40.         System.out.println( " Base position"  + temp +  " position where i and j meet"  + data[i] +  " exchange" );  
  41.         data[low] = data[i];  
  42.         data[i] = temp;  
  43.         System.out.println(java.util.Arrays.toString(data));  
  44.   
  45.         // Recursively call the left half of the array  
  46.         quickSort(data, low, j - 1);  
  47.         // Recursively call the right half of the array  
  48.         quickSort(data, j + 1, high);  
  49.     }  
  50.   
  51.   
  52.     public static void main(String[] args) {  
  53.   
  54.         int[] data = { 34438547153626272464195048};  
  55.   
  56.         System.out.println("排序之前:\n" + java.util.Arrays.toString(data));  
  57.   
  58.         quickSort(data, 0, data.length - 1);  
  59.   
  60.         System.out.println("排序之后:\n" + java.util.Arrays.toString(data));  
  61.     }  
  62. }  

快速排序详细参考:

快速排序(java实现)_大数据指北的博客-CSDN博客

2.3 Merge Sort (Merge Sort)

Algorithm Description:

  1. Divide an input sequence of length n into two subsequences of length n/2;
  2. Use merge sort for the two subsequences respectively;
  3. Merges two sorted subsequences into a final sorted sequence.

( 1 ) Merge sort process

( 2 ) The process of merging two ordered arrays

Code:

  1. package com.atguigu.interview.chapter02;  
  2.   
  3. /** 
  4.  * @author atguigu
  5.  */  
  6. public class MergeSort {  
  7.   
  8.     public static void mergeSort(int[] data) {  
  9.         sort(data, 0, data.length - 1);  
  10.     }  
  11.   
  12.     public static void sort(int[] arr, int l, int r) {  
  13.         if(l == r) {  
  14.             return;  
  15.         }  
  16.         int mid = l + ((r - l) >> 1);  
  17.         sort(arr, l, mid);  
  18.         sort(arr, mid + 1, r);  
  19.         merge(arr, l, mid, r);  
  20.     }  
  21.   
  22.     public static void merge(int[] arr, int l, int mid, int r) {  
  23.         int[] temp = new int[r - l + 1];  
  24.         int i = 0;  
  25.         int  p1 = l;  
  26.         int p2 = mid + 1;  
  27.         //  Compare the elements of the left and right parts, which one is smaller, and fill that element into temp  
  28.         while(p1 <= mid && p2 <= r) {  
  29.             temp[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];  
  30.         }  
  31.         //  After the above loop exits, fill the remaining elements into temp in turn  
  32.         //  Only one of the following two while will execute  
  33.         while(p1 <= mid) {  
  34.             temp[i++] = arr[p1++];  
  35.         }  
  36.         while(p2 <= r) {  
  37.             temp[i++] = arr[p2++];  
  38.         }  
  39.         //  Copy the final sorted result to the original array  
  40.         for(i = 0; i < temp.length; i++) {  
  41.             arr[l + i] = temp[i];  
  42.         }  
  43.     }  
  44.   
  45.     public static void main(String[] args) {  
  46.   
  47.         int[] data = { 34438547153626272464195048};  
  48.   
  49.         System.out.println( " Before sorting:\n"  + java.util.Arrays.toString(data));  
  50.   
  51.         mergeSort(data);  
  52.   
  53.         System.out.println( " After sorting:\n"  + java.util.Arrays.toString(data));  
  54.     }  
  55. }  

2.4 Binary Search

Algorithm Description:

  1. Binary search, also known as binary search, is a more efficient search method that requires the elements in the list to be arranged in an orderly manner first.
  2. 首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;
  3. 否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。
  4. 重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。

代码实现:

  1. package com.atguigu.interview.chapter02;  
  2.   
  3. /** 
  4.  * @author Atguigu
  5.  */  
  6. public class BinarySearch {  
  7.   
  8.   
  9.     /** 
  10.      * 二分查找 时间复杂度O(log2n);空间复杂度O(1) 
  11.      * 
  12.      * @param arr     被查找的数组 
  13.      * @param left 
  14.      * @param right 
  15.      * @param findVal 
  16.      * @return 返回元素的索引 
  17.      */  
  18.     public static int binarySearch(int[] arr, int left, int right, int findVal) {  
  19.   
  20.         if (left > right) { //递归退出条件,找不到,返回-1  
  21.             return -1;  
  22.         }  
  23.   
  24.         int midIndex = (left + right) / 2;  
  25.   
  26.         if (findVal < arr[midIndex]) { //向左递归查找  
  27.             return binarySearch(arr, left, midIndex, findVal);  
  28.         } else if (findVal > arr[midIndex]) { //向右递归查找  
  29.             return binarySearch(arr, midIndex, right, findVal);  
  30.         } else {  
  31.             return midIndex;  
  32.         }  
  33.     }  
  34.   
  35.     public static void main(String[] args){  
  36.   
  37.         //注意:需要对已排序的数组进行二分查找  
  38.         int[] data = {-49, -30, -1692121233030};  
  39.         int i = binarySearch(data, 0, data.length, 21);  
  40.         System.out.println(i);  
  41.     }  
  42. }  

Expansion needs:

When there are multiple identical values ​​in an ordered array, how to find all the values.

Code:

  1. package com.atguigu.interview.chapter02;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. /** 
  7.  * @author Atguigu
  8.  *
  9.  */  
  10. public class BinarySearch2 {  
  11.   
  12.     /** 
  13.      * {1, 8, 10, 89, 1000, 1000, 1234} 
  14.      *  In an ordered array, there are multiple identical values, how to find all the values, such as 1000 here. 
  15.      *  Analysis: 
  16.      * 1.  The returned result is a list list 
  17.      * 2.  When a result is found, scan left, scan right [Condition] 
  18.      * 3.  After finding the result, add it to ArrayBuffer 
  19.      * 
  20.      * @return 
  21.      */  
  22.     public static List<Integer> binarySearch2(int[] arr, int left, int right, int findVal) {  
  23.   
  24.         // Can't find condition?  
  25.         List<Integer> list = new ArrayList<>();  
  26.   
  27.         if  (left > right) { // recursive exit condition, if not found, return -1  
  28.             return list;  
  29.         }  
  30.   
  31.         int midIndex = (left + right) / 2;  
  32.         int  midVal = arr[midIndex];  
  33.         if  (findVal < midVal) { // recursive search to the left  
  34.             return binarySearch2(arr, left, midIndex - 1, findVal);  
  35.         }  else  if  (findVal > midVal) {  // recursive search to the right  
  36.             return binarySearch2(arr, midIndex + 1, right, findVal);  
  37.         } else {  
  38.             System.out.println("midIndex=" + midIndex);  
  39.   
  40.             // scan to the left  
  41.             int temp = midIndex - 1;  
  42.             while (true) {  
  43.                 if (temp < 0 || arr[temp] != findVal) {  
  44.                     break;  
  45.                 }  
  46.                 if (arr[temp] == findVal) {  
  47.                     list.add(temp);  
  48.                 }  
  49.                 temp -= 1;  
  50.             }  
  51.   
  52.             //将中间这个索引加入  
  53.             list.add(midIndex);  
  54.   
  55.             //向右边扫描  
  56.             temp = midIndex + 1;  
  57.             while (true) {  
  58.                 if (temp > arr.length - 1 || arr[temp] != findVal) {  
  59.                     break;  
  60.                 }  
  61.                 if (arr[temp] == findVal) {  
  62.                     list.add(temp);  
  63.                 }  
  64.                 temp += 1;  
  65.             }  
  66.             return list;  
  67.         }  
  68.     }  
  69.   
  70.     public static void main(String[] args){  
  71.   
  72.         //注意:需要对已排序的数组进行二分查找  
  73.         int[] data = { 181089100010001234};  
  74.         List<Integer> list = binarySearch2(data, 0, data.length, 1000);  
  75.         System.out.println(list);  
  76.     }  
  77. }  

2.5 单例模式(Binary Search)

2.5.1单例模式定义

单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。每台计算机可以有若干个打印机,但只能有一个Printer Spooler,以避免两个打印作业同时输出到打印机中。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。总之,选择单例模式就是为了避免不一致状态。

2.5.2 单例模式的特点

  1. 单例类只能有一个实例。
  2. 单例类必须自己创建自己的唯一实例。
  3. 单例类必须给所有其他对象提供这一实例。

单例模式保证了全局对象的唯一性,比如系统启动读取配置文件就需要单例保证配置的一致性。

2.5.3 单例的四大原则

  1. 构造私有
  2. 以静态方法或者枚举返回实例
  3. 确保实例只有一个,尤其是多线程环境
  4. 确保反序列换时不会重新构建对象

2.5.4 实现单例模式的方式

(1)饿汉式(立即加载):

饿汉式单例在类加载初始化时就创建好一个静态的对象供外部使用,除非系统重启,这个对象不会改变,所以本身就是线程安全的

Singleton通过将构造方法限定为private避免了类在外部被实例化,在同一个虚拟机范围内,Singleton的唯一实例只能通过getInstance()方法访问。(事实上,通过Java反射机制是能够实例化构造方法为private的类的,会使Java单例实现失效)

  1. package com.atguigu.interview.chapter02;  
  2.   
  3. /** 
  4.  * @author atguigu
  5.  * 饿汉式(立即加载) 
  6.  */  
  7. public class Singleton1 {  
  8.   
  9.     /** 
  10.      * 私有构造 
  11.      */  
  12.     private Singleton1() {  
  13.         System.out.println("构造函数Singleton1");  
  14.     }  
  15.   
  16.     /** 
  17.      * 初始值为实例对象 
  18.      */  
  19.     private static Singleton1 single = new Singleton1();  
  20.   
  21.     /** 
  22.      * 静态工厂方法 
  23.      * @return 单例对象 
  24.      */  
  25.     public static Singleton1 getInstance() {  
  26.         System.out.println("getInstance");  
  27.         return single;  
  28.     }  
  29.   
  30.     public static void main(String[] args){  
  31.         System.out.println("初始化");  
  32.         Singleton1 instance = Singleton1.getInstance();  
  33.     }  
  34. }  

  1. 懒汉式(延迟加载):

该示例虽然用延迟加载方式实现了懒汉式单例,但在多线程环境下会产生多个Singleton对象

  1. package com.atguigu.interview.chapter02;  
  2.   
  3. /** 
  4.  * @author atguigu
  5.  *
  6.  * 
  7.  * 懒汉式(延迟加载) 
  8.  */  
  9. public class Singleton2 {  
  10.   
  11.     /** 
  12.      *  private construct 
  13.      */  
  14.     private Singleton2() {  
  15.         System.out.println( " Constructor Singleton2" );  
  16.     }  
  17.   
  18.     /** 
  19.      *  Initial value is null 
  20.      */  
  21.     private static Singleton2 single = null;  
  22.   
  23.     /** 
  24.      *  static factory method 
  25.      * @return  singleton object 
  26.      */  
  27.     public static Singleton2 getInstance() {  
  28.         if(single == null){  
  29.             System.out.println("getInstance");  
  30.             single = new Singleton2();  
  31.         }  
  32.         return single;  
  33.     }  
  34.   
  35.     public static void main(String[] args){  
  36.   
  37.         System.out.println( " Initialization" );  
  38.         Singleton2 instance = Singleton2.getInstance();  
  39.     }  
  40. }  

  1. Synchronization locks (solve thread safety issues):

Add a synchronized synchronization lock to the method or use a synchronization code block to add a synchronization lock to the class. Although this method solves the problem of multiple instance objects, the operation efficiency of this method is very low. If the next thread wants to obtain the object, it must Wait for the previous thread to release the lock before continuing to run.

  1. package com.atguigu.interview.chapter02;  
  2.   
  3. /** 
  4.  * @author atguigu
  5.  *
  6.  * 
  7.  *  Synchronization lock (solve thread safety issues) 
  8.  */  
  9. public class Singleton3 {  
  10.   
  11.     /** 
  12.      *  private construct 
  13.      */  
  14.     private Singleton3() {}  
  15.   
  16.     /** 
  17.      *  Initial value is null 
  18.      */  
  19.     private static Singleton3 single = null;  
  20.   
  21.     public static Singleton3 getInstance() {  
  22.   
  23.         //  Equivalent to synchronized public static Singleton3 getInstance()  
  24.         synchronized(Singleton3.class){  
  25.             //  Note: The judgment inside must be added, otherwise there will be thread safety problems  
  26.             if(single == null){  
  27.                 single = new Singleton3();  
  28.             }  
  29.         }  
  30.         return single;  
  31.     }  
  32. }  

(4 ) Double-check locks (improve the efficiency of synchronization locks):

The use of double-check locks is further optimized, which can prevent the entire method from being locked, and only lock the part of the code that needs to be locked, which can improve execution efficiency.

  1. package com.atguigu.interview.chapter02;  
  2.   
  3. /** 
  4.  * @author atguigu
  5.  *
  6.  Double check locks ( improves the efficiency of synchronization locks ) 
  7.  */  
  8. public class Singleton4 {  
  9.   
  10.     /** 
  11.      *  private construct 
  12.      */  
  13.     private Singleton4() {}  
  14.   
  15.     /** 
  16.      *  Initial value is null 
  17.      */  
  18.     private static Singleton4 single = null;  
  19.   
  20.     /** 
  21.      *  double check lock 
  22.      * @return 单例对象 
  23.      */  
  24.     public static Singleton4 getInstance() {  
  25.         if (single == null) {  
  26.             synchronized (Singleton4.class) {  
  27.                 if (single == null) {  
  28.                     single = new Singleton4();  
  29.                 }  
  30.             }  
  31.         }  
  32.         return single;  
  33.     }  
  34. }  

(5) 静态内部类:

这种方式引入了一个内部静态类(static class),静态内部类只有在调用时才会加载,它保证了Singleton 实例的延迟初始化,又保证了实例的唯一性。它把singleton 的实例化操作放到一个静态内部类中,在第一次调用getInstance() 方法时,JVM才会去加载InnerObject类,同时初始化singleton 实例,所以能让getInstance() 方法线程安全。

特点是:即能延迟加载,也能保证线程安全。

静态内部类虽然保证了单例在多线程并发下的线程安全性,但是在遇到序列化对象时,默认的方式运行得到的结果就是多例的。

  1. package com.atguigu.interview.chapter02;  
  2.   
  3. /** 
  4.  * @author atguigu
  5.  *
  6.  * 
  7.  *  Static inner class ( lazy loading, thread safe) 
  8.  */  
  9. public class Singleton5 {  
  10.   
  11.     /** 
  12.      *  private construct 
  13.      */  
  14.     private Singleton5() {}  
  15.   
  16.     /** 
  17.      *  static inner class 
  18.      */  
  19.     private static class InnerObject{  
  20.         private static Singleton5 single = new Singleton5();  
  21.     }  
  22.   
  23.     public static Singleton5 getInstance() {  
  24.         return InnerObject.single;  
  25.     }  
  26. }  

(6 ) Internal enumeration class implementation (to prevent reflection attacks) :

In fact, it is possible to instantiate a class whose constructor is private through the Java reflection mechanism. This is the enumeration singleton pattern we need to introduce now.

  1. package com.atguigu.interview.chapter02;  
  2.   
  3. /** 
  4.  * @author atguigu
  5.  *
  6.  */  
  7. public class SingletonFactory {  
  8.   
  9.     /** 
  10.      *  Internal enumeration class 
  11.      */  
  12.     private enum EnumSingleton{  
  13.         Singleton;  
  14.         private Singleton6 singleton;  
  15.   
  16.         // The constructor of the enumeration class is instantiated when the class is loaded  
  17.         private EnumSingleton(){  
  18.             singleton = new Singleton6();  
  19.         }  
  20.         public Singleton6 getInstance(){  
  21.             return singleton;  
  22.         }  
  23.     }  
  24.       
  25.     public static Singleton6 getInstance() {  
  26.         return EnumSingleton.Singleton.getInstance();  
  27.     }  
  28. }  
  29.   
  30. class Singleton6 {  
  31.     public Singleton6(){}  
  32. }  

Chapter 3 Java SE

3.1 How do you understand object-oriented

Object-oriented is good for language to abstract real things. Object-oriented has the following four characteristics:

(1 ) Inheritance: Inheritance is the process of creating new classes by obtaining inheritance information from existing classes

(2)封装:通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。

(3)多态性:多态性是指允许不同子类型的对象对同一消息作出不同的响应。

(4)抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。

3.2 int和Integer有什么区别,以及以下程序结果

(1)Integer是int的包装类,int则是java的一种基本数据类型

(2)Integer变量必须实例化后才能使用,而int变量不需要

(3)Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象;而int则是直接存储数据值

(4)Integer的默认值是null,int的默认值是0

(5)java在编译Integer i = 100 ;时,会翻译成为Integer i = Integer.valueOf(100)。而java API中对Integer类型的valueOf的定义如下,对于-128到127之间的数,会进行缓存,Integer i = 127时,会将127这个Integer对象进行缓存,下次再写Integer j = 127时,就会直接从缓存中取,就不会new了

  1. package com.atguigu.interview.chapter03;  
  2.   
  3. /** 
  4.  * @author atguigu
  5.  * @since 2019/7/28 
  6.  */  
  7. public class Test01 {  
  8.   
  9.     public static void main(String[] args){  
  10.         Integer a = 127;  
  11.         Integer b = 127;  
  12.         Integer c = 128;  
  13.         Integer d = 128;  
  14.         System.out.println(a==b); //true  
  15.         System.out.println(c==d); //false  
  16.     }  
  17. }  

3.3 The difference between == and Equals

1 ==

If the comparison is of primitive data types, then the value of the variable is compared

If the comparison is a reference data type, then the address value is compared (whether the two objects point to the same memory)

  1.  equals

If the equals method is not rewritten, the address value of the two objects is compared

If we override the equals method, we often compare the contents of the properties in the object

The equals method is inherited from the Object class, and the default implementation is to use ==

3.4 Talk about your understanding of reflection

(1 ) Reflection mechanism:

The so-called reflection mechanism is that the Java language has a self-observation ability at runtime. Through this ability, you can thoroughly understand your own situation and prepare for the next step.

The implementation of Java's reflection mechanism requires the help of four classes: class, Constructor, Field, Method;

Among them, class represents the class object, Constructor—the constructor object of the class, Field—the attribute object of the class, and Method—the method object of the class. Through these four objects, we can roughly see the various components of a class.

(2 ) The role of Java reflection:

In the Java runtime environment, for any class, you can know which properties and methods this class has. For any object, any method of it can be called. This function of dynamically obtaining class information and dynamically calling object methods comes from the reflection mechanism of the Java language.

(3 ) The Java reflection mechanism provides functions

Determine the class of any object at runtime.

Constructs an object of any class at runtime.

Determine the member variables and methods of any class at runtime.

Call any object's method at runtime

3.5 Difference between ArrarList and LinkedList

(1) ArrayList implements a data structure based on a dynamic array, and LinkedList is based on a linked list data structure.

(2) For random access get and set, ArrayList is better than LinkedList, because LinkedList needs to move the pointer.

(3) LinkedList is more advantageous for adding and deleting operations add and remove, because ArrayList needs to move data. It depends on the actual situation. If only a single piece of data is inserted or deleted, the speed of ArrayList is better than that of LinkedList. But if you insert and delete data randomly in batches, LinkedList is much faster than ArrayList. Because every time ArrayList inserts a piece of data, it needs to move the insertion point and all subsequent data.

3.6 HashMap underlying source code, data structure

The underlying structure of HashMap is implemented by array + linked list in jdk1.7 , and by array + linked list + red-black tree in jdk1.8 . Take the structure of array + linked list as an example.

3.7 Difference between HashMap and HashTable

( 1 ) Different thread safety

HashMap is not thread-safe, and HashTable is thread-safe, and its method is Synchronize . In the case of multi-thread concurrency, HashTabl can be used directly , but when using HashMap , synchronization processing must be added by itself.

( 2 ) Whether to provide contains method

HashMap只有containsValuecontainsKey方法;HashTablecontainscontainsKeycontainsValue三个方法,其中containscontainsValue方法功能相同。

3keyvalue是否允许null

Hashtable中,keyvalue都不允许出现null值。HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null

4)数组初始化和扩容机制

HashTable在不指定容量的情况下的默认容量为11,而HashMap16Hashtable不要求底层数组的容量一定要为2的整数次幂,而HashMap则要求一定为2的整数次幂。

Hashtable扩容时,将容量变为原来的2倍加1,而HashMap扩容时,将容量变为原来的2倍。

3.8 TreeSet和HashSet区别

HashSet是采用hash表来实现的。其中的元素没有按顺序排列,add()remove()以及contains()等方法都是复杂度为O(1)的方法。

TreeSet是采用树结构实现(红黑树算法)。元素是按顺序进行排列,但是add()remove()以及contains()等方法都是复杂度为O(log (n))的方法。它还提供了一些方法来处理排序的set,如first(), last(), headSet(), tailSet()等等。

3.9 String buffer和String builder区别

1StringBuffer StringBuilder 中的方法和功能完全是等价的,

2)只是StringBuffer 中的方法大都采用了 synchronized 关键字进行修饰,因此是线程安全的,而 StringBuilder 没有这个修饰,可以被认为是线程不安全的。 

3)在单线程程序下,StringBuilder效率更快,因为它不需要加锁,不具备多线程安全而StringBuffer则每次都需要判断锁,效率相对更低

3.11 什么是 Java 序列化,如何实现 Java 序列化?

序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题。

序 列 化 的 实 现 : 将 需 要 被 序 列 化 的 类 实 现 Serializable 接 口 , 该 接 口 没 有 需 要 实 现 的 方 法 , implements Serializable 只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用 ObjectOutputStream 对象的 writeObject(Object obj)方法就可以将参数为 obj 的对象写出(即保存其状态),要恢复的话则用输入流。

3.12 Object中有哪些方法

(1)protected Object clone()--->创建并返回此对象的一个副本。 
(2)boolean equals(Object obj)--->指示某个其他对象是否与此对象“相等”。 
(3)protected void finalize()--->当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。 
(4)Class<? extendsObject> getClass()--->返回一个对象的运行时类。 
(5)int hashCode()--->返回该对象的哈希码值。 
(6)void notify()--->唤醒在此对象监视器上等待的单个线程。 
(7)void notifyAll()--->唤醒在此对象监视器上等待的所有线程。 
(8)String toString()--->返回该对象的字符串表示。 
(9)void wait()--->导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。 
       void wait(long timeout)--->导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll()方法,或者超过指定的时间量。 
       void wait(long timeout, int nanos)--->导致当前的线程等待,直到其他线程调用此对象的 notify()

3.13线程有几种状态,产生的条件是什么

  1. 新建状态(New) :线程对象被创建后,就进入了新建状态。例如,Thread thread = new Thread()。
    (2)就绪状态(Runnable): 也被称为“可执行状态”。线程对象被创建后,其它线程调用了该对象的start()方法,从而来启动该线程。例如,thread.start()。处于就绪状态的线程,随时可能被CPU调度执行。
    (3)运行状态(Running):线程获取CPU权限进行执行。需要注意的是,线程只能从就绪状态进入到运行状态。
    (4)阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
  1. 等待阻塞 -- 通过调用线程的wait()方法,让线程等待某工作的完成。
  2. 同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态。
  3. 其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

(5)死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

3.14产生死锁的基本条件

产生死锁的原因:
(1) 因为系统资源不足。
(2) 进程运行推进的顺序不合适。
(3) 资源分配不当等。
       如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则
就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。
产生死锁的四个必要条件:
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
       这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。
死锁的解除与预防:
       理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和
解除死锁。所以,在系统设计、进程调度等方面注意如何不让这四个必要条件成立,如何确
定资源的合理分配算法,避免进程永久占据系统资源。此外,也要防止进程在处于等待状态
的情况下占用资源。因此,对资源的分配要给予合理的规划。

3.15什么是线程池,如何使用?

线程池就是事先将多个线程对象放到一个容器中,当使用的时候就不用 new 线程而是直接去池中拿线程即可,节省了开辟子线程的时间,提高的代码执行效率。

在 JDK 的 java.util.concurrent.Executors 中提供了生成多种线程池的静态方法。

ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();

ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(4);

ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(4);

ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();

然后调用他们的 execute 方法即可。

优点:

第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。

第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

3.16 Java自带有哪几种线程池?

1newCachedThreadPool

创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。这种类型的线程池特点是:

工作线程的创建数量几乎没有限制(其实也有限制的,数目为Interger. MAX_VALUE), 这样可灵活的往线程池中添加线程。

If no task is submitted to the thread pool for a long time, that is, if the worker thread is idle for a specified time ( 1 minute by default ) , the worker thread will be terminated automatically. After termination, if you submit a new task, the thread pool will recreate a worker thread.

When using CachedThreadPool , you must pay attention to controlling the number of tasks, otherwise, due to a large number of threads running at the same time, it is likely to cause system paralysis.

2newFixedThreadPool

Create a thread pool with the specified number of worker threads. A worker thread is created whenever a task is submitted, and if the number of worker threads reaches the initial maximum number of thread pools, the submitted task is stored in the pool queue. FixedThreadPool is a typical and excellent thread pool, which has the advantages of improving program efficiency and saving the overhead of creating threads. However, when the thread pool is idle, that is, when there are no runnable tasks in the thread pool, it will not release the worker thread, and it will also occupy certain system resources.

3newSingleThreadExecutor

Create a single-threaded Executor , that is, only create a unique worker thread to execute tasks, it will only use the only worker thread to execute tasks, and ensure that all tasks are executed in the specified order ( FIFO, LIFO, priority ) . If this thread ends abnormally, another one will take its place, guaranteeing sequential execution. The biggest feature of a single worker thread is that tasks are guaranteed to be executed sequentially, and no multiple threads will be active at any given time.

4newScheduleThreadPool

Create a fixed-length thread pool, and support timing and periodic task execution. For example, delay execution for 3 seconds.

3.17 There are several types of streams in Java

3.18 How to convert byte stream to character stream

The conversion of byte input stream to character input stream is realized through InputStreamReader, and the constructor of this class can pass in the InputStream object.

Byte output stream to character output stream is realized through OutputStreamWriter, the constructor of this class can pass in OutputStream object.

3.19 Please write down your 5 most common RuntimeExceptions

(1) java.lang.NullPointerException Null pointer exception; cause: calling an uninitialized object or an object that does not exist.

(2) The class specified by java.lang.ClassNotFoundException could not be found; the cause: the name and path of the class were loaded incorrectly; usually an exception may be thrown when the program tries to load a class through a string.

(3) java.lang.NumberFormatException The conversion of a string to a number is abnormal; the reason: the character data contains non-numeric characters.

(4) java.lang.IndexOutOfBoundsException The array corner mark is out of bounds exception, which often occurs when manipulating array objects.

(5) The java.lang.IllegalArgumentException method is wrong in passing parameters.

(6) java.lang.ClassCastException Data type conversion exception.

3.20 What is the difference between JDK and JRE?

(1) JRE is the Java runtime environment, that is, Java programs must run on JRE, which is the virtual machine that executes Java programs.

(2)JDK是包含JRE的,它比JRE多了一些工具,这些多出来的工具就是让我们程序员来开发Java程序的。

(3)JDK包含JRE,编译器和其他的工具(比如:JavaDoc,Java调试器),可以让开发者开发、编译、执行Java应用程序

(4)JDK面向开发者,JRE面向程序使用者

3.21两个对象的 hashCode()相同,则 equals()也一定为 true,对吗?

(1)两个对象equals相等,则它们的hashcode必须相等,反之则不一定。

(2)两个对象==相等,则其hashcode一定相等,反之不一定成立

3.22final 在 java 中有什么作用?

final作为Java中的关键字可以用于三个地方。用于修饰类、类属性和类方法。

特征:凡是引用final关键字的地方皆不可修改!

(1)修饰类:表示该类不能被继承;

(2)修饰方法:表示方法不能被重写;

(3)修饰变量:表示变量只能一次赋值以后值不能被修改(常量)。

3.23Java 中的 Math.round(-1.5) 等于多少?

Math.round(-1.5)的返回值是-1。四舍五入的原理是在参数上加0.5然后做向下取整

3.24String 属于基础的数据类型吗?

在Java中,数据类型分为引用类型和基本类型,基本类型分为八种

整型byte,short,int,long

浮点型:float,double

字符型:char

Boolean型:boolean

String不是基本的数据类型,是final修饰的java类,是引用类型。

3.25 Java 中操作字符串都有哪些类?它们之间有什么区别?

主要是一下三种:String、StringBuffer、StringBuilder

特别是在项目中。先来看一下这三种操作方式的区别:

String是不可变的对象,对每次对String类型的改变时都会生成一个新的对象,

StringBuffer和StringBuilder是可以改变对象的。

对于操作效率:StringBuilder > StringBuffer > String

对于线程安全:StringBuffer 是线程安全,可用于多线程;

StringBuilder 是非线程安全,用于单线程

不频繁的字符串操作使用 String。反之,StringBuffer 和 StringBuilder 都优于String

所以,如果在项目中需要拼接字符串最好是采用StringBuffer 而非String.

3.26String str="i"与 String str=new String(“i”)一样吗?

不一样,因为内存的分配方式不一样。String str="i"的方式,Java 虚拟机会将其分配到常量池中;而 String str=new String(“i”) 则会被分到堆内存中。

3.28String 类的常用方法都有那些?

indexOf() 返回指定字符得索引

charAt() 返回指定索引处得字符

repalce() 字符串替换

trim() 去除字符串两端的空白

split() 分割字符串 返回分割后的字符串数组

getBytes() 返回字符串的byte类型数组

length() 返回字符串的长度

toLowerCase() 字符串转小写

toUpperCase() 字符串转大写

substring() 截取字符串

equals() 字符串比较

3.29抽象类必须要有抽象方法吗?

抽象类可以没有抽象方法,但是如果你的一个类已经声明成了抽象类,即使这个类中没有抽象方法,它也不能再实例化,即不能直接构造一个该类的对象。

如果一个类中有了一个抽象方法,那么这个类必须声明为抽象类,否则编译通不过。

3.30普通类和抽象类有哪些区别?

普通类不能包含抽象方法,抽象类可以包含抽象方法。

抽象类是不能被实例化的,就是不能用new调出构造方法创建对象,普通类可以直接实例化。

如果一个类继承于抽象类,则该子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类也定义为abstract类。

3.31抽象类能使用 final 修饰吗?

不能,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承,这样彼此就会产生矛盾,所以 final 不能修饰抽象类,如下图所示,编辑器也会提示错误信息。

3.32接口和抽象类有什么区别?

他们都不能实例化对象,都可以包含抽象方法,而且抽象方法必须被继承的类全部实现。

区别:

1、抽象类和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象。

2、抽象类要被子类继承,接口要被类实现。

3、接口只能做方法申明,抽象类中可以做方法申明,也可以做方法实现

4、接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。

5、抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,一个实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类。

6、抽象方法只能申明,不能实现,接口是设计的结果 ,抽象类是重构的结果

7、抽象类里可以没有抽象方法

8、如果一个类里有抽象方法,那么这个类只能是抽象类

9、抽象方法要被实现,所以不能是静态的,也不能是私有的。

10、接口可继承接口,并可多继承接口,但类只能单根继承。

3.33Java 中 IO 流分为几种?

按照流的流向分,可以分为输入流和输出流;

按照操作单元划分,可以划分为字节流和字符流;

按照流的角色划分为节点流和处理流。

Java Io流共涉及40多个类,这些类看上去很杂乱,但实际上很有规则,而且彼此之间存在非常紧密的联系, Java I0流的40多个类都是从如下4个抽象类基类中派生出来的。

InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。

OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。

按操作方式分类结构图:

3.34BIO、NIO、AIO 有什么区别?

1)BIO

在服务端启动一个ServerSocket,然后在客户端启动Socket来对服务端进行通信,默认情况下服务端需要对每个请求建立一堆线程等待请求,而客户端发送请求后,先咨询服务端是否有线程相应,如果没有则会一直等待或者遭到拒绝请求,如果有的话,客户端会线程会等待请求结束后才继续执行。

简单来说,用户进程在发起一个IO操作以后,必须等待IO操作的完成,只有当真正完成了IO操作以后,用户进程才能运行,BIO方式适用于连接数目比较小且固定的架构。

2)NIO

NIO基于Reactor,当socket有流可读或可写入socket时,操作系统会相应的通知引用程序进行处理,应用再将流读取到缓冲区或写入操作系统。 当一个连接创建后,不需要对应一个线程,这个连接会被注册到多路复用器上面,所以所有的连接只需要一个线程就可以搞定,当这个线程中的多路复用器进行轮询的时候,发现连接上有请求的话,才开启一个线程进行处理。

简单来说,用户进程发起一个IO操作以后边可返回做其它事情,但是用户进程需要时不时的询问IO操作是否就绪(引入不必要的CPU资源浪费)

NIO方式适用于连接数目多且连接比较短的架构。

BIO的每个连接一个单独的线程,而NIO则是每个连接共用一个线程。

3)AIO

When there is a stream to read, the operating system will transfer the readable stream to the buffer of the read method and notify the application; for the write operation, when the operating system finishes writing the stream passed by the write method, the operating system Proactively notify applications. The read/write methods are all asynchronous, and the callback function will be called actively after completion. AIO is effectively one thread per request.

To put it simply, the user process only needs to initiate an IO operation and then return immediately. After the IO operation is actually completed, the application will be notified of the completion of the IO operation. There is no need for actual IO read and write operations, because the real IO read or write operations have been completed by the kernel.

The AIO method is used in architectures with a large number of connections and relatively long connections.

3.35 What are the common methods of Files?

Files.exists(): Checks whether the file path exists.

Files.createFile(): Create a file.

Files.createDirectory(): Create a folder.

Files.delete(): Delete a file or directory.

Files.copy(): Copy files.

Files.move(): Move files.

Files.size(): View the number of files.

Files.read(): Read files.

Files.write(): Write to a file.

3.36 What are the Java containers?

as the picture shows

3.37 What is the difference between Collection and Collections?

java.util.Collection is a collection interface (a top-level interface of collection classes). It provides common interface methods for basic operations on collection objects. The Collection interface has many concrete implementations in the Java class library. The significance of the Collection interface is to provide a maximized unified operation method for various specific collections, and its direct inheritance interfaces include List and Set.

Collections is a tool class/helper class of the collection class, which provides a series of static methods for sorting, searching, and thread-safe operations on elements in the collection.

3.38 What is the difference between List, Set, and Map?

3.39说一下 HashSet 的实现原理?

(1)基于HashMap实现的,默认构造函数是构建一个初始容量为16,负载因子为0.75 的HashMap。封装了一个 HashMap 对象来存储所有的集合元素,所有放入 HashSet 中的集合元素实际上由 HashMap 的 key 来保存,而 HashMap 的 value 则存储了一个 PRESENT,它是一个静态的 Object 对象。

(2)当我们试图把某个类的对象当成 HashMap的 key,或试图将这个类的对象放入 HashSet 中保存时,重写该类的equals(Object obj)方法和 hashCode() 方法很重要,而且这两个方法的返回值必须保持一致:当该类的两个的 hashCode() 返回值相同时,它们通过 equals() 方法比较也应该返回 true。通常来说,所有参与计算 hashCode() 返回值的关键属性,都应该用于作为 equals() 比较的标准。

(3)HashSet的其他操作都是基于HashMap的。

3.40如何决定使用 HashMap 还是 TreeMap?

对于在Map中插入、删除和定位元素这类操作,HashMap是最好的选择。然而,假如你需要对一个有序的key集合进行遍历,TreeMap是更好的选择。基于你的collection的大小,也许向HashMap中添加元素会更快,将map换为TreeMap进行有序key的遍历。

3.41如何实现数组和 List 之间的转换?

List转数组:toArray(arraylist.size()方法

数组转List:Arrays的asList(a)方法

3.42哪些集合类是线程安全的?

在集合框架中,有些类是线程安全的,这些都是jdk1.1中的出现的。在jdk1.2之后,就出现许许多多非线程安全的类。 下面是这些线程安全的同步的类:

vector:就比arraylist多了个同步化机制(线程安全),因为效率较低,现在已经不太建议使用。在web应用中,特别是前台页面,往往效率(页面响应速度)是优先考虑的。

statck:堆栈类,先进后出

hashtable:就比hashmap多了个线程安全

enumeration:枚举,相当于迭代器

StringBuffer也是线程安全的,(StringBuilder 不是线程安全的)

除了这些之外,其他的都是非线程安全的类和接口。

线程安全的类其方法是同步的,每次只能一个访问。是重量级对象,效率较低。

3.43 Iterator 怎么使用?有什么特点?

1.Iterator在遍历元素过程中,有线程修改集合元素会有ConcurrentModificationEception异常

2.Iterator本身不具有装载数据功能,需依附Collection对象使用

3.next()是用游标指向的方式返回下一个元素的

3.44Iterator 和 ListIterator 有什么区别?

我们需要知道的第一个则是:

(1)所属关系,ListIterator是一个Iterator的子类型。

(2)局限:只能应用于各种List类的访问。

(3)优势:Iterator只能向前移动,而ListIterator可以双向移动。

还可以产生相对于迭代器在列表中指向的当前位置的前一个和后一个元素的索引

nextIndex()、previousIndex()方法。

还可以通过set()方法替换它访问过的最后一个元素。

还可以通过调用listIterator()方法产生一个指向List开始处的ListIterator,当然也可以有参数,即指向索引为参数处的ListIterator。

(4)ListIterator 有 add() 方法,可以向 List 中添加对象,而 Iterator 不能

3.45创建线程有哪几种方式?

1.继承Thread类实现多线程

2.覆写Runnable()接口实现多线程,而后同样覆写run().推荐此方式

3.覆写Callable接口实现多线程(JDK1.5)

4.通过线程池启动多线程

3.46说一下 runnable 和 callable 有什么区别?

Runnable应该是比较熟悉的接口,它只有一个run()函数,用于将耗时操作写在其中,该函数没有返回值,不能将结果返回给客户程序。然后使用某个线程去执行runnable即可实现多线程,Thread类在调用start()函数后就是执行的是Runnable的run()函数。

Callable与Runnable的功能大致相似,Callable中有一个call()函数,但是call()函数有返回值。

主要区别:

Runnable 接口 run 方法无返回值;Callable 接口 call 方法有返回值,支持泛型

Runnable 接口 run 方法只能抛出运行时异常,且无法捕获处理;Callable 接口 call 方法允许抛出异常,可以获取异常信息

3.47sleep() 和 wait() 有什么区别?

sleep方法:

  属于Thread类中的方法;会导致程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持着,当指定时间到了之后,又会自动恢复运行状态;在调用sleep方法的过程中,线程不会释放对象锁。(只会让出CPU,不会导致锁行为的改变)

wait方法:

  Belongs to the method in the Object class; when calling the wait method, the thread will give up the object lock and enter the waiting lock pool waiting for this object. Only after calling the notify method for this object will the thread enter the object lock pool to prepare. Get the object lock and enter the running state. (Not only give up the CPU, but also release the already occupied synchronization resource lock)

3.48 What is the difference between notify() and notifyAll()?

notify():

Wake up a thread that is in a waiting state,

Note that when calling this method,

It cannot exactly wake up a thread in a waiting state,

Instead, the JVM determines which thread to wake up, and not by priority.

notifyAll():

Wake up all waiting threads;

And can be understood as putting them into a queue;

It's just that only the head thread has acquired the lock before it can run;

Notice! ! Instead of giving all waking threads a lock on an object, let them compete,

When one of the threads finishes running, it starts running the next thread that has been awakened, because the lock has been transferred.

3.49 What is the difference between run() and start() of a thread?

run() method:

  The method is executed in the main thread, just like calling a normal method; (executed sequentially, synchronously)

start() method:

  A new thread is created and executed in the new thread; (asynchronous execution)

3.50 What is the difference between the submit() and execute() methods in the thread pool?

execute() argument Runnable; submit() argument (Runnable) or (Runnable and result T) or (Callable)

execute() has no return value; submit() has a return value

When the return value Future of submit() calls the get method, it can catch and handle exceptions

3.51 How to ensure the safety of multi-threaded operation in java programs?

Thread safety issues are reflected in:

Atomicity: the property that one or more operations are not interrupted during CPU execution

Visibility: when one thread modifies a shared variable, another thread can see it immediately

Orderliness: The order in which the program is executed is executed in the order in which the code is executed

导致原因:

缓存导致的可见性问题

线程切换带来的原子性问题

编译优化带来的有序性问题

解决办法:

JDK Atomic开头的原子类、synchronized、LOCK,可以解决原子性问题

synchronized、volatile、LOCK,可以解决可见性问题

Happens-Before 规则可以解决有序性问题

Happens-Before 规则如下:

程序次序规则:在一个线程内,按照程序控制流顺序,书写在前面的操作先行发生于书写在后面的操作

管程锁定规则:一个unlock操作先行发生于后面对同一个锁的lock操作

volatile变量规则:对一个volatile变量的写操作先行发生于后面对这个变量的读操作

线程启动规则:Thread对象的start()方法先行发生于此线程的每一个动作

线程终止规则:线程中的所有操作都先行发生于对此线程的终止检测

线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生

对象终结规则:一个对象的初始化完成(构造函数执行结束)先行发生于它的finalize()方法的开始

3.52什么是死锁?

所谓死锁,是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进。 因此我们举个例子来描述,如果此时有一个线程A,按照先锁a再获得锁b的的顺序获得锁,而在此同时又有另外一个线程B,按照先锁b再锁a的顺序获得锁。如下图所示:

3.53怎么防止死锁?

预防死锁:

资源一次性分配:一次性分配所有资源,这样就不会再有请求了:(破坏请求条件)

只要有一个资源得不到分配,也不给这个进程分配其他的资源:(破坏请保持条件)

可剥夺资源:即当某进程获得了部分资源,但得不到其它资源,则释放已占有的资源(破坏不可剥夺条件)

资源有序分配法:系统给每类资源赋予一个编号,每一个进程按编号递增的顺序请求资源,释放则相反(破坏环路等待条件)

1、以确定的顺序获得锁

如果必须获取多个锁,那么在设计的时候需要充分考虑不同线程之前获得锁的顺序。按照上面的例子,两个线程获得锁的时序图如下:

那么死锁就永远不会发生。 针对两个特定的锁,开发者可以尝试按照锁对象的hashCode值大小的顺序,分别获得两个锁,这样锁总是会以特定的顺序获得锁,那么死锁也不会发生。问题变得更加复杂一些,如果此时有多个线程,都在竞争不同的锁,简单按照锁对象的hashCode进行排序(单纯按照hashCode顺序排序会出现“环路等待”),可能就无法满足要求了,这个时候开发者可以使用银行家算法,所有的锁都按照特定的顺序获取,同样可以防止死锁的发生,该算法在这里就不再赘述了,有兴趣的可以自行了解一下。

2、超时放弃

当使用synchronized关键词提供的内置锁时,只要线程没有获得锁,那么就会永远等待下去,然而Lock接口提供了boolean tryLock(long time, TimeUnit unit) throws InterruptedException方法,该方法可以按照固定时长等待锁,因此线程可以在获取锁超时以后,主动释放之前已经获得的所有的锁。通过这种方式,也可以很有效地避免死锁。 还是按照之前的例子,时序图如下:

避免死锁:

预防死锁的几种策略,会严重地损害系统性能。因此在避免死锁时,要施加较弱的限制,从而获得 较满意的系统性能。由于在避免死锁的策略中,允许进程动态地申请资源。因而,系统在进行资源分配之前预先计算资源分配的安全性。若此次分配不会导致系统进入不安全的状态,则将资源分配给进程;否则,进程等待。其中最具有代表性的避免死锁算法是银行家算法。

Banker's Algorithm: First, you need to define the concepts of state and security state. The state of the system is the current allocation of resources to the process. Therefore, the state contains two vectors Resource (the total amount of each resource in the system) and Available (the total amount of each resource not allocated to the process) and two matrices Claim (representing the process's demand for resources) and Allocation (representing resources currently allocated to the process). A safe state is one in which at least one sequence of resource allocations does not result in a deadlock. When a process requests a set of resources, assume that the request is granted, thereby changing the state of the system, and then determine whether the result is still in a safe state. If yes, grant the request; if not, block the process until the state of the system remains safe after granting the request.

3.54 What is the difference between synchronized and volatile?

1) volatile is more lightweight than synchronized.

2) volatile is not widely used as synchronized.

3) Volatile does not require locking, is lighter than synchronized, and will not block threads.

4) From the perspective of memory visibility, volatile reading is equivalent to locking, and volatile writing is equivalent to unlocking.

5) synchronized can guarantee both visibility and atomicity, while volatile can only guarantee visibility and cannot guarantee atomicity.

6) volatile itself does not guarantee the atomicity of get and set operations, but only maintains the visibility of modifications. But Java's memory model guarantees that the get and set operations of long and double variables declared as volatile are atomic.

3.55 What is the difference between synchronized and Lock?

3.56 What is the difference between synchronized and ReentrantLock?

Basic meaning : Synchronized is a keyword in the Java language, so the synchronized lock is a mutual exclusion at the native syntax level, which needs to be implemented by the JVM. Specifically, it is implemented through an object called a monitor lock (monitor). ReentrantLock, which literally means reentrant lock, is an API-level mutex provided after JDK1.5. The lock function is mainly completed by two methods, namely lock() and unlock().

Ease of use : The use of Synchronized is more convenient and concise, and the compiler guarantees the lock and release of the lock, while ReentrantLock needs to manually write code to lock and release the lock.
Note: In order to avoid deadlock caused by forgetting to manually release the lock, it is best to declare the release lock in finally.

Flexibility : ReentrantLock is better than Synchronized, and can flexibly control where to lock and unlock.

performance difference

When we usually write code, the lock that Java uses the most is Synchronized, and the lock seen in the singleton mode is also Synchronized. Why is this? In addition to the use of Synchronized, in fact, compared with ReentrantLock, the performance is not inferior at all. Of course, it is the version after JDK1.5.

The previous version of JDK1.6 was not optimized, and it must be much worse than ReentrantLock at this time. After optimization, Synchronized introduces bias locks, lightweight locks, etc., so that the performance is almost the same as that of ReentrantLock.

3.57 What is reflection?

The Java reflection mechanism is in the running state. For any class, you can get all the properties and methods of this class, and you can call any of its properties and methods for any object. This function of dynamically obtaining information and dynamically calling object methods at runtime is called Java's reflection mechanism.

Class 类与java.lang.reflect 类库一起对反射的概念进行了支持,该类库包含了Field,Method,Constructor类(每个类都实现了Member 接口)。这些类型的对象时由JVM 在运行时创建的,用以表示未知类里对应的成员。

这样就可以使用Constructor 创建新的对象,用get() 和set() 方法读取和修改与Field 对象关联的字段,用invoke() 方法调用与Method 对象关联的方法。另外,还可以调用getFields() getMethods() 和 getConstructors() 等很便利的方法,以返回表示字段,方法,以及构造器的对象的数组。这样匿名对象的信息就能在运行时被完全确定下来,而在编译时不需要知道任何事情。

3.58动态代理是什么?有哪些应用?

动态代理是运行时动态生成代理类。 动态代理的应用有 spring aop、hibernate 数据查询、测试框架的后端 mock、rpc,Java注解对象获取等。

3.59深拷贝和浅拷贝区别是什么?

浅拷贝:创建一个新对象,然后将当前对象的非静态字段复制到该新对象,如果字段是值类型的,那么对该字段执行复制;如果该字段是引用类型的话,则复制引用但不复制引用的对象。因此,原始对象及其副本引用同一个对象。

深拷贝:创建一个新对象,然后将当前对象的非静态字段复制到该新对象,无论该字段是值类型的还是引用类型,都复制独立的一份。当你修改其中一个对象的任何内容时,都不会影响另一个对象的内容。

3.60throw 和 throws 的区别?

throw:

(1)throw 语句用在方法体内,表示抛出异常,由方法体内的语句处理。

(2)throw 是具体向外抛出异常的动作,所以它抛出的是一个异常实例,执行 throw 一定是抛出了某种异常。

throws:

(1) The throws statement is used after the method declaration, indicating that if an exception is thrown, the caller of the method will handle the exception.

(2) throws mainly declares that this method will throw a certain type of exception, so that its users need to know the type of exception that needs to be caught.

(3) Throws indicates a possibility of an exception, which does not necessarily occur.

3.61 What is the difference between final, finally, and finalize?

1、final

Final can be used for member variables (including method parameters), methods, and classes.

Final member

 as a variable

Once a variable is initialized, it cannot be changed (for basic types, it means that the value does not change; for object types, it means that the reference does not change), and initialization is only possible in two places: definition and constructor.

as a method parameter

For the basic type, it is meaningless to define it as a final parameter, because the basic type is passed by value and will not affect the variables in the calling statement; for the object type, if the parameter does not need to be changed in the method, it can be defined as a final parameter to prevent the method Inadvertent modification in the method affects the calling method.

final method

not overwritable

The compiler converts the call to this method into an inline (inline) call, that is, directly inserts the method body into the calling place (when the method body has too much content, it will affect the efficiency instead)

Final class

not inheritable

2、finally

Exception handling keywords, the body in finally will always be executed, no matter whether an exception occurs or not. It is usually placed after try...catch to construct the final execution code block, which means that whether the program is executed normally or an exception occurs, the code here can be executed as long as the JVM is not closed, and the code for releasing external resources can be written in the finally block.

2.1. Execution order when there is return in try

The return statement is not the final exit of the function. If there is a finally statement, it will execute finally after return (the value of return will be temporarily stored in the stack, waiting for finally to execute before returning)

2.2, the position of return and exception acquisition statement

3、finalize

The Finalize method of the class, which can tell the garbage collector what to do, is inherited from the Object class. Before an object is permanently removed from the heap, the garbage collector calls the object's Finalize method. Note that there is no guarantee of exactly when the garbage collector will call this method, nor the order in which methods of different objects are called. Even if one object contains a reference to the other object, or the other object is released long before one object is released, the Finalize methods of both objects may be called in any order. If you must guarantee a specific order, you must provide your own unique cleanup methods.

3.64 What is the difference between CyclicBarrier and CountDownLatch in Java?

1. A thread of CyclicBarrier stops running after running to a certain point, and all threads will not run again until all threads reach the same point;

 After the CountDownLatch thread runs to a certain point, the count value is -1, and the thread continues to run until the count value is 0, then it stops running;

2. CyclicBarrier can only wake up one task; CountDownLatch can wake up multiple tasks;

3. CyccliBarrier can be reused, but CountDownLatch cannot be reused. When the count value is 0, CountDownLatch cannot be reused.

3.65 Why is Synchronized a pessimistic lock? What is the implementation principle of optimistic lock? What is CAS and what are its characteristics?

Synchronized is obviously a pessimistic lock, because its concurrency strategy is pessimistic: regardless of whether there will be competition, any data operation must be locked, user-mode core state conversion, maintenance of lock counters and checking whether there is a need for blocked threads be woken up and so on.

With the development of hardware instruction sets, we can use optimistic concurrency strategies based on conflict detection. Perform the operation first, and if no other thread requisitions the data, the operation is successful; if the shared data is requisitioned and a conflict occurs, then other compensation measures will be taken. Many implementations of this optimistic concurrency strategy do not require thread suspension, so are called non-blocking synchronization.

The core algorithm of optimistic locking is CAS (Compare and Swap, compare and exchange), which involves three operands: memory value, expected value, and new value. Modify the memory value to the new value if and only if the expected value and the memory value are equal. The logic of this processing is to first check whether the value of a certain memory is the same as when I read it before. If it is not the same, it means that the memory value has been changed by other threads during the period, and this operation is discarded. Otherwise, there is no other during the period. The thread operates on this memory value, and can set a new value to this block of memory.

CAS is atomic, and its atomicity is guaranteed by CPU hardware instructions, that is, using JNI to call Native methods to call hardware-level instructions written in C++, and the Unsafe class is provided in JDK to perform these operations.

3.66 What is Semaphore in Java?

Semaphore in Java is a new synchronization class which is a counting semaphore. Conceptually, a semaphore maintains a collection of permissions. Each acquire() blocks until a permit is available, and then acquires the permit, if necessary. Each release() adds a permit, potentially releasing a blocking acquirer. However, instead of using actual permit objects, the Semaphore just counts the number of available permits and acts accordingly. Semaphores are often used in multi-threaded code, such as database connection pools.

3.67 Now there are three threads T1, T2, and T3. How do you ensure that T2 is executed after T1 is executed, and T3 is executed after T2 is executed?

There are many ways to make threads execute in a specific order in multithreading. You can use the join() method of the thread class to start another thread in one thread, and the other thread will continue to execute after completing the thread. To ensure the order of the three threads you should start the last one first (T3 calls T2, T2 calls T1), so that T1 will finish first and T3 will finish last.

3.68 How do you get a thread stack in Java?

Java虚拟机提供了线程转储(thread dump)的后门,通过这个后门可以把线程堆栈打印出来。通常我们将堆栈信息重定向到一个文件中,便于我们分析,由于信息量太大,很可能超出控制台缓冲区的最大行数限制造成信息丢失。这里介绍一个jdk自带的打印线程堆栈的工具,jstack用于打印出给定的Java进程ID或core file或远程调试服务的Java堆栈信息。

示例:$jstack –l 23561 >> xxx.dump 

命令 : $jstack [option] pid >> 文件  

>>表示输出到文件尾部,实际运行中,往往一次dump的信息,还不足以确认问题,建议产生三次dump信息,如果每次dump都指向同一个问题,我们才确定问题。

3.69提交任务时线程池队列已满会时发会生什么?

这个问题问得很狡猾,许多程序员会认为该任务会阻塞直到线程池队列有空位。但是最大线程数没有满的话,就会新建一个非核心线程去执行该任务。如果核心线程数、阻塞队列、最大线程数都满了的话,就会执行线程池的拒绝策略,如果一个任务不能被调度执行那么ThreadPoolExecutor’s submit()方法将会抛出一个RejectedExecutionException异常

3.70什么是乐观锁和悲观锁?

乐观锁总是认为不会产生并发问题,每次去取数据的时候总认为不会有其他线程对数据进行修改,因此不会上锁,但是在更新时会判断其他线程在这之前有没有对数据进行修改,一般会使用版本号机制或CAS操作实现。

乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。

悲观锁顾名思义,就是很悲观,总是假设最坏的情况,每次取数据时都认为其他线程会修改,所以都会加锁(读锁、写锁、行锁等),当其他线程想要访问数据时,都需要阻塞挂起。可以依靠数据库实现,如行锁、读锁和写锁等,都是在操作之前加锁,在Java中,synchronized的思想也是悲观锁。

第4章 JVM

4.1 JVM内存分哪几个区,每个区的作用是什么?

 

java虚拟机主要分为以下几个区:

(1)方法区

  1. 有时候也成为永久代,在该区内很少发生垃圾回收,但是并不代表不发生GC,在这里进行的GC主要是对方法区里的常量池和对类型的卸载
  2. 方法区主要用来存储已被虚拟机加载的类的信息、常量、静态变量和即时编译器编译后的代码等数据。
  3. 该区域是被线程共享的。
  4. 方法区里有一个运行时常量池,用于存放静态编译产生的字面量和符号引用。该常量池具有动态性,也就是说常量并不一定是编译时确定,运行时生成的常量也会存在这个常量池中。

(2)虚拟机栈:

  1. 虚拟机栈也就是我们平常所称的栈内存,它为java方法服务,每个方法在执行的时候都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接和方法出口等信息。
  2. 虚拟机栈是线程私有的,它的生命周期与线程相同。
  3. 局部变量表里存储的是基本数据类型、returnAddress类型(指向一条字节码指令的地址)和对象引用,这个对象引用有可能是指向对象起始地址的一个指针,也有可能是代表对象的句柄或者与对象相关联的位置。局部变量所需的内存空间在编译器间确定
  4. 操作数栈的作用主要用来存储运算结果以及运算的操作数,它不同于局部变量表通过索引来访问,而是压栈和出栈的方式
  5. 每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接.动态链接就是将常量池中的符号引用在运行期转化为直接引用。

(3)本地方法栈
本地方法栈和虚拟机栈类似,只不过本地方法栈为Native方法服务。

(4)堆

java堆是所有线程所共享的一块内存,在虚拟机启动时创建,几乎所有的对象实例都在这里创建,因此该区域经常发生垃圾回收操作。

(5)程序计数器:

内存空间小,字节码解释器工作时通过改变这个计数值可以选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理和线程恢复等功能都需要依赖这个计数器完成。该内存区域是唯一一个java虚拟机规范没有规定任何OOM情况的区域。

4.2 heap 和stack 有什么区别

(1)申请方式

stack:由系统自动分配。例如,声明在函数中一个局部变量 int b; 系统自动在栈中为 b 开辟空间

heap:需要程序员自己申请,并指明大小,在 c 中 malloc 函数,对于Java 需要手动 new Object()的形式开辟

(2)申请后系统的响应

stack:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。

heap : First of all, you should know that the operating system has a linked list that records free memory addresses. When the system receives an application from a program, it will traverse the linked list to find the first heap node whose space is larger than the requested space, and then remove the node from the Delete the free node linked list, and allocate the space of the node to the program. In addition, since the size of the found heap node is not necessarily exactly equal to the requested size, the system will automatically put the redundant part back into the free list.

(3 ) Application size limit

stack : The stack is a data structure that expands to low addresses and is a continuous memory area. This sentence means that the address of the top of the stack and the maximum capacity of the stack are predetermined by the system. Under WINDOWS, the size of the stack is 2M (some say it is 1M , in short, it is a constant determined at compile time), if When the requested space exceeds the remaining space of the stack, overflow will be prompted . Therefore, less space can be obtained from the stack.

heap : The heap is a data structure that expands to high addresses and is a discontinuous memory area. This is because the system uses a linked list to store free memory addresses, which are naturally discontinuous, and the traversal direction of the linked list is from low address to high address. The size of the heap is limited by the virtual memory available on the computer system. It can be seen that the space obtained by the heap is more flexible and larger.

(4 ) Comparison of application efficiency

stack : automatically allocated by the system, the speed is faster. But the programmer is out of control.

heap : The memory allocated by new is generally slow and prone to memory fragmentation, but it is the most convenient to use.

(5 ) Storage content in heap and stack

stack:在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址, 然后是函数的各个参数,在大多数的 C 编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。

当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。

heap:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。

4.3 java类加载过程?

Java类加载需要经历一下几个过程:

(1)加载

加载时类加载的第一个过程,在这个阶段,将完成一下三件事情:

  1. 通过一个类的全限定名获取该类的二进制流。
  2. 将该二进制流中的静态存储结构转化为方法去运行时数据结构。 
  3. 在内存中生成该类的Class对象,作为该类的数据访问入口。

(2)验证

验证的目的是为了确保Class文件的字节流中的信息不回危害到虚拟机.在该阶段主要完成以下四钟验证:

  1. 文件格式验证:验证字节流是否符合Class文件的规范,如主次版本号是否在当前虚拟机范围内,常量池中的常量是否有不被支持的类型.
  2. 元数据验证:对字节码描述的信息进行语义分析,如这个类是否有父类,是否集成了不被继承的类等。
  3. 字节码验证:是整个验证过程中最复杂的一个阶段,通过验证数据流和控制流的分析,确定程序语义是否正确,主要针对方法体的验证。如:方法中的类型转换是否正确,跳转指令是否正确等。
  4. 符号引用验证:这个动作在后面的解析过程中发生,主要是为了确保解析动作能正确执行。
  5. 准备

准备阶段是为类的静态变量分配内存并将其初始化为默认值,这些内存都将在方法区中进行分配。准备阶段不分配类中的实例变量的内存,实例变量将会在对象实例化时随着对象一起分配在Java堆中。

(3)解析

该阶段主要完成符号引用到直接引用的转换动作。解析动作并不一定在初始化动作完成之前,也有可能在初始化之后。

(4)初始化

初始化时类加载的最后一步,前面的类加载过程,除了在加载阶段用户应用程序可以通过自定义类加载器参与之外,其余动作完全由虚拟机主导和控制。到了初始化阶段,才真正开始执行类中定义的Java程序代码。

4.4 什么是类加载器,类加载器有哪些?

实现通过类的权限定名获取该类的二进制字节流的代码块叫做类加载器。

主要有一下四种类加载器:

(1)启动类加载器(Bootstrap ClassLoader)用来加载java核心类库,无法被java程序直接引用。

(2)扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。

(3)系统类加载器(system class loader)也叫应用类加载器:它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader()来获取它。

(4)用户自定义类加载器,通过继承 java.lang.ClassLoader类的方式实现。

4.5 java中垃圾收集的方法有哪些?

1)引用计数法   应用于:微软的COM/ActionScrip3/Python等

a) 如果对象没有被引用,就会被回收,缺点:需要维护一个引用计算器

2 ) Copying algorithm  Minor GC is used in the young generation, and this GC algorithm uses the copying algorithm (Copying)

a)  High efficiency, disadvantages: large memory capacity is required, which consumes more memory

b)  It is used in the new area that occupies a relatively small space and has a large number of refresh times

3 ) Mark clearing  the old generation is generally implemented by mark clearing or a mixture of mark clearing and mark finishing

a)  The efficiency is relatively low, and it will cause poor debris.

4 ) Mark compression  in the old generation is generally implemented by mark clearing or a mixture of mark clearing and mark finishing

a)  Low efficiency and slow speed, need to move objects, but will not generate fragments.

5 ) Mark clearing and compacting Mark clearing-marking and compacting collections, Compact after multiple GCs

a)  It is used in retirement areas that take up a lot of space and have few refresh times. It is a collection of 3+4

4.6 How to judge whether an object is alive? (or the method of judging GC objects)

There are two ways to determine whether an object is alive:

(1 ) Reference counting method

The so-called reference counting method is to set a reference counter for each object. Whenever there is a reference to this object, the counter is incremented by one, and when the reference becomes invalid, the counter is decremented by one. When the reference counter of an object is zero, it means that the object is not referenced, that is, "dead object", and will be garbage collected.

One defect of the reference counting method is that it cannot solve the problem of circular references. That is to say, when object A refers to object B, and object B refers to object A, then the reference counters of A and B objects are not zero at this time, which results in failure. Complete garbage collection, so mainstream virtual machines do not use this algorithm.

(2 ) Reachability algorithm ( reference chain method)

The basic idea of ​​the algorithm is to use some objects called reference chains ( GC Roots ) as the starting point, and start searching downwards from these nodes. The search path is called ( Reference Chain) . When an object arrives at GC Roots without When any reference chain is connected (that is, from the GC Roots node to the node is not reachable), it proves that the object is not available.

Objects that can be used as GC Roots in java include the following types: objects referenced in the virtual machine stack, objects referenced by class static properties in the method area, objects referenced by the constant pool in the method area, and objects referenced by the local method stack JNI.

4.7 Briefly describe java memory allocation and recovery strategies, Minor GC and Major GC (full GC)

memory allocation:

(1 ) Stack area : the stack is divided into java virtual machine stack and local method stack

(2 ) Heap area : The heap is an area shared by all threads, created when the virtual machine starts, and the sole purpose is to store object instances. The heap area is the main area of ​​GC, and is usually divided into two blocks, the young generation and the old generation. A little more detail, the young generation is divided into the Eden area, which mainly stores newly created objects. From Survivor and To Survivor save the objects that survived the GC. By default, the respective ratios are 8:1:1.

(3 ) Method area : an area shared by all threads, used to store class information, constants, static variables and other data that have been loaded by the virtual machine. Described by the Java virtual machine as a logical part of the heap. It is customary to also call it the permanent generation (permanment generation)

(4 ) Program counter : The line number indicator executed by the current thread. The next instruction is determined by changing the value of the counter, such as loops, branches, jumps, exception handling, thread recovery, etc., all rely on the counter to complete. thread-private.

Recycling strategy and Minor GC and Major GC :

(1) Objects are allocated in the Eden area of ​​the heap first.

(2) Large objects enter the old age directly.

(3) Long-term surviving objects will directly enter the old age.

When the Eden area does not have enough space for allocation, the virtual machine executes a Minor GC. Minor GC usually occurs in the Eden area of ​​the new generation. Objects in this area have a short lifetime, and the frequency of GC is often high, and the recovery speed is relatively fast. ;Full GC/Major GC occurs in the old generation. Under normal circumstances, Minor GC is not triggered when the old generation GC is triggered. However, through configuration, a Minor GC can be performed before the Full GC, which can speed up the recycling speed of the old generation.

4.8 Under what circumstances will stack memory overflow occur.

The stack is private to the thread, and its life cycle is the same as that of the thread. Each method will create a stack frame when it is executed, which is used to store local variable table, operand stack, dynamic link, method exit and other information. The local variable table also contains basic data types, object reference types

If the stack depth requested by the thread is greater than the maximum depth allowed by the virtual machine, a StackOverflowError exception will be thrown, and the method recursive call will produce this result.

If the Java virtual machine stack can be dynamically expanded, and the expansion action has been tried, but cannot apply for enough memory to complete the expansion, or there is not enough memory to create the corresponding virtual machine stack when a new thread is created, then the Java virtual machine The machine will throw an OutOfMemory exception. (too many threads started)

Parameter -Xss to adjust the size of the JVM stack

4.9 What is a complete GC process in the JVM, and how objects are promoted to the old generation

对象诞生即新生代->eden,在进行minor gc过程中,如果依旧存活,移动到from,变成Survivor,进行标记。当一个对象存活默认超过15次都没有被回收掉,就会进入老年代。

4.10你知道哪几种垃圾收集器,各自的优缺点,重点讲下cms和G1,包括原理,流程,优缺点。

垃圾收集器包括Serial、parNew、ParallelScavenge、SerialOld、ParallelOld、CMS、G1

CMS:

一、初始标记:此时标记需要用户线程停下来;

二、并发标记:此时标记可以和用户线程一起运行;

三、重新标记:此时标记需要用户线程停下来,主要母的是为了对并发标记的垃圾进行审核;

四、并发清除:与用户线程一起与运行进行垃圾清除;

缺点:

     1、CMS收集器对cpu资源非常敏感;

     2、CMS收集器无法清除浮动垃圾;

     3、cms基于标记清除的算法实现的,所以内存碎片会产生过多。

G1收集器:

    1、初始标记:标记GC Root能直接关联的对象,并且修改TAMS的值,让下一阶段的用户进行并发运行是,能够正确运用Region创建新对象,这阶段需要停顿,但停顿时间很短

   2、并发标记:从GC Root开始对堆进行可达性分析,找出存活的对象,这段耗时较长,但可以与用户线程并发执行。

    3、最终标记是为了修正在并发标记阶段因用户程序继续运作导致标记产生变动的那一部分的标记记录,虚拟机将这部分标记记录在线程Remembered Set中,这阶段需要停顿线程,但是可并行执行。

   4、筛选回收:首先对各个Region的回收价值和成本进行排序,根据用户所期待的GC停顿时间来制定回收计划,这个阶段也可以与用户线程并行执行,但由于只回收一部分的Region,时间是用户可控制的,而且停顿用户线程将大幅度提高收集效率。

4.11 JVM内存模型的相关知识了解多少,比如重排序,内存屏障,happen-before,主内存,工作内存。

重排序:jvm虚拟机允许在不影响代码最终结果的情况下,可以乱序执行。

内存屏障:可以阻挡编译器的优化,也可以阻挡处理器的优化

happens-before原则:

1:一个线程的A操作总是在B之前,那多线程的A操作肯定实在B之前。

2:monitor 再加锁的情况下,持有锁的肯定先执行。

3:volatile修饰的情况下,写先于读发生

4:线程启动在一起之前 strat

5:线程死亡在一切之后 end

6:线程操作在一切线程中断之前

7:一个对象构造函数的结束都该对象的finalizer的开始之前

8:传递性,如果A肯定在B之前,B肯定在C之前,那A肯定是在C之前。

主内存:所有线程共享的内存空间

工作内存:每个线程特有的内存空间

4.12简单说说你了解的类加载器,可以打破双亲委派么,怎么打破。

1) 什么是类加载器?

类加载器 就是根据指定全限定名称将class文件加载到JVM内存,转为Class对象。

启动类加载器(Bootstrap ClassLoader):由C++语言实现(针对HotSpot),负责将存放在<JAVA_HOME>\lib目录或-Xbootclasspath参数指定的路径中的类库加载到内存中。

其他类加载器:由Java语言实现,继承自抽象类ClassLoader。如:

扩展类加载器(Extension ClassLoader):负责加载<JAVA_HOME>\lib\ext目录或java.ext.dirs系统变量指定的路径中的所有类库。

应用程序类加载器(Application ClassLoader)。负责加载用户类路径(classpath)上的指定类库,我们可以直接使用这个类加载器。一般情况,如果我们没有自定义类加载器默认就是用这个加载器。

2)双亲委派模型

双亲委派模型工作过程是:

如果一个类加载器收到类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器完成。每个类加载器都是如此,只有当父加载器在自己的搜索范围内找不到指定的类时(即ClassNotFoundException),子加载器才会尝试自己去加载。

双亲委派模型图:

3)为什么需要双亲委派模型?

在这里,先想一下,如果没有双亲委派,那么用户是不是可以自己定义一个java.lang.Object的同名类,java.lang.String的同名类,并把它放到ClassPath中,那么类之间的比较结果及类的唯一性将无法保证,因此,为什么需要双亲委派模型?防止内存中出现多份同样的字节码

4)怎么打破双亲委派模型?

打破双亲委派机制则不仅要继承ClassLoader类,还要重写loadClass和findClass方法。

4.13说说你知道的几种主要的JVM参数

1)堆栈配置相关

java -Xmx3550m -Xms3550m -Xmn2g -Xss128k

-XX:MaxPermSize=16m -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxTenuringThreshold=0

-Xmx3550m: 最大堆大小为3550m。

-Xms3550m: 设置初始堆大小为3550m。

-Xmn2g: 设置年轻代大小为2g。

-Xss128k: 每个线程的堆栈大小为128k。

-XX:MaxPermSize: 设置持久代大小为16m

-XX:NewRatio=4: 设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)。

-XX:SurvivorRatio=4: 设置年轻代中Eden区与Survivor区的大小比值。设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6

-XX:MaxTenuringThreshold=0: 设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。

2)垃圾收集器相关

-XX:+UseParallelGC

-XX:ParallelGCThreads=20

-XX:+UseConcMarkSweepGC

-XX:CMSFullGCsBeforeCompaction=5

-XX:+UseCMSCompactAtFullCollection:

-XX:+UseParallelGC: 选择垃圾收集器为并行收集器。

-XX:ParallelGCThreads=20: 配置并行收集器的线程数

-XX:+UseConcMarkSweepGC: 设置年老代为并发收集。

-XX:CMSFullGCsBeforeCompaction:由于并发收集器不对内存空间进行压缩、整理,所以运行一段时间以后会产生“碎片”,使得运行效率降低。此值设置运行多少次GC以后对内存空间进行压缩、整理。

-XX:+UseCMSCompactAtFullCollection: 打开对年老代的压缩。可能会影响性能,但是可以消除碎片

3)辅助信息相关

-XX:+PrintGC

-XX:+PrintGCDetails

-XX:+PrintGC 输出形式:

[GC 118250K->113543K(130112K), 0.0094143 secs] [Full GC 121376K->10414K(130112K), 0.0650971 secs]

-XX:+PrintGCDetails 输出形式:

[GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs] [GC [DefNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured: 112761K->10414K(121024K), 0.0433488 secs] 121376K->10414K(130112K), 0.0436268 secs

4.15垃圾收集算法

jvm的垃圾回收算法有3种,列举如下:

1,标记清除算法。(即把标注的可回收对象直接清理,这样会带来内存碎片化的问题,而且效率不高);

2,标记整理算法。(即把标注的可回收对象清理,在清理的过程中整理内存,解决了内存的碎片化问题);

3,标记复制算法。(把标注的对象清理,没有清理的对象复制到to区,然后互换引用,解决了内存碎片化的问题,但是需要维护对象关系带来一定代价)

4.16调优工具用过哪些

常用调优工具分为两类,jdk自带监控工具:jconsole和jvisualvm,第三方有:MAT(Memory Analyzer Tool)、GChisto。

jconsole,Java Monitoring and Management Console是从java5开始,在JDK中自带的java监控和管理控制台,用于对JVM中内存,线程和类等的监控jvisualvm,jdk自带全能工具,可以分析内存快照、线程快照;监控内存变化、GC变化等。MAT,Memory Analyzer Tool,一个基于Eclipse的内存分析工具,是一个快速、功能丰富的Java heap分析工具,它可以帮助我们查找内存泄漏和减少内存消耗

GChisto,一款专业分析gc日志的工具

4.17 Which JVM performance tuning do you know

The first thing to note is that when tuning the JVM memory, you can’t just look at the memory occupied by the Java process at the operating system level. This value cannot accurately reflect the real occupancy of the reactor memory, because this value will not change after the GC, so When tuning memory, use more memory viewing tools provided by JDK, such as JConsole and Java VisualVM.

  The main purpose of system-level tuning of JVM memory is to reduce the frequency of GC and the number of times of Full GC. Excessive GC and Full GC will occupy a lot of system resources (mainly CPU) and affect the throughput of the system. Pay special attention to Full GC, because it will organize the entire heap, resulting in Full GC generally due to the following situations:

Insufficient space in the old generation

  When tuning, try to let the object be recycled in the new generation GC, let the object survive for a longer period of time in the new generation, and do not create too large objects and arrays to avoid directly creating objects in the old generation

Insufficient space for Pemanet Generation

  Increase Perm Gen space to avoid too many static objects

  The average size of promotion to the old generation after GC statistics obtained is greater than the remaining space of the old generation

  Control the ratio of the new generation to the old generation

System.gc() is called explicitly

  Do not manually trigger garbage collection, try to rely on the JVM's own mechanism

The tuning method is mainly realized by controlling the proportion of each part of the heap memory and the GC strategy. Let's take a look at the consequences of bad proportion settings of each part.

1). The new generation setting is too small

  One is that the number of GCs in the new generation is very frequent, which increases system consumption; the other is that large objects directly enter the old generation, occupying the remaining space of the old generation, and inducing Full GC

2). The setting of the new generation is too large

  One is that the new generation is set too large and the old generation is too small (the total amount of the heap is constant), which induces Full GC; the other is that the time spent on the new generation GC increases significantly

  Generally speaking, it is more appropriate for the new generation to occupy 1/3 of the entire heap.

3). Survivor setting is too small

  Causes objects to directly reach the old generation from eden, reducing the survival time in the new generation

4). Survivor is set too large

  Causes eden to be too small, increasing GC frequency

  In addition, use -XX:MaxTenuringThreshold=n to control the survival time of the new generation, and try to let the objects be recycled in the new generation

由内存管理和垃圾回收可知新生代和旧生代都有多种GC策略和组合搭配,选择这些策略对于我们这些开发人员是个难题,JVM提供两种较为简单的GC策略的设置方式

1). 吞吐量优先

  JVM以吞吐量为指标,自行选择相应的GC策略及控制新生代与旧生代的大小比例,来达到吞吐量指标。这个值可由-XX:GCTimeRatio=n来设置

2). 暂停时间优先

  JVM以暂停时间为指标,自行选择相应的GC策略及控制新生代与旧生代的大小比例,尽量保证每次GC造成的应用停止时间都在指定的数值范围内完成。这个值可由-XX:MaxGCPauseRatio=n来设置

4.18 Eden和Survivor的比例分配等

默认比例8:1。部分对象都是朝生夕死。 复制算法的基本思想就是将内存分为两块,每次只用其中一块,当这一块内存用完,就将还活着的对象复制到另外一块上面。复制算法不会产生内存碎片。

4.19说一说你对环境变量classpath的理解?如果一个类不在classpath下,为什么会抛出ClassNotFoundException异常,如果在不改变这个类路径的前期下,怎样才能正确加载这个类?

classpath是javac编译器的一个环境变量。它的作用与import、package关键字有关。package的所在位置,就是设置CLASSPATH当编译器面对import packag这个语句时,它先会查找CLASSPATH所指定的目录,并检视子目录java/util是否存在,然后找出名称吻合的已编译文件(.class文件)。如果没有找到就会报错!

动态加载包

 设计模式

5.1你所知道的设计模式有哪些

Java 中一般认为有 23 种设计模式,我们不需要所有的都会,但是其中常用的几种设计模式应该去掌握。下面列出了所有的设计模式。需要掌握的设计模式我单独列出来了,当然能掌握的越多越好。

总体来说设计模式分为三大类:

There are five creational patterns: factory method pattern, abstract factory pattern, singleton pattern, builder pattern, and prototype pattern.

There are 7 structural modes: adapter mode, decorator mode, proxy mode, appearance mode, bridge mode, combination mode, flyweight mode.

There are 11 behavioral patterns: strategy pattern, template method pattern, observer pattern, iterative sub-pattern, chain of responsibility pattern, command pattern, memo pattern, state pattern, visitor pattern, mediator pattern, and interpreter pattern.

5.2 Singleton design pattern

See [Chapter 2 Handwritten Code 2.5]

5.3 Factory design pattern (Factory)

5.3.1 What is the factory design pattern?

The factory design pattern, as the name suggests, is used to produce objects. In java, everything is an object, and these objects need to be created. If the object is directly new when it is created, it will be severely coupled to the object. If we want to replace the object, All new objects need to be modified again, which obviously violates the open-close principle of software design. If we use the factory to produce objects, we can only deal with the factory, which is completely decoupled from the object. If we want to replace the object, Just replace the object directly in the factory, achieving the purpose of decoupling from the object; therefore, the biggest advantage of the factory model is: decoupling

5.3.2 Simple Factory

definition:

A factory method generates corresponding product objects according to the parameters passed in;
roles:
1. Abstract product
2. Concrete product
3. Concrete factory
4. Product user
instructions:

First abstract the product category. For example, both apples and pears belong to fruits, abstract a fruit category Fruit, and apples and pears are specific product categories, and then create a fruit factory to create apples and pears respectively. code show as below:

Fruit interface:

  1. public interface Fruit {  
  2.     void whatIm();  
  3. }  

苹果类:

  1. public class Apple implements Fruit {  
  2.     @Override  
  3.     public void whatIm() {  
  4.         System.out.println("苹果");  
  5.     }  
  6. }  

梨类:

  1. public class Pear implements Fruit {  
  2.     @Override  
  3.     public void whatIm() {  
  4.         System.out.println("梨");  
  5.     }  
  6. }  

水果工厂:

  1. public class FruitFactory {  
  2.   
  3.     public Fruit createFruit(String type) {  
  4.   
  5.         if (type.equals("apple")) { //生产苹果  
  6.             return new Apple();  
  7.         } else if (type.equals("pear")) { //生产梨  
  8.             return new Pear();  
  9.         }  
  10.   
  11.         return null;  
  12.     }  
  13. }  

使用工厂生产产品:

  1. public class FruitApp {  
  2.   
  3.     public static void main(String[] args) {  
  4.         FruitFactory mFactory = new FruitFactory();  
  5.         Apple apple = (Apple) mFactory.createFruit("apple");//获得苹果  
  6.         Pear pear = (Pear) mFactory.createFruit("pear");//获得梨  
  7.         apple.whatIm();  
  8.         pear.whatIm();  
  9.     }  
  10. }  

以上的这种方式,每当添加一种水果,就必然要修改工厂类,违反了开闭原则;

Therefore, the simple factory is only suitable for the needs of fewer product objects and fixed products, and it is obviously not suitable for the needs of changing products.

5.3.3 Factory Method (Factory Method)

definition:

The factory is extracted into an interface or an abstract class, and the specific product to be produced is determined by the subclass;
roles:
1. Abstract product
2. Concrete product
3. Abstract factory
4. Specific factory
instructions:

As in the previous example, the product class is abstracted, this time we also abstract the factory class, and what kind of product to produce is determined by the subclass. The code is as follows:
fruit interface, apple class and pear class:

The code is the same as the previous example

Abstract factory interface:

  1. public interface FruitFactory {  
  2.     Fruit createFruit(); // produce fruit  
  3. }  

Apple Factory:

  1. public class AppleFactory implements FruitFactory {  
  2.     @Override  
  3.     public Apple createFruit() {  
  4.         return new Apple();  
  5.     }  
  6. }  

Pear Factory:

  1. public class PearFactory implements FruitFactory {  
  2.     @Override  
  3.     public Pear createFruit() {  
  4.         return new Pear();  
  5.     }  
  6. }  

Use the factory to produce products:

  1. public class FruitApp {  
  2.   
  3.     public static void main(String[] args){  
  4.         AppleFactory appleFactory = new AppleFactory();  
  5.         PearFactory pearFactory = new PearFactory();  
  6.         Apple apple = appleFactory.createFruit(); // get apple  
  7.         Pear pear = pearFactory.createFruit(); // get pears  
  8.         apple.whatIm();  
  9.         pear.whatIm();  
  10.     }  
  11. }  

Although the above method is decoupled and follows the principle of opening and closing, if I need a lot of products, I need to create a lot of factories, so the disadvantages of this method are also obvious.

5.3.4 Abstract Factory (Abstract Factory)

definition:

An interface provided for creating a set of related or interdependent objects without specifying their concrete classes.
Role:

1. Abstract products

2. Specific products

3、抽象工厂

4、具体工厂

使用说明:

抽象工厂和工厂方法的模式基本一样,区别在于,工厂方法是生产一个具体的产品,而抽象工厂可以用来生产一组相同,有相对关系的产品;重点在于一组,一批,一系列;举个例子,假如生产小米手机,小米手机有很多系列,小米note、红米note等;假如小米note生产需要的配件有825的处理器,6英寸屏幕,而红米只需要650的处理器和5寸的屏幕就可以了。用抽象工厂来实现:

cpu接口和实现类:

  1. public interface Cpu {  
  2.     void run();  
  3.   
  4.     class Cpu650 implements Cpu {  
  5.         @Override  
  6.         public void run() {  
  7.             System.out.println("650 也厉害");  
  8.         }  
  9.     }  
  10.   
  11.     class Cpu825 implements Cpu {  
  12.         @Override  
  13.         public void run() {  
  14.             System.out.println("825 更强劲");  
  15.         }  
  16.     }  
  17. }  

屏幕接口和实现类:

  1. public interface Screen {  
  2.   
  3.     void size();  
  4.   
  5.     class Screen5 implements Screen {  
  6.   
  7.         @Override  
  8.         public void size() {  
  9.             System.out.println("" +  
  10.                     "5寸");  
  11.         }  
  12.     }  
  13.   
  14.     class Screen6 implements Screen {  
  15.   
  16.         @Override  
  17.         public void size() {  
  18.             System.out.println("6寸");  
  19.         }  
  20.     }  
  21. }  

抽象工厂接口:

  1. public interface PhoneFactory {  
  2.   
  3.     Cpu getCpu();//使用的cpu  
  4.   
  5.     Screen getScreen();//使用的屏幕  
  6. }  

小米手机工厂:

  1. public class XiaoMiFactory implements PhoneFactory {  
  2.     @Override  
  3.     public Cpu.Cpu825 getCpu() {  
  4.         return new Cpu.Cpu825();//高性能处理器  
  5.     }  
  6.   
  7.     @Override  
  8.     public Screen.Screen6 getScreen() {  
  9.         return new Screen.Screen6();//6寸大屏  
  10.     }  
  11. }  

红米手机工厂:

  1. public class HongMiFactory implements PhoneFactory {  
  2.   
  3.     @Override  
  4.     public Cpu.Cpu650 getCpu() {  
  5.         return new Cpu.Cpu650();//高效处理器  
  6.     }  
  7.   
  8.     @Override  
  9.     public Screen.Screen5 getScreen() {  
  10.         return new Screen.Screen5();//小屏手机  
  11.     }  
  12. }  

使用工厂生产产品:

  1. public class PhoneApp {  
  2.     public static void main(String[] args){  
  3.         HongMiFactory hongMiFactory = new HongMiFactory();  
  4.         XiaoMiFactory xiaoMiFactory = new XiaoMiFactory();  
  5.         Cpu.Cpu650 cpu650 = hongMiFactory.getCpu();  
  6.         Cpu.Cpu825 cpu825 = xiaoMiFactory.getCpu();  
  7.         cpu650.run();  
  8.         cpu825.run();  
  9.   
  10.         Screen.Screen5 screen5 = hongMiFactory.getScreen();  
  11.         Screen.Screen6 screen6 = xiaoMiFactory.getScreen();  
  12.         screen5.size();  
  13.         screen6.size();  
  14.     }  
  15. }  

As can be seen from the above examples, the abstract factory can solve the production needs of a series of products. For high-volume, multi-series products, the abstract factory can be used for better management and expansion.

5.3.5 Summary of three factory methods

1. For the simple factory and the factory method, the usage of the two is actually the same. If the classification and name of the product are determined and the quantity is relatively fixed, it is recommended to use the simple factory model;

2. The abstract factory is used to solve relatively complex problems, and is suitable for a series of large-scale object production.

5.4 Proxy mode (Proxy)

5.4.1 What is proxy mode?

The proxy mode provides a proxy object to an object, and the proxy object controls the reference to the original object. In layman's terms, the agency model is a common intermediary in our lives.

Let me give an example to illustrate: If I want to buy a second-hand car now, although I can find the source of the car by myself, do a series of vehicle transfer procedures such as quality inspection, but this is really a waste of my time and energy. I just want to buy a car. Why do I have to do so much extra? So I bought a car through an intermediary company. They came to find me a car source and helped me handle the vehicle transfer process. I was only responsible for choosing the car I liked and paying for it. It is shown as follows with a graph:

5.4.2 Why use proxy mode?

Intermediary isolation:

In some cases, a client class does not want or cannot directly refer to a delegate object, and the proxy class object can play an intermediary role between the client class and the delegate object, and the characteristic is that the proxy class and the delegate class implement the same interface .

The principle of opening and closing, adding functions:

In addition to being the intermediary between the client class and the delegate class, the proxy class can also extend the function of the delegate class by adding additional functions to the proxy class. In this way, we only need to modify the proxy class instead of the delegate class, which conforms to the code The open-closed principle of design. The proxy class is mainly responsible for preprocessing messages for the entrusting class, filtering messages, forwarding messages to the entrusting class, and processing the returned results afterwards. The proxy class itself does not really implement the service, but provides specific services by calling related methods of the delegate class. The real business function is still implemented by the delegate class, but some public services can be added before and after the execution of the business function. For example, if we want to add functions such as caching and logging to the project , we can use the proxy class to complete it without modifying the encapsulated delegate class.

5.4.3 What kinds of proxy modes are there?

We have a number of different ways to implement proxies.

If classified according to the period when the agent was created, it can be divided into two types: static agent and dynamic agent.

  1. Static proxies are created by programmers or automatically generated by specific tools to compile source code. The proxy class .class file is created before the programmer runs it.
  2. Dynamic proxies are dynamically created through the reflection mechanism when the program is running.

5.4.4 Static Proxy

Step 1: Create a service class interface

  1. public interface BuyHouse {  
  2.     void buyHouse();  
  3. }  

Step 2: Implement the service interface

  1. public class BuyHouseImpl implements BuyHouse {  
  2.   
  3.     @Override  
  4.     public void buyHouse() {  
  5.         System.out.println( " I want to buy a house" );  
  6.     }  
  7. }  

Step 3: Create a Proxy Class

  1.  public class BuyHouseProxy implements BuyHouse {  
  2.   
  3.     private BuyHouse buyHouse;  
  4.   
  5.     public BuyHouseProxy(final BuyHouse buyHouse) {  
  6.         this.buyHouse = buyHouse;  
  7.     }  
  8.   
  9.     @Override  
  10.     public void buyHouse() {  
  11.         System.out.println( " Preparation before buying a house" );  
  12.         buyHouse.buyHouse();  
  13.         System.out.println("买房后装修");  
  14.   
  15.     }  
  16. }  

第四步:编写测试类

  1. public class HouseApp {  
  2.   
  3.     public static void main(String[] args) {  
  4.         BuyHouse buyHouse = new BuyHouseImpl();  
  5.         BuyHouseProxy buyHouseProxy = new BuyHouseProxy(buyHouse);  
  6.         buyHouseProxy.buyHouse();  
  7.     }  
  8. }  

静态代理总结:

优点:可以做到在符合开闭原则的情况下对目标对象进行功能扩展。

缺点:我们得为每一个服务创建代理类,工作量太大,不易管理。同时接口一旦发生改变,代理类也得相应修改。    

5.4.5 JDK动态代理(Dynamic Proxy)

在动态代理中我们不再需要再手动的创建代理类,我们只需要编写一个动态处理器就可以了。真正的代理对象由JDK在运行时为我们动态的来创建。

第一步:创建服务类接口

代码和上例一样

第二步:实现服务接口

代码和上例一样

第三步:编写动态处理器

  1. public class DynamicProxyHandler implements InvocationHandler {  
  2.   
  3.     private Object object;  
  4.   
  5.     public DynamicProxyHandler(final Object object) {  
  6.         this.object = object;  
  7.     }  
  8.   
  9.     @Override  
  10.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
  11.         System.out.println("买房前准备");  
  12.         Object result = method.invoke(object, args);  
  13.         System.out.println("买房后装修");  
  14.         return result;  
  15.     }  
  16. }  

第四步:编写测试类

  1. public class HouseApp {  
  2.   
  3.     public static void main(String[] args) {  
  4.         BuyHouse buyHouse = new BuyHouseImpl();  
  5.         BuyHouse proxyBuyHouse = (BuyHouse) Proxy.newProxyInstance(  
  6.                 BuyHouse.class.getClassLoader(),  
  7.                 new Class[]{BuyHouse.class},  
  8.                 new DynamicProxyHandler(buyHouse));  
  9.         proxyBuyHouse.buyHouse();  
  10.     }  
  11. }  

 Proxy is the common parent class of all dynamically generated proxies. This class has a static method Proxy.newProxyInstance() that receives three parameters:

  1. ClassLoader loader: Specify the class loader used by the current target object, the method of obtaining the loader is fixed
  2. Class<?>[] interfaces: Specify the type of interface implemented by the target object, and use the generic method to confirm the type
  3. InvocationHandler: Specify the dynamic processor, when the method of the target object is executed, the method of the event handler will be triggered

JDK dynamic proxy summary:

Advantages: Compared with static proxies, dynamic proxies greatly reduce development tasks, while reducing dependence on business interfaces and reducing coupling.

Disadvantages: Proxy is the common parent class of all dynamically generated proxies, so the service class must be in the form of an interface, not a common class, because Java cannot implement multiple inheritance.

5.4.6 CGLib Dynamic Proxy (CGLib Proxy)

To implement dynamic proxy in JDK, the implementation class needs to define business methods through interfaces. For classes without interfaces, how to implement dynamic proxy? This requires CGLib. CGLib adopts the underlying bytecode technology. The principle is to create a subclass for a class through bytecode technology , and use the method interception technology in the subclass to intercept all parent class method calls, and weave cross-cutting logic into it. But because inheritance is used, final modified classes cannot be proxied. Both JDK dynamic proxy and CGLib dynamic proxy are the basis for implementing Spring AOP.

Cglib subclass proxy implementation method:

(1) Introduce the jar file of cglib and the jar file of asm

(2) The proxy class cannot be final

(3) If the method of the target business object is final/static, it will not be intercepted, that is, the additional business method of the target object will not be executed

Step 1: Create a service class

  1. public class BuyHouse2 {  
  2.   
  3.     public void buyHouse() {  
  4.         System.out.println( " I want to buy a house" );  
  5.     }  
  6. }  

Step 2: Create a CGLIB proxy class

  1. public class CglibProxy implements MethodInterceptor {  
  2.   
  3.     private Object target;  
  4.   
  5.     public CglibProxy(Object target) {  
  6.         this.target = target;  
  7.     }  
  8.   
  9.     /** 
  10.      *   Create a proxy object for the target object 
  11.      * @return  proxy object 
  12.      */  
  13.     public Object getProxyInstance() {  
  14.         //1. Tool class  
  15.         Enhancer enhancer = new Enhancer();  
  16.         //2. Set the parent class  
  17.         enhancer.setSuperclass(target.getClass());  
  18.         //3. Set the callback function  
  19.         enhancer.setCallback(this);  
  20.         //4. Create a subclass (proxy object)  
  21.         return enhancer.create();  
  22.   
  23.     }  
  24.   
  25.     public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {  
  26.         System.out.println( " Preparation before buying a house" );  
  27.         // Execute the method of the target object  
  28.         Object result = method.invoke(target, args);  
  29.         System.out.println("买房后装修");  
  30.         return result;  
  31.     }  
  32. }  

第三步:创建测试类

  1. public class HouseApp {  
  2.   
  3.     public static void main(String[] args) {  
  4.   
  5.         BuyHouse2 target = new BuyHouse2();  
  6.         CglibProxy cglibProxy = new CglibProxy(target);  
  7.         BuyHouse2 buyHouseCglibProxy = (BuyHouse2) cglibProxy.getProxyInstance();  
  8.         buyHouseCglibProxy.buyHouse();  
  9.     }  
  10. }  

CGLib代理总结:

CGLib创建的动态代理对象比JDK创建的动态代理对象的性能更高,但是CGLIB创建代理对象时所花费的时间却比JDK多得多。所以对于单例的对象,因为无需频繁创建对象,用CGLIB合适,反之使用JDK方式要更为合适一些。同时由于CGLib由于是采用动态创建子类的方法,对于final修饰的方法无法进行代理。

5.4.7 Briefly describe the principle of dynamic proxy and common implementation methods of dynamic proxy

The principle of dynamic proxy: use a proxy to wrap the object , and then replace the original object with the proxy object. Any calls to the original object go through the proxy.

The proxy object decides if and when to forward method calls to the original object

The way of dynamic proxy

Realize dynamic proxy based on interface: JDK dynamic proxy

Dynamic proxy based on inheritance: Cglib, Javassist dynamic proxy

Chapter 6 MySql

6.1 jdbc operation database process

Step 1: Class.forName() loads the database connection driver;

Step 2: DriverManager.getConnection() gets the data connection object;

Step 3: Obtain the sql session object according to SQL, there are two ways: Statement and PreparedStatement;

Step 4: Execute the SQL to process the result set. If there is a parameter value before executing the SQL, set the parameter value setXXX();

Step 5: Close the result set, close the session, and close the connection.

6.2 What is the mechanism of connection pool in relational database?

Prerequisite: Create a buffer pool for database connections.

(1) Obtain or create available connections from the connection pool

(2) After use, return the connection to the connection pool

(3) Before the system shuts down, disconnect all connections and release the system resources occupied by the connections

(4) Be able to handle invalid connections, limit the total number of connections in the connection pool to not be lower than or not exceed a certain limit value.

There are several concepts that need to be understood by everyone:

The minimum number of connections is the data connection kept by the connection pool. If the application program does not use a large amount of database connections, a large amount of database connection resources will be wasted.

The maximum number of connections is the maximum number of connections that the connection pool can apply for. If the data connection request exceeds this number, subsequent data connection requests will be added to the waiting queue, which will affect subsequent database operations.

If the difference between the minimum number of connections and the maximum number of connections is too large, the first connection request will be profitable, and subsequent connection requests exceeding the minimum number of connections are equivalent to establishing a new database connection. However, these database connections that are greater than the minimum number of connections will not be released immediately after use, and will be placed in the connection pool for reuse or released after the idle timeout.

The above explanation can be understood as follows: the number of database pool connections has always been kept at a number not less than the minimum number of connections. When the number is not enough, the database will create some connections until a maximum number of connections is reached, and then the connection to the database will wait.

6.3 The complete execution sequence of the SQL select statement

The complete execution sequence of the SQL Select statement:

(1) The from clause assembles data from different data sources;

(2) The where clause filters the record rows based on the specified conditions;

(3) The group by clause divides the data into multiple groups;

(4) Use aggregate functions for calculation;

(5) Use the having clause to filter the grouping;

(6) Calculate all expressions;

(7) select field;

(8) Use order by to sort the result set.

6.3 MySQL transactions

Basic elements of transactions (ACID):

  1. Atomicity: After the transaction starts, all operations are either completed or not performed at all, and it is impossible to stagnate in the middle. If an error occurs during transaction execution, it will be rolled back to the state before the transaction started, and all operations will be as if they did not happen. In other words, affairs are an indivisible whole, just like the atoms learned in chemistry, which are the basic units of matter
  2. Consistency: Before and after the transaction, the integrity constraints of the database are not violated. For example, when A transfers money to B, it is impossible for A to deduct the money, but B does not receive it.
  3. Isolation: At the same time, only one transaction is allowed to request the same data, and there is no interference between different transactions. For example, A is withdrawing money from a bank card, and B cannot transfer money to this card until the process of A withdrawing money is over.
  4. Durability: After the transaction is completed, all updates made by the transaction to the database will be saved to the database and cannot be rolled back.

Transaction concurrency issues:

  1. Dirty read: Transaction A reads the data updated by transaction B, and then B rolls back the operation, then the data read by A is dirty data
  2. 不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致
  3. 幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

小结:

不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表

MySQL事务隔离级别:

事务隔离级别                                       脏读             不可重复读        幻读

读未提交(read-uncommitted)                是                 是                        是

不可重复读(read-committed)                否                 是                        是

可重复读(repeatable-read)              否                 否                        是

串行化(serializable)                               否                 否                        否

6.4行锁,表锁

MyISAM

InnoDB

行表锁

表锁,即使操作一条记录也会锁住整个表,不适合高并发的操作

行锁,操作时只锁某一行,不对其它行有影响,适合高并发的操作

6.5索引

数据结构:B+Tree

一般来说能够达到range就可以算是优化了

口诀:

全值匹配我最爱,最左前缀要遵守;

带头大哥不能死,中间兄弟不能断;

索引列上少计算,范围之后全失效;

LIKE百分写最右,覆盖索引不写*;

不等空值还有OR,索引影响要注意;

VAR引号不可丢,SQL优化有诀窍。

6.6 b-tree和b+tree的区别

b-tree我们称之为B树。B树是一种多路自平衡搜索树,它类似普通的二叉树,但是B书允许每个节点有更多的子节点。B树示意图如下:

B树的特点:

(1)所有键值分布在整个树中

(2)任何关键字出现且只出现在一个节点中

(3)搜索有可能在非叶子节点结束

(4)在关键字全集内做一次查找,性能逼近二分查找算法

B+Tree

从图中也可以看到,B+树与B树的不同在于:

(1)非叶子节点只存储键值信息

(2)所有叶子节点之间都有一个链指针

(3)数据记录都存放在叶子节点中

6.7简述在MySQL数据库中MyISAM和InnoDB的区别

InnoDB存储引擎

主要面向OLTP(Online Transaction Processing,在线事务处理)方面的应用

特点:

行锁设计、支持外键;

MyISAM存储引擎

主要面向OLAP(Online Analytical Processing,在线分析处理)方面的应用。

特点:

不支持事务,支持表所和全文索引。操作速度快。

6.8你们公司有哪些数据库设计规范

(一)基础规范

1、表存储引擎必须使用InnoD,表字符集默认使用utf8,必要时候使用utf8mb4

解读:

1)通用,无乱码风险,汉字3字节,英文1字节

( 2 ) utf8mb4 is a superset of utf8 , when storing 4 bytes such as emoticons, use it

2. It is forbidden to use stored procedures, views, triggers, and Events

Interpretation:

( 1 ) It has a great impact on the performance of the database. For Internet business, things that can be done by the site layer and the service layer should not be handed over to the database layer

( 2 ) Debugging, debugging, and migration are difficult, and the scalability is poor

3. It is forbidden to store large files in the database, such as photos. Large files can be stored in the object storage system, and the path is stored in the database.

4. It is forbidden to do database stress testing in the online environment

5. Testing, development, and online database environments must be isolated

(2) Naming convention

1. The library name, table name, and column name must be in lowercase and separated by underscores

Interpretation: abc , Abc , and ABC are all burying holes for themselves

2. The library name, table name, and column name must be clear from the name, and the length should not exceed 32 characters

Interpretation: tmp , wushan , who knows what these libraries are for

3. The library backup must be prefixed with bak and suffixed with date

4. The slave library must be suffixed with -s

5. The standby database must be suffixed with -ss

(3) Table Design Specifications

1. The number of single instance tables must be controlled within 2000

2. The number of single-table sub-tables must be controlled within 1024

3. The table must have a primary key, and it is recommended to use an UNSIGNED integer as the primary key

Potential pit: delete a table without a primary key, if it is a master-slave architecture in row mode, the slave library will hang

4. The use of foreign keys is prohibited. If integrity is to be ensured, it should be implemented by the application

解读:外键使得表之间相互耦合,影响update/deleteSQL性能,有可能造成死锁,高并发情况下容易成为数据库瓶颈

5、建议将大字段,访问频度低的字段拆分到单独的表中存储,分离冷热数据

(四)列设计规范

1、根据业务区分使用tinyint/int/bigint,分别会占用1/4/8字节

2、根据业务区分使用char/varchar

解读:

1)字段长度固定,或者长度近似的业务场景,适合使用char,能够减少碎片,查询性能高

2)字段长度相差较大,或者更新较少的业务场景,适合使用varchar,能够减少空间

3、根据业务区分使用datetime/timestamp

解读:前者占用5个字节,后者占用4个字节,存储年使用YEAR,存储日期使用DATE,存储时间使用datetime

4、必须把字段定义为NOT NULL并设默认值

解读:

1NULL的列使用索引,索引统计,值都更加复杂,MySQL更难优化

2NULL需要更多的存储空间

( 3 ) NULL can only use IS NULL or IS NOT NULL , and there is a big pit when =/!=/in/not in

5. Use INT UNSIGNED to store IPv4 instead of char(15)

6. Use varchar(20) to store the phone number instead of an integer

Interpretation:

( 1 ) When the country code is involved, characters such as +/-/() may appear, such as +86

( 2 ) The phone number will not be used for mathematical operations

( 3 ) varchar can be fuzzy query, for example like ' 138% '

7. Use TINYINT instead of ENUM

Interpretation: DDL operations are required to add new values ​​to ENUM

(5) Index specification

1. The unique index is named using uniq_[field name]

2. Non-unique indexes are named using idx_[field name]

3. The number of indexes on a single table is recommended to be controlled within 5

Interpretation:

( 1 ) Internet high concurrency business, too many indexes will affect the write performance

( 2 ) When generating an execution plan, if there are too many indexes, it will reduce performance and may cause MySQL to choose less than the optimal index

3)异常复杂的查询需求,可以选择ES等更为适合的方式存储

4、组合索引字段数不建议超过5个

解读:如果5个字段还不能极大缩小row范围,八成是设计有问题

5、不建议在频繁更新的字段上建立索引

6、非必要不要进行JOIN查询,如果要进行JOIN查询,被JOIN的字段必须类型相同,并建立索引

解读:踩过因为JOIN字段类型不一致,而导致全表扫描的坑么?

7、理解组合索引最左前缀原则,避免重复建设索引,如果建立了(a,b,c),相当于建立了(a), (a,b), (a,b,c)

(六)SQL规范

1、禁止使用select *,只获取必要字段

解读:

1select *会增加cpu/io/内存/带宽的消耗

2)指定字段能有效利用索引覆盖

3)指定字段查询,在表结构变更时,能保证对应用程序无影响

2、insert必须指定字段,禁止使用insert into T values()

解读:指定字段插入,在表结构变更时,能保证对应用程序无影响

3、隐式类型转换会使索引失效,导致全表扫描

4、禁止在where条件列使用函数或者表达式

解读:导致不能命中索引,全表扫描

5、禁止负向查询以及%开头的模糊查询

解读:导致不能命中索引,全表扫描

6、禁止大表JOIN和子查询

7、同一个字段上的OR必须改写问IN,IN的值必须少于50个

8、应用程序必须捕获SQL异常

解读:方便定位线上问题

说明:本规范适用于并发量大,数据量大的典型互联网业务,可直接参考。

6.9 MySQL性能优化

(1)尽量选择较小的列

(2)将where中用的比较频繁的字段建立索引

(3)select子句中避免使用‘*’

(4)避免在索引列上使用计算、not in 和<>等操作

(5)当只需要一行数据的时候使用limit 1

(6)保证单表数据不超过200W,适时分割表。针对查询较慢的语句,可以使用explain 来分析该语句具体的执行情况。

(7)避免改变索引列的类型。

(8)选择最有效的表名顺序,from字句中写在最后的表是基础表,将被最先处理,在from子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表。

(9)避免在索引列上面进行计算。

(10)尽量缩小子查询的结果

6.10 SQL 语句优化案例

例1:where 子句中可以对字段进行 null 值判断吗?

可以,比如 select id from t where num is null 这样的 sql 也是可以的。但是最好不要给数据库留NULL,尽可能的使用 NOT NULL 填充数据库。不要以为 NULL 不需要空间,比如:char(100) 型,在字段建立时,空间就固定了, 不管是否插入值(NULL 也包含在内),都是占用 100 个字符的空间的,如果是 varchar 这样的变长字段,null 不占用空间。可以在 num 上设置默认值 0,确保表中 num 列没有 null 值,然后这样查询:select id from t where num= 0。

例2:如何优化?下面的语句?

select * from admin left   join log on admin.admin_id    = log.admin_id where log.admin_id>10

优化为:select * from (select * from admin where admin_id>10) T1 lef join log on T1.admin_id = log.admin_id。

When using JOIN, small results should be used to drive large results (the results of the left table of left join should be as small as possible, and if conditions permit, they should be processed on the left first, and right join is similarly reversed). Divide into multiple queries (multiple linked table queries are inefficient, and it is easy to lock tables and block later).

Example 3 : Use between when the base of limit is relatively large

例如:select * from admin order by admin_id limit 100000,10

优化为:select * from admin where admin_id between 100000 and 100010 order by admin_id。

Example 4 : Try to avoid doing operations on the column, which will cause the index to fail

例如:select * from admin where year(admin_time)>2014

Optimized to: select * from admin where admin_time> '2014-01-01′

6.11 common interview sql

Example 1 :

Use a SQL statement to query the names of students whose scores are greater than 80 in each course

name     kecheng fenshu
张三      语文      81
张三      数学      75
李四      语文      76
李四      数学           90
王五      语文      81
王五      数学      100
王五      英语      90
1

select distinct name from table where name not in (select distinct name from table where fenshu<=80)  
2

select name from table group by name having min(fenshu)>80  


例2

The student table is as follows:
Automatic Number Student Number Name Course Number Course Name Score
1 2005001 Zhang San 0001 Math 69
2 2005002 Li Si 0001 Math 89
3 2005001 Zhang San 0001 Math 69 Delete
the redundant information of students who are the same except for the automatic number
:

delete  tablename  where  automatic number  not  in ( select  min ( automatic number)  from  tablename  group  by student number, name, course number, course name, score)  

Example 3 :

A table called team has only one field name, and there are 4 records in total, which are a, b, c, and d, corresponding to four teams. Now the four teams are competing, and a sql statement is used to display all possible game combination.

answer:

  1. select a.name, b.name  
  2. from team a, team b   
  3. where a.name < b.name  

Example 4 :

How to check such a table
year month amount
1991 1 1.1
1991 2 1.2
1991 3 1.3
1991 4 1.4
1992 1 2.1 1992 2 2.2 1992 3 2.3 1992 4 2.4 into such a result year m1 m2 m3 m4
199 1 1.1 1.2 1.3 1.4 1992 2.1 2.2 2.3 2.4  Answer:






  1. select year,   
  2. (select amount from aaa m where month=1 and m.year=aaa.yearas m1,  
  3. (select amount from aaa m where month=2 and m.year=aaa.yearas m2,  
  4. (select amount from aaa m where month=3 and m.year=aaa.yearas m3,  
  5. (select amount from  aaa m where month=4 and m.year=aaa.yearas m4  
  6. from aaa group by year  


Example 5 :

Description: Copy table (only copy structure, source table name: a new table name: b) 

Answer:
SQL:

select  *  into  b  from  a  where  1<>1 (where1=1 , copy table structure and data content) 

ORACLE:

  1.  create table b  
  2. As  
  3. Select * from a where 1=2  

[<> (not equal to) (SQL Server Compact)

Compares two expressions. When comparing non-null expressions using this operator, the result is TRUE if the left operand is not equal to the right operand. Otherwise, the result is FALSE. ]

Example 6 :

原表:
courseid coursename  score
1           java                    70
2           oracle          90
3           xml                     40
4           jsp               30
5           servlet         80

为了便于阅读,查询此表后的结果显式如下(及格分数为60):
courseid coursename  score     mark
1           java                    70         pass
2           oracle          90         pass
3           xml                     40         fail
4           jsp               30         fail
5           servlet         80         pass
写出此查询语句

答:

select courseid, coursename ,score ,if(score>=60, "pass","fail")  as mark from course  


例7

表名:购物信息

购物人  商品名称     数量

A          甲                 2

B          乙          4

C          丙          1

A           丁          2

B          丙          5

给出所有购入商品为两种或两种以上的购物人记录

答:

select * from 购物信息 where 购物人 in (select 购物人 from 购物信息 group by 购物人 having count(*) >= 2);  

例8

info 表

date                    result

2005-05-09 win

2005-05-09 lose

2005-05-09 lose

2005-05-09 lose

2005-05-10 win

2005-05-10 lose

2005-05-10 lose

如果要生成下列结果, 该如何写sql语句?

date                    win        lose

2005-05-09              2         2

2005-05-10              1         2

Answer 1 :

select datesum(case when result = "win" then 1 else 0 endas "win"sum(case when result = "lose" then 1 else 0 endas "lose" from info group by date;   

Answer 2 :

  1. select a.date, a.result as win, b.result as lose   
  2. from   
  3. (select datecount(result) as result from info where result = "win" group by dateas a   
  4. join   
  5. (select datecount(result) as result from info where result = "lose" group by dateas b   
  6. on a.date = b.date;  

6.12联合索引是什么?为什么需要注意联合索引中的顺序?

mysql可以使用多个字段同时建立一个索引,叫做联合索引,同时联合索引在建立时要留意将高频的字段索引放在前面

具体原因为:

MySQL使用索引时需要索引有序,假设现在建立了"name,age,school"的联合索引,那么索引的排序为: 先按照name排序,如果name相同,则按照age排序,如果age的值也相等,则按照school进行排序.

当进行查询时,此时索引仅仅按照name严格有序,因此必须首先使用name字段进行等值查询,之后对于匹配到的列而言,其按照age字段严格有序,此时可以使用age字段用做索引查找,,,以此类推.因此在建立联合索引的时候应该注意索引列的顺序,一般情况下,将查询需求频繁或者字段选择性高的列放在前面.此外可以根据特例的查询或者表结构进行单独的调整.

6.13什么是聚簇索引和非聚簇索引

聚簇索引即是主键索引,他索引的内容就是整行数据。

非聚簇索引即使非主键索引,他索引的是主键id。

如果一个表中没有主键索引,那么mysql会寻找唯一的非空索引做为主键索引,如果没有则隐式的定义一个主键来作为聚簇索引。

6.14 delete、drop、truncate区别

1、delete 和 truncate 仅仅删除表数据,drop 连表数据和表结构一起删除,打个比方,delete 是单杀,truncate 是团灭,drop 是把电脑摔了。

 2、delete 是 DML 语句,操作完以后如果没有不想提交事务还可以回滚,truncate 和 drop 是 DDL 语句,操作完马上生效,不能回滚,打个比方,delete 是发微信说分手,后悔还可以撤回,truncate 和 drop 是直接扇耳光说滚,不能反悔。

 3、执行的速度上,drop>truncate>delete,打个比方,drop 是神舟火箭,truncate 是和谐号动车,delete 是自行车。

6.15 mysql主从复制

slave 服务器执行 start slave,开启主从复制开关,slave 服务器的 I/O Thread 请求从 master 服务器读取 binlog(如果该线程追赶上了主库,会进入睡眠状态)

master 服务器创建 Log Dump Thread,把 binlog 发送给 slave 服务器。slave 服务器的 I/O Thread 将读取到的 binlog 日志内容写入中继日志 relay log(中继日志,mysql-relay-bin.xxxxxx,会记录位置信息,以便下次继续读取)

slave 服务器的 SQL Thread 会实时监测 relay log 新增的日志内容,把 relay log

解析成 SQL 语句,并执行。

6.16 MySQL中的varchar和char的区别以及varchar(50)中的50代表的涵义

1)、varchar与char的区别

char是一种固定长度的类型,varchar则是一种可变长度的类型

尽可能的使用 varchar 代替 char ,因为首先变长字段存储空间小,可以节省存储空间,

其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。

varchar(50)代表的含义:

varchar(50)中50的涵义最多存放50个字符,varchar(50)和(200)存储hello所占空间一样,但后者在排序时会消耗更多内存,因为order by col采用fixed_length计算col长度(memory引擎也一样)

int(20)中20的涵义:

是指显示字符的长度但要加参数的,最大为255,比如它是记录行数的id,插入10笔资料,

它就显示00000000001 ~~~00000000010,当字符的位数超过11,它也只显示11位,如果你没有加那个让它未满11位就前面加0的参数,

它不会在前面加020表示最大显示宽度为20,但仍占4字节存储,存储范围不变;

6.17一张表里面有ID自增主键,当insert了17条记录之后,删除了第15,16,17条记录,再把mysql重启,再insert一条记录,这条记录的ID是18还是15 ?

一般情况下,我们创建的表的类型是InnoDB,如果新增一条记录(不重启mysql的情况下),这条记录的id是18;但是如果重启(文中提到的)MySQL的话,这条记录的ID是15。因为InnoDB表只把自增主键的最大ID记录到内存中,所以重启数据库或者对表OPTIMIZE操作,都会使最大ID丢失。

        但是,如果我们使用表的类型是MylSAM,那么这条记录的ID就是18。因为MylSAM表会把自增主键的最大ID记录到数据文件里面,重启MYSQL后,自增主键的最大ID也不会丢失。

注:如果在这17条记录里面删除的是中间的几个记录(比如删除的是10,11,12三条记录),重启MySQL数据库后,insert一条记录后,ID都是18。因为内存或者数据库文件存储都是自增主键最大ID

6.18为什么使用数据索引能提高效率

索引就是通过事先排好序,从而在查找时可以应用二分查找等高效率的算法。

一般的顺序查找,复杂度为O(n),而二分查找复杂度为O(log2n)。当n很大时,二者的效率相差及其悬殊。

举个例子:

表中有一百万条数据,需要在其中寻找一条特定id的数据。如果顺序查找,平均需要查找50万条数据。而用二分法,至多不超过20次就能找到。二者的效率差了2.5万倍!

在一个或者一些字段需要频繁用作查询条件,并且表数据较多的时候,创建索引会明显提高查询速度,因为可由全表扫描改成索引扫描。

(无索引时全表扫描也就是要逐条扫描全部记录,直到找完符合条件的,索引扫描可以直接定位)

不管数据表有无索引,首先在SGA的数据缓冲区中查找所需要的数据,如果数据缓冲区中没有需要的数据时,服务器进程才去读磁盘。

1、无索引,直接去读表数据存放的磁盘块,读到数据缓冲区中再查找需要的数据。

2、有索引,先读入索引表,通过索引表直接找到所需数据的物理地址,并把数据读入数据缓冲区中。

6.19 B+树索引和哈希索引的区别

首先要知道Hash索引和B+树索引的底层实现原理:

hash索引底层就是hash表,进行查找时,调用一次hash函数就可以获取到相应的键值,之后进行回表查询获得实际数据.B+树底层实现是多路平衡查找树.对于每一次的查询都是从根节点出发,查找到叶子节点方可以获得所查键值,然后根据查询判断是否需要回表查询数据.

那么可以看出他们有以下的不同:

hash索引进行等值查询更快(一般情况下),但是却无法进行范围查询.

因为在hash索引中经过hash函数建立索引之后,索引的顺序与原顺序无法保持一致,不能支持范围查询.而B+树的的所有节点皆遵循(左节点小于父节点,右节点大于父节点,多叉树也类似),天然支持范围.

hash索引不支持使用索引进行排序,原理同上.

hash索引不支持模糊查询以及多列索引的最左前缀匹配.原理也是因为hash函数的不可预测.AAAA和AAAAB的索引没有相关性.

hash索引任何时候都避免不了回表查询数据,而B+树在符合某些条件(聚簇索引,覆盖索引等)的时候可以只通过索引完成查询.

hash索引虽然在等值查询上较快,但是不稳定.性能不可预测,当某个键值存在大量重复的时候,发生hash碰撞,此时效率可能极差.而B+树的查询效率比较稳定,对于所有的查询都是从根节点到叶子节点,且树的高度较低.

因此,在大多数情况下,直接选择B+树索引可以获得稳定且较好的查询速度.而不需要使用hash索引.

6.20什么情况下应不建或少建索引

1. 表记录太少

如果一个表只有5条记录,采用索引去访问记录的话,那首先需访问索引表,再通过索引表访问数据表,一般索引表与数据表不在同一个数据块,这种情况下ORACLE至少要往返读取数据块两次。而不用索引的情况下ORACLE会将所有的数据一次读出,处理速度显然会比用索引快。

如表zl_sybm(使用部门)一般只有几条记录,除了主关键字外对任何一个字段建索引都不会产生性能优化,实际上如果对这个表进行了统计分析后ORACLE也不会用你建的索引,而是自动执行全表访问。如:

select * from zl_sybm where sydw_bh=’5401’(对sydw_bh建立索引不会产生性能优化)

2. 经常插入、删除、修改的表

对一些经常处理的业务表应在查询允许的情况下尽量减少索引,如zl_yhbm,gc_dfss,gc_dfys,gc_fpdy等业务表。

3. 数据重复且分布平均的表字段

假如一个表有10万行记录,有一个字段A只有T和F两种值,且每个值的分布概率大约为50%,那么对这种表A字段建索引一般不会提高数据库的查询速度。

4. 经常和主字段一块查询但主字段索引值比较多的表字段

如gc_dfss(电费实收)表经常按收费序号、户标识编号、抄表日期、电费发生年月、操作 标志来具体查询某一笔收款的情况,如果将所有的字段都建在一个索引里那将会增加数据的修改、插入、删除时间,从实际上分析一笔收款如果按收费序号索引就已 经将记录减少到只有几条,如果再按后面的几个字段索引查询将对性能不产生太大的影响。

6.21行级锁定的优点缺点

优点:

1、当在许多线程中访问不同的行时只存在少量锁定冲突。

2、回滚时只有少量的更改。

3、可以长时间锁定单一的行。

缺点:

1、比页级或表级锁定占用更多的内存。

2、当在表的大部分中使用时,比页级或表级锁定速度慢,因为你必须获取更多的锁。

3、如果你在大部分数据上经常进行GROUP BY操作或者必须经常扫描整个表,比其它锁定明显慢很多。

4、用高级别锁定,通过支持不同的类型锁定,你也可以很容易地调节应用程序,因为其锁成本小于行级锁定。

6.22创建的索引有没有被使用到?或者说怎么才可以知道这条语句运行很慢的原因?

MySQL提供了explain命令来查看语句的执行计划,MySQL在执行某个语句之前,会将该语句过一遍查询优化器,之后会拿到对语句的分析,也就是执行计划,其中包含了许多信息. 可以通过其中和索引有关的信息来分析是否命中了索引,例如possilbe_key,key,key_len等字段,分别说明了此语句可能会使用的索引,实际使用的索引以及使用的索引长度.

6.23 varchar(10)和int(10)代表什么含义?

varchar的10代表了申请的空间长度,也是可以存储的数据的最大长度,而int的10只是代表了展示的长度,不足10位以0填充.也就是说,int(1)和int(10)所能存储的数字大小以及占用的空间都是相同的,只是在展示时按照长度展示.

6.24关心过业务系统里面的sql耗时吗?统计过慢查询吗?对慢查询都怎么优化过?

在业务系统中,除了使用主键进行的查询,其他的我都会在测试库上测试其耗时,慢查询的统计主要由运维在做,会定期将业务中的慢查询反馈给我们.

慢查询的优化首先要搞明白慢的原因是什么? 是查询条件没有命中索引?是load了不需要的数据列?还是数据量太大?

所以优化也是针对这三个方向来的,

首先分析语句,看看是否load了额外的数据,可能是查询了多余的行并且抛弃掉了,可能是加载了许多结果中并不需要的列,对语句进行分析以及重写.

分析语句的执行计划,然后获得其使用索引的情况,之后修改语句或者修改索引,使得语句可以尽可能的命中索引.

如果对语句的优化已经无法进行,可以考虑表中的数据量是否太大,如果是的话可以进行横向或者纵向的分表.

6.25什么是存储过程?有哪些优缺点?

存储过程是一些预编译的SQL语句。1、更加直白的理解:存储过程可以说是一个记录集,它是由一些T-SQL语句组成的代码块,这些T-SQL语句代码像一个方法一样实现一些功能(对单表或多表的增删改查),然后再给这个代码块取一个名字,在用到这个功能的时候调用他就行了。2、存储过程是一个预编译的代码块,执行效率比较高,一个存储过程替代大量T_SQL语句 ,可以降低网络通信量,提高通信速率,可以一定程度上确保数据安全

但是,在互联网项目中,其实是不太推荐存储过程的,比较出名的就是阿里的《Java开发手册》中禁止使用存储过程,我个人的理解是,在互联网项目中,迭代太快,项目的生命周期也比较短,人员流动相比于传统的项目也更加频繁,在这样的情况下,存储过程的管理确实是没有那么方便,同时,复用性也没有写在服务层那么好.

6.26字段为什么要定义为NOT NULL?

一般情况,都会设置一个默认值,不会出现字段里面有null,又有空的情况。主要有以下几个原:

1. The index performance is not good, and it is difficult for Mysql to optimize queries that refer to nullable columns, which will make indexes, index statistics, and values ​​more complicated. Nullable columns require more storage space and require special handling within mysql. Nullable columns require an extra byte per record when indexed, and can also cause a fixed-size index in MYisam to become a variable-size index.

2. If there is null in a certain column, it may cause incorrect execution of functions such as count()

6.27 What type of currency field is used?

If the currency unit is points, you can use the LONG type. If you insist on dollars, use Decimal.

6.28 What type of time field is used?

There is no fixed answer to this question, you should answer it in combination with your own project background! Just explain why!

(1) varchar, if you use varchar type to save time, the advantage is that the display is intuitive. But there are quite a lot of pits. For example, if the inserted data is not verified, you may find a piece of data with the data 2013111 one day. Does this represent January 11, 2013, or November 1, 2013?

Secondly, to do time comparison operations, you need to use functions such as STR_TO_DATE to convert it into a time type, and you will find that writing this way cannot hit the index. A large amount of data is a pit!

(2) timestamp, this type is a four-byte integer, and the time range it can represent is from 1970-01-01 08:00:01 to 2038-01-19 11:14:07. After 2038, It cannot be stored with timestamp type.

But it has an advantage, the timestamp type has time zone information. Once the time zone in your system changes, for example, you modify the time zone

SET TIME_ZONE = "america/new_york";

You will find that the value of this field in the project will change itself. This feature is used for some large international projects and applications across time zones, pay special attention!

(3)datetime,datetime储存占用8个字节,它存储的时间范围为1000-01-01 00:00:00 ~ 9999-12-31 23:59:59。显然,存储时间范围更大。但是它坑的地方在于,他存储的是时间绝对值,不带有时区信息。如果你改变数据库的时区,该项的值不会自己发生变更!

(4)bigint,也是8个字节,自己维护一个时间戳,表示范围比timestamp大多了,就是要自己维护,不大方便。

6.29为什么不直接存储图片、音频、视频等大容量内容?

我们在实际应用中,都是文件形式存储的。mysql中,只存文件的存放路径。虽然mysql中blob类型可以用来存放大容量文件,但是,我们在生产中,基本不用!

主要有如下几个原因:

  1. Mysql内存临时表不支持TEXT、BLOB这样的大数据类型,如果查询中包含这样的数据,查询效率会非常慢。

  2. 数据库特别大,内存占用高,维护也比较麻烦。

  3. binlog太大,如果是主从同步的架构,会导致主从同步效率问题!

因此,不推荐使用blob等类型!

6.30为什么一定要设一个主键?

因为不设主键,innodb也会帮你生成一个隐形列作为自增主键。反正都要生成主键,自己指定主键可以显示用上主键索引,提高查询效率。

6.31你们主键是用自增还是UUID?

 自增。innodb住的主键是聚簇索引,如果主键是自增的,每次插入新的记录,记录就会顺序添加到当前索引节点的后续位置,一页写满后自动开新页。不是自增主键,可能会在中间插入,引发页的分裂,产生很多表碎片。相比之下,自增插入性能更好。

6.32自增主键用完了怎么办?

自增主键用的是int类型的话,最大值是2147483648.如果达到最大值,数据有21亿条,这时应该做分表分库处理,不应该单表存这么多数据。

6.33主键为什么不推荐有业务含义?

带有业务含义的主键可能会发生变更,引发页分裂,产生空间碎片。

第7章Java Web

7.1 http 的长连接和短连接

HTTP 协议有 HTTP/1.0 版本和 HTTP/1.1 版本。HTTP1.1 默认保持长连接(HTTP persistent connection,也翻译为持久连接),数据传输完成了保持 TCP 连接不断开(不发 RST 包、不四次握手),等待在同域名下继续用这个通道传输数据;相反的就是短连接。

在 HTTP/1.0 中,默认使用的是短连接。也就是说,浏览器和服务器每进行一次 HTTP 操作,就建立一次连接,任务结束就中断连接。从 HTTP/1.1 起,默认使用的是长连接,用以保持连接特性。

7.2 http 常见的状态码有哪些?

200 OK //客户端请求成功

301 Moved Permanently(永久移除),请求的 URL 已移走。Response 中应该包含一个 Location URL, 说明资源现在所处的位置

302 found 重定向

400 Bad Request //客户端请求有语法错误,不能被服务器所理解

401 Unauthorized //请求未经授权,这个状态代码必须和 WWW-Authenticate 报头域一起使用

403 Forbidden //服务器收到请求,但是拒绝提供服务

404 Not Found //请求资源不存在,eg:输入了错误的 URL

500 Internal Server Error //An unexpected error occurred on the server

503 Server Unavailable //The server is currently unable to process the client's request, and it may return to normal after a period of time

7.3 What is the difference between GET and POST?

(1) The data of the GET request will be attached to the URL (that is, the data is placed in the HTTP protocol header), and the URL and the transmission data will be separated by ?, and the parameters will be connected by &, such as: login.action?name=zhagnsan&password=123456 . POST places the submitted data in the body of the HTTP package.

(2) The data submitted by GET method can only be 1024 bytes at most. In theory, POST has no limit, and a large amount of data can be transmitted. In fact, it is wrong and inaccurate to say this: "The data submitted by GET method can only be up to 1024 bytes", because GET submits data through URL, so the amount of data that can be submitted by GET is directly related to the length of URL . In fact, there is no upper limit on URL parameters, and the HTTP protocol specification does not limit the length of URLs. This limitation is a limitation imposed by specific browsers and servers. IE limits the URL length to 2083 bytes (2K+35). For other browsers, such as Netscape, FireFox, etc., there is no length limit in theory, and the limit depends on the support of the operating system.

(3) The security of POST is higher than that of GET. Note: The security mentioned here is not the same concept as the "security" mentioned above in GET. The above "safety" means no data modification, but the meaning of security here is the real meaning of Security, for example: submitting data through GET, the user name and password will appear on the URL in plain text, because (1) the login page may be blocked Browser cache, (2) Others can view the history of the browser, so others can get your account and password. In addition, using GET to submit data may also cause Cross-site request forgery attacks.

Get 是向服务器发索取数据的一种请求,而 Post 是向服务器提交数据的一种请求,在 FORM(表单)中,Method

默认为"GET",实质上,GET 和 POST 只是发送机制不同,并不是一个取一个发!

7.4 Cookie 和Session 的区别

Cookie 是 web 服务器发送给浏览器的一块信息,浏览器会在本地一个文件中给每个 web 服务器存储 cookie。以后浏览器再给特定的 web 服务器发送请求时,同时会发送所有为该服务器存储的 cookie。

Session 是存储在 web 服务器端的一块信息。session 对象存储特定用户会话所需的属性及配置信息。当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。

Cookie 和session 的不同点:

(1)无论客户端做怎样的设置,session 都能够正常工作。当客户端禁用 cookie 时将无法使用 cookie。

(2)在存储的数据量方面:session 能够存储任意的java 对象,cookie 只能存储 String 类型的对象。

7.5在单点登录中,如果 cookie 被禁用了怎么办?

单点登录的原理是后端生成一个 session ID,然后设置到 cookie,后面的所有请求浏览器都会带上 cookie, 然后服务端从 cookie 里获取 session ID,再查询到用户信息。所以,保持登录的关键不是 cookie,而是通过cookie 保存和传输的 session ID,其本质是能获取用户信息的数据。除了 cookie,还通常使用 HTTP 请求头来传输。但是这个请求头浏览器不会像 cookie 一样自动携带,需要手工处理。

7.6什么是jsp,什么是Servlet?jsp 和Servlet 有什么区别?

jsp 本质上就是一个Servlet,它是 Servlet 的一种特殊形式(由 SUN 公司推出),每个 jsp 页面都是一个servlet实例。

Servlet 是由 Java 提供用于开发 web 服务器应用程序的一个组件,运行在服务端,由 servlet 容器管理,用来生成动态内容。一个 servlet 实例是实现了特殊接口 Servlet 的 Java 类,所有自定义的 servlet 均必须实现 Servlet 接口。

区别:

jsp 是 html 页面中内嵌的Java 代码,侧重页面显示;

Servlet 是 html 代码和 Java 代码分离,侧重逻辑控制,mvc 设计思想中jsp 位于视图层,servlet 位于控制层

Jsp 运行机制:如下图

JVM 只能识别 Java 类,并不能识别 jsp 代码!web 容器收到以.jsp 为扩展名的 url 请求时,会将访问请求交给tomcat 中 jsp 引擎处理,每个 jsp 页面第一次被访问时,jsp 引擎将 jsp 代码解释为一个 servlet 源程序,接着编译servlet 源程序生成.class 文件,再有 web 容器 servlet 引擎去装载执行servlet 程序,实现页面交互。

7.7 servlet生命周期

Servlet 加载—>实例化—>服务—>销毁。

生命周期详解:

init():

在Servlet的生命周期中,仅执行一次init()方法。它是在服务器装入Servlet时执行的,负责初始化Servlet对象。可以配置服务器,以在启动服务器或客户机首次访问Servlet时装入Servlet。无论有多少客户机访问Servlet,都不会重复执行init()。

service():

它是Servlet的核心,负责响应客户的请求。每当一个客户请求一个HttpServlet对象,该对象的Service()方法就要调用,而且传递给这个方法一个“请求”(ServletRequest)对象和一个“响应”(ServletResponse)对象作为参数。在HttpServlet中已存在Service()方法。默认的服务功能是调用与HTTP请求的方法相应的do功能。

destroy():

仅执行一次,在服务器端停止且卸载Servlet时执行该方法。当Servlet对象退出生命周期时,负责释放占用的资源。一个Servlet在运行service()方法时可能会产生其他的线程,因此需要确认在调用destroy()方法时,这些线程已经终止或完成。

如何与Tomcat 结合工作步骤:

(1)Web Client 向Servlet容器(Tomcat)发出Http请求

(2)Servlet容器接收Web Client的请求

(3)Servlet容器创建一个HttpRequest对象,将Web Client请求的信息封装到这个对象中。

(4)Servlet容器创建一个HttpResponse对象

(5)Servlet容器调用HttpServlet对象的service方法,把HttpRequest对象与HttpResponse对象作为参数传给HttpServlet 对象。

(6)HttpServlet调用HttpRequest对象的有关方法,获取Http请求信息。

(7)HttpServlet调用HttpResponse对象的有关方法,生成响应数据。

7.8 servlet特性

单例多线程

7.9 servlet是单实例的吗?

servlet是单实例的

7.10 servlet是线程安全的吗?为什么?

Servlet对象并不是一个线程安全的对象。

Servlet第一次被调用的时候,init()方法会被调用,然后调用service() 方法,从第二次被请求开始,就直接调用service()方法。

因为servlet是单实例的,所以后面再次请求同一个Servlet的时候都不会创建Servlet实例,

而且web容器会针对每个请求创建一个独立的线程,这样多个并发请求会导致多个线程同时调用 service() 方法,这样就会存在线程不安全的问题。

7.11如何解决Servlet线程不安全的问题?

(1)不要在servlet中使用成员变量。

(2)可以给servlet中的方法添加同步锁,Synchronized,但是不提倡,数据并发访问会造成阻塞等待。

(3)可以实现 SingleThreadModel 接口,如下。这样可以避免使用成员变量的问题,但是也不提倡,原因同上。

Public class Servlet1 extends HttpServlet implements SingleThreadModel{

……..

}

7.12谈谈过滤器的作用

过滤器,是在java web中,你传入的request,response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者struts的 action进行业务逻辑,比如过滤掉非法url(不是login.do的地址请求,如果用户没有登陆都过滤掉),或者在传入servlet或者 struts的action前统一设置字符集,或者去除掉一些非法字符 

7.13谈谈拦截器的作用

拦截器,是在面向切面编程的就是在你的service或者一个方法,前调用一个方法,或者在方法后调用一个方法比如动态代理就是拦截器的简单实现,在你调用方法前打印出字符串(或者做其它业务逻辑的操作),也可以在你调用方法后打印出字符串,甚至在你抛出异常的时候做业务逻辑的操作。

7.14拦截器和过滤器有什么区别

拦截器是基于java的反射机制的,而过滤器是基于函数回调。

拦截器不依赖servlet容器,过滤器依赖与servlet容器。

拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。

拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。

在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次

7.15拦截器和过滤器的执行顺序

过滤前 – 拦截前 – Action处理 – 拦截后 – 过滤后。

过滤是一个横向的过程,首先把客户端提交的内容进行过滤(例如未登录用户不能访问内部页面的处理);过滤通过后,拦截器将检查用户提交数据的验证,做一些前期的数据处理,接着把处理后的数据发给对应的Action;Action处理完成返回后,拦截器还可以做其他过程(还没想到要做啥),再向上返回到过滤器的后续操作。

7.16说一下 jsp 的 4 种作用域?

application、session、request、page

application 作用域

     如果把变量放到application里,就说明它的作用域是application,它的有效范围是整个应用。 整个应用是指从应用启动,到应用结束。我们没有说“从服务器启动,到服务器关闭”,是因为一个服务器可能部署多个应用,当然你关闭了服务器,就会把上面所有的应用都关闭了。 application作用域里的变量,它们的存活时间是最长的,如果不进行手工删除,它们就一直可以使用。

The information transfer on the application scope is realized through ServletContext, and the main methods it provides are as follows:

Object getAttribute(String name) //Get information from application;

void setAttribute(String name, Object value) //Set information to the application scope.

session scope

       The session scope is relatively easy to understand. The same browser visits the server multiple times, and passing information between these multiple visits is the embodiment of the session scope. If you put the variable in the session, it means that its scope is session, and its valid scope is the current session. The so-called current session refers to the process from when the user opens the browser to when the user closes the browser. This process may involve multiple request responses. That is to say, as long as the user does not close the browser, the server has a way to know that these requests are initiated by one person. The whole process is called a session (session), and the variables placed in the session can be used in all sessions of the current session. used in requests.

 Session is implemented through the HttpSession interface, and the main methods it provides are as follows:

ObjectHttpSession.getAttribute(String name) //Get information from session.

void HttpSession.setAttribute(String name, Object value)//Save information to the session.

HttpSession HttpServletRequest.getSessio() //Get the session object where the current request is located.

 It is easier to judge the start time of the session. It can be considered that the session starts when the browser sends the first HTTP request. But it is difficult to judge the end time, because the server will not be notified when the browser is closed, so it can only be judged by the following method: if the client does not respond within a certain period of time, the session is considered to be over. Tomcat's default value is 120 minutes, but this value can also be set through the setMaxInactiveInterval() method of HttpSession:

void setMaxInactiveInterval(int interval)

如果想主动让会话结束,例如用户单击“注销”按钮的时候,可以使用 HttpSession 的 invalidate()方法,用于强制结束当前session:void invalidate()

request作用域

     一个HTTP请求的处理可能需要多个Servlet合作,而这几个Servlet之间可以通过某种方式传递信息,但这个信息在请求结束后就无效了。request里的变量可以跨越forward前后的两页。但是只要刷新页面,它们就重新计算了。如果把变量放到request里,就说明它的作用域是request,它的有效范围是当前请求周期。 所谓请求周期,就是指从http请求发起,到服务器处理结束,返回响应的整个过程。在这个过程中可能使用forward的方式跳转了多个jsp页面,在这些页面里你都可以使用这个变量。

Servlet之间的信息共享是通过HttpServletRequest接口的两个方法来实现的:

void setAttribute(String name, Object value) //将对象value以name为名称保存到request作用域中。

Object getAttribute(String name) //从request作用域中取得指定名字的信息。

     JSP中的doGet()、doPost()方法的第一个参数就是HttpServletRequest对象,使用这个对象的 setAttribute()方法即可传递信息。那么在设置好信息之后,要通过何种方式将信息传给其他的Servlet呢?这就要用到RequestDispatcher接口的forward()方法,通过它将请求转发给其他Servlet。

 RequestDispatcher ServletContext.getRequestDispatcher(String path) //取得Dispatcher以便转发,path为转发的目的Servlet。

 void RequestDispatcher.forward(ServletRequest request, ServletResponse response)//将request和response转发

     因此,只需要在当前Servlet中先通过setAttribute()方法设置相应的属性,然后使用forward()方法进行跳转,最后在跳转到的Servlet中通过使用getAttribute()方法即可实现信息传递。

  需要注意两点:

1、转发不是重定向,转发是在Web应用内部进行的。

2、转发对浏览器是透明的,也就是说,无论在服务器上如何转发,浏览器地址栏中显示的仍然是最初那个Servlet的地址。

page作用域

page对象的作用范围仅限于用户请求的当前页面,对于page对象的引用将在响应返回给客户端之后被释放,或者在请求被转发到其他地方后被释放。page里的变量只要页面跳转了,它们就不见了。如果把变量放到pageContext里,就说明它的作用域是page,它的有效范围只在当前jsp页面里。从把变量放到pageContext开始,到jsp页面结束,你都可以使用这个变量。

以上介绍的作用范围越来越小,request和page的生命周期都是短暂的,它们之间的区别:一个request可以包含多个page页(include,forward及filter)。

7.17 jsp 有哪些内置对象?作用分别是什么?

JSP共有以下9个内置的对象:

request 用户端请求,此请求会包含来自GET/POST请求的参数

response 网页传回用户端的回应

pageContext 网页的属性是在这里管理

session 与请求有关的会话期

What the application servlet is executing

out is used to send the output of the response

Architectural components of the config servlet

page JSP page itself

exception For error pages, uncaught exceptions

request represents the HttpServletRequest object. It contains information about the browser request and provides several useful methods for retrieving cookie, header, and session data.

response represents the HttpServletResponse object and provides several methods for setting the response sent back to the browser (such as cookies, header information, etc.)

The out object is an instance of javax.jsp.JspWriter and provides several methods that you can use to send output back to the browser.

pageContext represents a javax.servlet.jsp.PageContext object. It is an API for convenient access to various namespaces, servlet-related objects, and wraps the common

Methods for servlet-related functionality.

session represents a requested javax.servlet.http.HttpSession object. Session can store user status information

applicationton represents a javax.servle.ServletContext object. This helps to find information about the servlet engine and servlet environment

config represents a javax.servlet.ServletConfig object. This object is used to access the initialization parameters of the servlet instance.

page represents a servlet instance spawned from the page

7.18 What is the difference between Forward and Redirect?

Redirection will change the URL address, request forwarding will not

Redirection can use URL absolute path to access resources of other web servers, while request forwarding can only be forwarded within a web application

The redirection efficiency is low, which is equivalent to requesting again, and the request forwarding jump only occurs on the server side.

7.19 What are the main methods of the Request object?

The main method of the Request object: 

setAttribute(String name,Object):设置名字为name的request 的参数值 

getAttribute(String name):返回由name指定的属性值 

getAttributeNames():返回request 对象所有属性的名字集合,结果是一个枚举的实例 

getCookies():返回客户端的所有 Cookie 对象,结果是一个Cookie 数组 

getCharacterEncoding() :返回请求中的字符编码方式 

getContentLength() :返回请求的 Body的长度 

getHeader(String name) :获得HTTP协议定义的文件头信息 

getHeaders(String name) :返回指定名字的request Header 的所有值,结果是一个枚举的实例 

getHeaderNames() :返回所以request Header 的名字,结果是一个枚举的实例 

getInputStream() :返回请求的输入流,用于获得请求中的数据 

getMethod() :获得客户端向服务器端传送数据的方法 

getParameter(String name) :获得客户端传送给服务器端的有 name指定的参数值 

getParameterNames() :获得客户端传送给服务器端的所有参数的名字,结果是一个枚举的实

7.20request.getAttribute()和 request.getParameter()有何区别?

getParameter 得到的都是 String 类型的。或者是 http://a.jsp?id=123 中的 123,或者是某个表

单提交过去的数据。

getAttribute 则可以是对象。

getParameter()是获取 POST/GET 传递的参数值;

getAttribute()是获取对象容器中的数据值;

getParameter: Used for client redirection, that is, when a link is clicked or a value is passed when a button is submitted, that is, it is used for an active form

Or to receive data when url redirects to pass values.

getAttribute: When used for server-side redirection, that is, the forward function is used in sevlet, or the struts is used

mapping. findForward. getAttribute can only receive the value passed by the program with setAttribute.

getParameter() is to obtain the parameter value passed by POST/GET;

getAttribute() is to get the value of SESSION;

In addition, you can use setAttribute, getAttribute to send and receive objects. And getParameter can only pass strings obviously.

setAttribute means that the application server puts this object in a block of memory corresponding to the page, when your page server

When redirecting to another page, the application server will copy this piece of memory into the memory corresponding to another page. so

getAttribute can get the value you set, of course, this method can pass objects. session is the same, just object

The life cycle in memory is just different. getParameter is just the application server analyzing the request you sent

The text of the page, get the value you set in the form or url redirection.

getParameter returns a String, which is used to read the value in the submitted form;

The object returned by getAttribute needs to be converted, and can be set to any object with setAttribute, which is very flexible to use.

ready to use;

7.21 What is the difference between dynamic include and static include in JSP?

Dynamic include:

用法:<jsp:include page="1.jsp" flush="true" />

Features: Behavior elements can take parameters; compile first, then page synthesis; it will always check the changes in the included files, suitable for including dynamic pages;

因此,动态include的结构是互相独立的,所包含的jsp文件中的变量不可以同它的主文件共享,需要自行创建所使用的对象和页面设置;

静态的include:

用法:<%@ include file="1.htm" %>

特点:指令元素;不能带参数;先页面合成,再编译;不会检查所含文件的变化,适用于包含静态页面;

因此,静态include的结构是高度紧密的,所包含的jsp文件中所有的变量都可以同它的主文件共享,但不能有变量同名的冲突,连页面设置都可以借用主文件的.

扩展:

两种用法中file和page属性都被解释为一个相对的URI.

若以斜杠开头,说明它是一个环境相关的路径.将根据所指定URI的前缀进行解释,

若不是不是以斜杠开头,说明它是页面相关的路径,将根据当前页面路径进行解释.

7.22JSP乱码如何解决?

1.查看jsp文件头是否设置了编码格式:

2.查看项目的编码格式:设置为UTF-8

3.提交的表单乱码等问题,需要在请求头响应头设置编码

4. 设置tomcat服务器编码格式,默认情况下,tomcat使用的的编码方式:iso8859-1,打开setting.xml文件(在tomcat文件夹conf中)

7.23什么是Tomcat?

Tomcat简单的说就是一个运行JAVA的网络服务器,底层是Socket的一个程序,它也是JSP和Serlvet的一个容器。

7.24详细描述MVC

基于java的web应用系统采用MVC设计模型,即用Model(模型)、View(视图)和Controller(控制)分离设计,这是目前web应用服务系统的主流设置方向。

      Model:处理业务逻辑的模块。

      View:负责页面显示,显示Model的处理结果给用户,主要实现数据到页面的转换过程。

      Controller:负责每个请求的分发,把Form数据传递给Model进行处理,处理完成后,把处理结果返回给相应的View显示给用户。

7.25Http请求由哪三部分组成?

http协议报文

    1.请求报文(请求行/请求头/请求数据/空行)

        请求行

            求方法字段、URL字段和HTTP协议版本

            例如:GET /index.html HTTP/1.1

                get方法将数据拼接在url后面,传递参数受限

            请求方法:

                GET、POST、HEAD、PUT、DELETE、OPTIONS、TRACE、CONNECT

        请求头(key value形式)

            User-Agent:产生请求的浏览器类型。

            Accept:客户端可识别的内容类型列表。

            Host:主机地址

        请求数据

            post方法中,会把数据以key value形式发送请求

        空行

            发送回车符和换行符,通知服务器以下不再有请求头

    2.响应报文(状态行、消息报头、响应正文)

        状态行

        消息报头

        响应正文

7.26如何实现跨域?

1、jsonp

利用了 script 不受同源策略的限制

缺点:只能 get 方式,易受到 XSS攻击

2、CORS(Cross-Origin Resource Sharing),跨域资源共享

当使用XMLHttpRequest发送请求时,如果浏览器发现违反了同源策略就会自动加上一个请求头 origin;

后端在接受到请求后确定响应后会在后端在接受到请求后确定响应后会在 Response Headers 中加入一个属性 Access-Control-Allow-Origin;

浏览器判断响应中的 Access-Control-Allow-Origin 值是否和当前的地址相同,匹配成功后才继续响应处理,否则报错

缺点:忽略 cookie,浏览器版本有一定要求

3、代理跨域请求

前端向发送请求,经过代理,请求需要的服务器资源

缺点:需要额外的代理服务器

4、Html5 postMessage 方法

允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本、多窗口、跨域消息传递

缺点:浏览器版本要求,部分浏览器要配置放开跨域限制

5、修改 document.domain 跨子域

相同主域名下的不同子域名资源,设置 document.domain 为 相同的一级域名

缺点:同一一级域名;相同协议;相同端口

6、基于 Html5 websocket 协议

websocket 是 Html5 一种新的协议,基于该协议可以做到浏览器与服务器全双工通信,允许跨域请求

缺点:浏览器一定版本要求,服务器需要支持 websocket 协议

7、document.xxx + iframe

通过 iframe 是浏览器非同源标签,加载内容中转,传到当前页面的属性中

缺点:页面的属性值有大小限制

7.27简述 tcp 和 udp的区别?

1:TCP基于连接,UDP基于无连接。

2:TCP对系统资源要求高,UDP少。

3:TCP是基于字节流的,UDP是数据报文模式。

4:TCP复杂,UDP简单。

7.28tcp 为什么要三次握手,两次不行吗?为什么?

两次握手只能保证单向连接是畅通的。

Step1       A -> B : 你好,B。

Step2       A <- B : 收到。你好,A。

In such a two-way handshake process, A greets B and gets a response, that is, A sends data to B, and B can receive it.

But B greets A, but A has not responded yet, and B has not received any feedback from A, so there is no way to ensure that A can receive the data sent by B.

Only after the third handshake can it be ensured that both parties can receive the data sent by the other party.

Step3 A -> B : Received, B.

In this way, B can confirm that A can also receive the data sent by B to A.

SSM framework

8.1 Please write down the commonly used dependency injection methods in spring.

Injection via setter method

Inject via constructor

8.2 Briefly describe the commonly used interfaces and specific implementation classes of IOC containers in Spring

  1. The basic setting of the BeanFactory SpringIOC container is the bottom-level implementation, oriented to the framework itself. 
  2. A sub-interface of ApplicationContext BeanFactory that provides more advanced specificity. It is for developers.
  3. ConfigurableApplicationContext, a sub-interface of ApplicationContext, extends the methods of closing and refreshing containers such as close and refresh
  4. ClassPathXmlApplicationContext: reads the context from the classpath XML configuration file and generates a context definition. The application context is obtained from program environment variables.
  5. FileSystemXmlApplicationContext : A context for reading from XML configuration files in the file system.
  6. XmlWebApplicationContext: The context read by the XML file of the web application.

8.3 Briefly describe how to configure beans and assemble beans based on annotations in Spring

(1) First, configure and enable annotation scanning in Spring

<context:component-scan base-package=” ”></ context:component-scan>

(2) Add specific annotations to specific classes

(3) In Spring, annotations such as @Autowired or @Resource are usually used for bean assembly

8.4 Name the 5 annotations commonly used in Spring or Springmvc, and explain the meaning

@Component basic annotation, identifying a component managed by Spring

@Controller is identified as a component of the presentation layer

@Service is identified as a business layer component

@Repository is identified as a component of the persistence layer

@Autowired automatic assembly

@Qualifier("") specifies the id value of the component to be assembled

@RequestMapping() completes request mapping

@PathVariable maps the placeholders in the request URL to the formal parameters of the request processing method

Just say a few notes on the machine and explain the meaning, the above answer is just for reference

8.5 Please explain the life cycle of Spring Bean?

(1) By default, the bean life cycle in the IOC container is divided into five stages:

  1. Call the constructor or create a Bean object through the factory
  2. Inject values ​​into the properties of the bean object
  3. Call the initialization method for initialization, and the initialization method is specified by init-method.
  4. use
  5. When the IOC container is closed, the Bean object is destroyed.

(2) When the bean post-processor is added, the life cycle of the bean in the IOC container is divided into seven stages:

  1. Call the constructor or create a Bean object through the factory
  2. Inject values ​​into the properties of the bean object
  3. Execute postProcessBeforeInitialization in the Bean post-processor
  4. Call the initialization method for initialization, and the initialization method is specified by init-method.
  5. Execute postProcessAfterInitialization in the post-processor of the Bean   
  6. use
  7. When the IOC container is closed, the Bean object is destroyed

You only need to answer the first point, and you can also answer the second point to get extra points.

8.6 Briefly talk about the workflow of SpringMVC?

  1. The user sends a request to the front controller DispatcherServlet
  2. DispatcherServlet receives a request to call HandlerMapping processor mapper.
  3. The processor mapper finds the specific processor, generates the processor object and the processor interceptor (if any) and returns it to the DispatcherServlet.
  4. DispatcherServlet calls HandlerAdapter processor adapter
  5. HandlerAdapter is adapted to call a specific processor (Controller, also called a backend controller).
  6. Controller executes and returns to ModelAndView
  7. HandlerAdapter returns the controller execution result ModelAndView to DispatcherServlet
  8. DispatcherServlet passes ModelAndView to ViewReslover view parser
  9. ViewReslover returns a specific View after parsing
  10. DispatcherServlet renders the view according to the View (that is, fills the model data into the view).
  11. DispatcherServlet responds to the user

8.7 How to solve the Chinese garbled problem of POST request in SpringMVC

Solve the Chinese garbled problem through CharacterEncodingFilter in Springmvc.

Add in web.xml:

  1. <filter>  
  2.     <filter-name>CharacterEncodingFilter</filter-name>  
  3.     <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>  
  4.     <init-param>  
  5.         <param-name>encoding</param-name>  
  6.         <param-value>utf-8</param-value>  
  7.     </init-param>  
  8. </filter>  
  9. <filter-mapping>  
  10.     <filter-name>CharacterEncodingFilter</filter-name>  
  11.     <url-pattern>/*</url-pattern>  
  12. </filter-mapping>  

8.8简述SpringMvc里面拦截器是如何定义,如何配置,拦截器中三个重要的方法

定义:有两种方式

  1. 实现HandlerInterceptor接口
  2. 继承HandlerInterceptorAdapter

配置:

  1. <mvc:interceptors>  
  2.     <!--默认是对所有请求都拦截 -->  
  3.     <bean id="myFirstInterceptor" class="com.atguigu.interceptor.MyFirstInterceptor">  
  4.     </bean>  
  5.     <!-- 只针对部分请求拦截或者不拦截 -->  
  6.     <mvc:interceptor>  
  7.         <mvc:mapping path=" " />  <!—指定拦截-->  
  8.         <mvc:exclude-mapping path=””/> <!—指定不拦截-->  
  9.         <bean class=" com.atguigu.interceptor.MySecondInterceptor " /> </mvc:interceptor>  
  10. </mvc:interceptors>  

拦截器中三个重要的方法:

  1. preHandle
  2. postHandle
  3. afterCompletion

8.9 MyBatis中 #{}和${}的区别是什么?

#{}是预编译处理,${}是字符串替换;

Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;

Mybatis在处理${}时,就是把${}替换成变量的值;

使用#{}可以有效的防止SQL注入,提高系统安全性。

8.10 Mybatis 结果集的映射方式有几种,并分别解释每种映射方式如何使用。

For automatic mapping, specify the type to be mapped through resultType.

Custom mapping uses resultMap to complete specific mapping rules, specifying which column in the result set is mapped to which attribute of the object.

8.11 Briefly describe how to pass a single parameter and multiple parameters of MyBatis and how to get a value.

MyBatis passes a single parameter. If it is a common type (String+8 basic), you can specify it arbitrarily in #{} when taking the value. If it is an object type, use the property name of the object in #{} to take the value

MyBatis passes multiple parameters. By default, MyBatis will encapsulate multiple parameters with a Map. When taking values, you can use 0 1 2 .. or param1 param2.. in #{}

MyBatis passes multiple parameters. It is recommended to use named parameters before the formal parameters of the method of the Mapper interface.

@Param() to specify the key used when encapsulating the Map. Use the key specified by @Param in #{} when fetching the value

8.12 How does MyBatis obtain the automatically generated (primary) key value?  

Use the two attributes useGeneratedKeys and keyProperty in the <insert> tag to get the automatically generated primary key value.

Example:

  1. <insert id=”insertname” usegeneratedkeys=”true” keyproperty=”id”>  
  2.     insert into names (name) values (#{name})  
  3. </insert>  

8.13 Briefly describe the dynamic SQL of Mybatis, and list the 6 commonly used tags and their functions

Dynamic SQL is one of the powerful features of MyBatis based on powerful OGNL expressions.

Dynamic SQL is mainly to solve the situation where the query conditions are uncertain. During the running of the program, the query is dynamically completed according to the submitted conditions.

Commonly used labels:

<if> : to judge the condition

<where>: add the WHERE keyword in front of the SQL statement judged by <if>, and deal with the AND or OR problem at the beginning position of the SQL statement

<trim>: You can add specified characters or remove specified characters before and after the SQL statement.

<set>: Mainly used for comma problems when modifying operations

<choose> <when> <otherwise>: Similar to the switch statement in java. Choose one of all the conditions

<foreach>: iterative operation

8.14 In the Xml mapping file of Mybatis , can the id of different Xml mapping files be repeated?

For different Xml mapping files, if the namespace is configured, the id can be repeated; if the namespace is not configured, the id cannot be repeated.

8.15 How Mybatis completes the batch operation of MySQL, with examples

MyBatis completes the batch operation of MySQL mainly by assembling the corresponding SQL statement through the <foreach> tag.

For example:

  1. <insert id="insertBatch" >  
  2.     insert into tbl_employee(last_name,email,gender,d_id) values  
  3.     <foreach collection="emps" item="curr_emp" separator=",">  
  4.         (#{curr_emp.lastName},#{curr_emp.email},#{curr_emp.gender},#{curr_emp.dept.id})  
  5.     </foreach>  
  6. </insert>  

8.17简述Spring 中bean的作用域

总共有四种作用域:

  1. Singleton  单例的
  2. Prototype  原型的
  3. Request
  4. Session

8.18简述Spring中自动装配常用的两种装配模式

byName:  根据bean对象的属性名进行装配

byType: 根据bean对象的属性的类型进行装配,需要注意匹配到多个兼容类型的bean对象时,会抛出异常。

8.19请解释@Autowired注解的工作机制及required属性的作用

(1)首先会使用byType的方式进行自动装配,如果能唯一匹配,则装配成功,

如果匹配到多个兼容类型的bean, 还会尝试使用byName的方式进行唯一确定.

如果能唯一确定,则装配成功,如果不能唯一确定,则装配失败,抛出异常.

(2)默认情况下, 使用@Autowired标注的属性必须被装配,如果装配不了,也会抛出异常.

可以使用required=false来设置不是必须要被装配.

8.20 Briefly describe the role and implementation principle of ContextLoaderListener in Springmvc

effect:

The role of ContextLoaderListener is to initialize the Spring container object when the WEB application server starts by listening.

principle:

ContextLoaderListener implements the ServletContextListener interface for monitoring

The creation of ServletContext, when listening to the creation of ServletContext, in the corresponding contextInitialized

In the method, the Spring container object is created, and the created container object is set to the ServletContext domain object.

The purpose is to allow each component to share to Spring's container object through ServletContext

8.21 Briefly describe the two-level cache provided by Mybatis and the search order of the cache

(1) The cache of MyBatis is divided into a first-level cache and a second-level cache.

The first level cache is the SqlSession level cache, which is enabled by default.

The second-level cache is a NameSpace-level (Mapper) cache, which can be shared by multiple SqlSessions, and needs to be configured and enabled when using it.

(2) The search order of the cache: second-level cache => first-level cache => database

8.22 Briefly describe how to solve the problem that beans are created twice when integrating Spring and Springmvc

The problem with the Bean being created twice is that Springmvc is only responsible for scanning WEB-related components in the scan configuration, and Spring scans components other than Springmvc.

8.23 Briefly describe the two main integration places when Spring and Mybatis are integrated

(1) For the problem of SqlSession creation, configure the information used to create SqlSession through SqlSessionFactoryBean. For example: Mybatis core configuration files, Mapper mapping files, data sources, etc.

(2) The problem of Mapper interface creation, use MapperScannerConfigurer to generate proxy implementation classes for MyBatis Mapper interface in batches and hand over specific objects to Spring container management

8.24 Briefly describe the two transaction propagation behaviors commonly used in @Transaction in Spring declarative transactions

Propagation behavior of transactions is performed through propagation

REQUIRED: Use the caller's transaction, if the caller does not have a transaction, start a new transaction to run

REQUIRES_NEW: Suspend the caller's transaction and start a new transaction.

8.25 Briefly describe the function of the @RequestMapping annotation, the position that can be marked, and the commonly used attributes

(1) The function of this annotation is to complete the mapping between the request and the request processing method

(2) The annotation can be marked on the class or on the method

(3) Commonly used attributes:

value: default attribute, used to specify the mapped request URL

method: Specifies the request method of the mapping

params: Specify the request parameters for the mapping

headers: Specify the request header information for the mapping

8.26 Briefly describe the two ways of processing model data in Springmvc

  1. Use ModelAndView as the return value of the method to encapsulate model data and view information into ModelAndView
  2. Use Map or Model as the formal parameter of the method to add model data to Map or Model

8.27 Briefly describe the four request methods and corresponding operations in REST

GET query operation

POST add operation

DELETE delete operation

PUT modification operation

8.28 Briefly describe the relationship and function of view and view resolution

  1. Views are resolved by view resolvers.
  2. The function of the view resolver is to obtain specific view objects according to the information in ModelAndView
  3. The role of the view is to complete the rendering of the model data, and finally complete the forwarding or redirection operation

8.29 Name three commonly used view classes

InternalResourceView

JstlView

RedirectView

8.30简述REST中HiddenHttpMethodFilter过滤器的作用

该过滤器主要负责转换客户端请求的方式,当浏览器的请求方式为POST,并且在请求中能通过 _method获取到请求参数值。该过滤器就会进行请求方式的转换。

一般在REST中,都是将POST请求转换为对应的DELETE 或者是PUT

8.31简述Springmvc中如何返回JSON数据

Step1:在项目中加入json转换的依赖,例如jackson,fastjson,gson等

Step2:在请求处理方法中将返回值改为具体返回的数据的类型, 例如数据的集合类List<Employee>等

Step3:在请求处理方法上使用@ResponseBody注解

8.32简述如何在myBatis中的增删改操作获取到对数据库的影响条数

直接在Mapper接口的方法中声明返回值即可

8.33 Springmvc中的控制器的注解用哪个,可以是否用别的注解代替

使用@Controller注解来标注控制器,不能使用别的注解代替。

8.34如何在Springmvc中获取客户端提交的请求参数

直接在请求处理方法中声明对应的形参,也可以是用@RequestParam注解来具体指定将那些请求参数映射到方法中对应的形参。

8.35简述Springmvc中InternalResourceViewResolver解析器的工作机制

使用prefix  + 方法的返回值 + suffix 生成一个物理视图路径。

8.36 Springmvc中如何完成重定向

Add redirect: prefix in front of the return value of the request processing method, and eventually RedirectView will be parsed, and RedirectView will complete the redirection operation.

8.37 Briefly describe several notifications commonly used in aspects in Spring, and briefly explain them

Pre-advice is executed before the execution of the target method

Post notification Executed after the target method is executed, regardless of whether the target method throws an exception

Return notification is executed after the target method returns successfully, and the return value of the target method can be obtained

Exception notification is executed after the target method throws an exception

Surround advice Surround target method execution

8.38 Explain the role of @Param annotation in MyBatis

Use this annotation to specify the key used by the bottom layer of Mybatis to encapsulate the Map when processing parameters, so that it is convenient to take parameters in the SQL mapping file.

8.39 Briefly describe the use of Mapper interface development in Mybatis, how to complete the binding of Mapper interface and SQL mapping files, methods and SQL statements

The Mapper interface is bound to the SQL mapping file: the namespace value in the SQL mapping file is specified as the full class name of the Mapper interface

The method in the interface is bound to the SQL statement: the id of the SQL statement is specified as the method name in the interface.

8.40 How Spring MVC Works

(1) The user sends a request to the server, and the request is captured by the springMVC front-end controller DispatchServlet;

(2) DispatcherServle parses the request URL to obtain the request resource identifier (URL), and then calls HandlerMapping according to the URL to map the request to the handler HandlerExcutionChain;

(3) DispatchServlet selects a suitable HandlerAdapter adapter for processing according to the obtained Handler;

(4) Handler will return a ModelAndView() object to DisPatchServlet after processing the data;

(5)Handler 返回的 ModelAndView() 只是一个逻辑视图并不是一个正式的视图, DispatcherSevlet  通过ViewResolver 试图解析器将逻辑视图转化为真正的视图View;

(6)DispatcherServle 通过 model 解析出 ModelAndView()中的参数进行解析最终展现出完整的 view 并返回给客户端;

8.41谈谈你对Spring 的理解

Spring 是一个开源框架,为简化企业级应用开发而生。Spring 可以是使简单的JavaBean 实现以前只有EJB 才能实现的功能。Spring 是一个 IOC 和 AOP 容器框架。

Spring 容器的主要核心是:

控制反转(IOC),传统的 java 开发模式中,当需要一个对象时,我们会自己使用 new 或者 getInstance 等直接或者间接调用构造方法创建一个对象。而在 spring 开发模式中,spring 容器使用了工厂模式为我们创建了所需要的对象,不需要我们自己创建了,直接调用spring 提供的对象就可以了,这是控制反转的思想。

依赖注入(DI),spring 使用 javaBean 对象的 set 方法或者带参数的构造方法为我们在创建所需对象时将其属性自动设置所需要的值的过程,就是依赖注入的思想。

面向切面编程(AOP),在面向对象编程(oop)思想中,我们将事物纵向抽成一个个的对象。而在面向切面编程中,我们将一个个的对象某些类似的方面横向抽成一个切面,对这个切面进行一些如权限控制、事物管理,记录日志等公用操作处理的过程就是面向切面编程的思想。AOP 底层是动态代理,如果是接口采用 JDK 动态代理,如果是类采用CGLIB 方式实现动态代理。

8.42 Spring中常用的设计模式

(1)代理模式——spring 中两种代理方式,若目标对象实现了若干接口,spring 使用jdk 的java.lang.reflect.Proxy类代理。若目标兑现没有实现任何接口,spring 使用 CGLIB 库生成目标类的子类。

(2)单例模式——在 spring 的配置文件中设置 bean 默认为单例模式。

(3)模板方式模式——用来解决代码重复的问题。

比如:RestTemplate、JmsTemplate、JpaTemplate

(4)工厂模式——在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用同一个接口来指向新创建的对象。Spring 中使用 beanFactory 来创建对象的实例。

8.43请描述一下Spring的事务管理

(1)声明式事务管理的定义:用在 Spring 配置文件中声明式的处理事务来代替代码式的处理事务。这样的好处是,事务管理不侵入开发的组件,具体来说,业务逻辑对象就不会意识到正在事务管理之中,事实上也应该如此,因为事务管理是属于系统层面的服务,而不是业务逻辑的一部分,如果想要改变事务管理策划的话,也只需要在定义文件中重新配置即可,这样维护起来极其方便。

基于 TransactionInterceptor  的声明式事务管理:两个次要的属性: transactionManager,用来指定一个事务治理器, 并将具体事务相关的操作请托给它; 其他一个是 Properties 类型的transactionAttributes 属性,该属性的每一个键值对中,键指定的是方法名,方法名可以行使通配符, 而值就是表现呼应方法的所运用的事务属性。

(2) Declarative transaction management based on @Transactional: Spring 2.x also introduces an Annotation-based approach, which mainly involves the @Transactional annotation. @Transactional can be impregnated on interfaces, interface methods, classes and class methods. When the calculation is applied to a class, all public methods of the class will have the transaction attribute of this type.

(3) Definition of programmatic transaction management: explicitly calling methods related to transaction management such as beginTransaction(), commit(), rollback() in the code, this is programmatic transaction management. Spring's programmatic management of things has two methods: programmatic management based on the underlying API and programmatic transaction management based on TransactionTemplate.

8.45 Name the 5 annotations commonly used in SpringMVC? How to complete JSON manipulation with SpringMVC?

@Controller

@RequestMapping

@Resource and @Autowired

@PathVariable

@Repository

Use the following annotations to complete the json operation

@RequestBody

@ResponseBody

8.46 What types of transaction management does Spring support? Which way do you use in your project? How to understand global affairs and local affairs?

Spring supports programmatic transaction management and declarative transaction management. Users of the Spring Framework choose declarative transaction management because it is less application-specific and therefore more consistent with the concept of lightweight containers. Declarative transaction management is better than programmatic transaction management, although it is weaker than programmatic transaction management in terms of flexibility, because programmatic transactions allow you to control the business through code.

Transactions are divided into global transactions and local transactions. Global transactions are managed by the application server and require JTA support from the underlying server (such as WebLogic, WildFly, etc.). Local transactions are related to the persistence scheme adopted by the bottom layer. For example, when using JDBC for persistence, you need to use the Connetion object to operate the transaction; when using Hibernate for persistence, you need to use the Session object to operate the transaction.

这些事务的父接口都是PlatformTransactionManager。Spring的事务管理机制是一种典型的策略模式,PlatformTransactionManager代表事务管理接口,该接口定义了三个方法,该接口并不知道底层如何管理事务,但是它的实现类必须提供getTransaction()方法(开启事务)、commit()方法(提交事务)、rollback()方法(回滚事务)的多态实现,这样就可以用不同的实现类代表不同的事务管理策略。使用JTA全局事务策略时,需要底层应用服务器支持,而不同的应用服务器所提供的JTA全局事务可能存在细节上的差异,因此实际配置全局事务管理器是可能需要使用JtaTransactionManager的子类,如:WebLogicJtaTransactionManager(Oracle的WebLogic服务器提供)、UowJtaTransactionManager(IBM的WebSphere服务器提供)等。

8.47JDBC编程有哪些不足之处,MyBatis是如何解决这些问题的?

1) 数据库连接的创建、释放频繁造成系统资源浪费从而影响了性能,如果使用数据库连接池就可以解决这个问题。当然JDBC同样能够使用数据源。

解决:在SQLMapConfig.xml中配置数据连接池,使用数据库连接池管理数据库连接。

2) SQL语句在写代码中不容易维护,事件需求中SQL变化的可能性很大,SQL变动需要改变JAVA代码。解决:将SQL语句配置在mapper.xml文件中与java代码分离。

3) 向SQL语句传递参数麻烦,因为SQL语句的where条件不一定,可能多,也可能少,占位符需要和参数一一对应。解决:Mybatis自动将java对象映射到sql语句。

4) 对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。解决:Mbatis自动将SQL执行结果映射到java对象。

8.48SqlMapConfig.xml中配置有哪些内容?

properties(属性)

settings(配置)

typeAliases(类型别名)

typeHandlers(类型处理器)

objectFactory(对象工厂)

plugins(插件)

environments(环境集合属性对象)

environment(环境子属性对象)

transactionManager(事务管理)

dataSource(数据源)

mappers(映射器)

8.49简单的说一下MyBatis的一级缓存和二级缓存?

Mybatis首先去缓存中查询结果集,如果没有则查询数据库,如果有则从缓存取出返回结果集就不走数据库。Mybatis内部存储缓存使用一个HashMap,key为hashCode+sqlId+Sql语句。value为从查询出来映射生成的java对象

Mybatis的二级缓存即查询缓存,它的作用域是一个mapper的namespace,即在同一个namespace中查询sql可以从缓存中获取数据。二级缓存是可以跨SqlSession的。

8.50Mybatis是否支持延迟加载?如果支持,它的实现原理是什么?

Mybatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。在Mybatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false。

Its principle is to use CGLIB to create the proxy object of the target object. When the target method is called, enter the interceptor method, such as calling a.getB().getName(), and the interceptor invoke() method finds that a.getB() is If the value is null, then it will send the pre-saved sql query associated with the B object separately, query B, and then call a.setB(b), so the object b attribute of a has a value, and then complete a.getB( ).getName() method call. This is the basic principle of lazy loading.

  1. SpringBoot

9.1 What is Spring Boot?

Spring Boot is a sub-project under the Spring open source organization. It is a one-stop solution for Spring components. It mainly simplifies the difficulty of using Spring, saves heavy configuration, and provides various starters so that developers can get started quickly.

9.2 Why use Spring Boot?

Advantages of Spring Boot

  1. Operate independently

Spring Boot also embeds various servlet containers, Tomcat, Jetty, etc. Now it no longer needs to be packaged into a war package and deployed to the container. Spring Boot can run independently as long as it is packaged into an executable jar package, and all dependent packages are In a jar package.

  1. Simplified configuration

The spring-boot-starter-web starter automatically depends on other components, simplifying the maven configuration. In addition, various launchers are provided so that developers can get started quickly.

  1. automatic configuration

Spring Boot can automatically configure beans according to the classes and jar packages in the current classpath. For example, adding a spring-boot-starter-web starter can have web functions without other configuration.

  1. No code generation and XML configuration

There is no code generation in the Spring Boot configuration process, and all configuration work can be completed without XML configuration files. All of this is done with the help of conditional annotations, which is also one of the core functions of Spring 4.x.

  1. application monitoring

Spring Boot provides a series of endpoints to monitor services and applications and perform health checks.

9.3 What are the disadvantages of Spring Boot ?

Although Spring Boot is easy to get started, if you don't understand its core technology and process, it will be very difficult once you encounter problems, and there are not many solutions now, which requires a complete process.

9.4 What are the core configuration files of Spring Boot ? What's the difference?

The core configuration files of Spring Boot are application and bootstrap configuration files.

The application configuration file is easy to understand and is mainly used for automatic configuration of Spring Boot projects.

Features of the bootstrap configuration file:

  1. boostrap is loaded by the parent ApplicationContext, which is loaded first than applicationton
  2. Attributes in boostrap cannot be overridden

The bootstrap configuration file has the following application scenarios:

  1. When using the Spring Cloud Config configuration center, you need to add configuration properties connected to the configuration center in the bootstrap configuration file to load the configuration information of the external configuration center;
  2. Some fixed properties that cannot be overridden;
  3. Some encryption/decryption scenarios;

9.5 What are the formats of Spring Boot configuration files? What's the difference?

The difference between .properties and .yml is mainly in the writing format.

1).properties

app.user. name  = java stack

2).yml

app:
  user:
    name: javastack

In addition, the .yml format does not support @PropertySource annotation import configuration.

9.6 Which is the core annotation of Spring Boot ? Which annotations does it mainly consist of?

The annotation above the startup class is @SpringBootApplication, which is also the core annotation of Spring Boot. The main combination includes the following three annotations:

  1. @SpringBootConfiguration: The @Configuration annotation is combined to realize the function of the configuration file.
  2. @EnableAutoConfiguration: Turn on the automatic configuration function, or turn off an automatic configuration option,
    1. For example, turn off the data source automatic configuration function: @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }).
  3. @ComponentScan: Spring component scan.

9.7 What are the ways to enable Spring Boot features?

  1. Inherit the spring-boot-starter-parent project
  1. <parent>  
  2.     <groupId>  
  3.         org.springframework.boot  
  4.     </groupId>  
  5.     <artifactId>  
  6.         spring-boot-starter-parent  
  7.     </artifactId>  
  8.     <version>  
  9.         2.0.7.RELEASE  
  10.     </version>  
  11. </parent>  

  1. If the project has inherited other parent projects, you can import spring-boot-dependencies project dependencies
  1. <dependencyManagement>  
  2.     <dependencies>  
  3.         <dependency>   
  4.             <groupId>  
  5.                 org.springframework.boot  
  6.             </groupId>   
  7.             <artifactId>  
  8.                 spring-boot-dependencies  
  9.             </artifactId>  
  10.             <version>  
  11.                 2.0.7.RELEASE  
  12.             </version>    
  13.             <type>  
  14.                 pom  
  15.             </type>      
  16.             <scope>  
  17.                 import  
  18.             </scope>  
  19.         </dependency>  
  20.     </dependencies>  
  21. </dependencyManagement>

9.8 Spring Boot 需要独立的容器运行吗?

可以不需要,内置了 Tomcat/ Jetty 等容器。

9.9运行 Spring Boot 有哪几种方式?

1)打包命令或者放到容器中运行

2)用 Maven/ Gradle 插件运行

3)直接执行 main 方法运行

9.10 Spring Boot 自动配置原理是什么?

注解 @EnableAutoConfiguration, @Configuration, @ConditionalOnClass 就是自动配置的核心,

首先它得是一个配置文件,其次根据类路径下是否有这个类去自动配置。

@EnableAutoConfiguration是实现自动配置的注解

@Configuration表示这是一个配置文件

从上面的@Import的类可以找到下面自动加载自动配置的映射。

  1. org.springframework.core.io.support.SpringFactoriesLoader.loadFactoryNames(Class<?>, ClassLoader)
  1. public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
  2.     String factoryClassName = factoryClass.getName();
  3.     try {
  4.         Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
  5.                 lassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
  6.         List<String> result = new ArrayList<String>();
  7.         while (urls.hasMoreElements()) {
  8.             URL url = urls.nextElement();
  9.             Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
  10.             String factoryClassNames = properties.getProperty(factoryClassName);
  11.             result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
  12.         }
  13.         return result;
  14.     }
  15.     catch (IOException ex) {
  16.         throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
  17.                 "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
  18.     }
  19. }

这个方法会加载类路径及所有jar包下META-INF/spring.factories配置中映射的自动配置的类。

  1. /**
  2.  * The location to look for factories.
  3.  * <p>Can be present in multiple JAR files.
  4.  */
  5. public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

查看Spring Boot自带的自动配置的包:

spring-boot-autoconfigure-1.5.6.RELEASE.jar,打开其中的META-INF/spring.factories文件会找到自动配置的映射。

  1. # Auto Configure
  2. org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  3. org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
  4. org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
  5. org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
  6. org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
  7. org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
  8. org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
  9. org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
  10. ...

Let's take a look at the implementation annotations of data source automatic configuration

  1. @Configuration
  2. @ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
  3. @EnableConfigurationProperties(DataSourceProperties.class)
  4. @Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class })
  5. public class DataSourceAutoConfiguration {
  6. ...

@Configuration,@ConditionalOnClass就是自动配置的核心,首先它得是一个配置文件,其次根据类路径下是否有这个类去自动配置。

9.11、你如何理解 Spring Boot 中的 Starters?

Starters可以理解为启动器,它包含了一系列可以集成到应用里面的依赖包,你可以一站式集成 Spring 及其他技术,而不需要到处找示例代码和依赖包。如你想使用 Spring JPA 访问数据库,只要加入 spring-boot-starter-data-jpa 启动器依赖就能使用了。

Starters包含了许多项目中需要用到的依赖,它们能快速持续的运行,都是一系列得到支持的管理传递性依赖。具体请看这篇文章《Spring Boot Starters启动器》。

9.12、如何在 Spring Boot 启动的时候运行一些特定的代码?

可以实现接口 ApplicationRunner 或者 CommandLineRunner,这两个接口实现方式一样,它们都只提供了一个 run 方法,具体请看这篇文章《Spring Boot Runner启动器》。

9.13、Spring Boot 有哪几种读取配置的方式?

Spring Boot 可以通过 @PropertySource,@Value,@Environment, @ConfigurationProperties 来绑定变量,具体请看这篇文章《Spring Boot读取配置的几种方式》。

9.14、Spring Boot 支持哪些日志框架?推荐和默认的日志框架是哪个?

Spring Boot 支持 Java Util Logging, Log4j2, Lockback 作为日志框架,如果你使用 Starters 启动器,Spring Boot 将使用 Logback 作为默认日志框架。

9.15、SpringBoot 实现热部署有哪几种方式?

主要有两种方式:

Spring Loaded

Spring-boot-devtools

Spring-boot-devtools 使用步骤如下:

1、引用devtools依赖

  1. <dependency>
  2.     <groupId>org.springframework.boot</groupId>
  3.     <artifactId>spring-boot-devtools</artifactId>
  4.     <optional>true</optional>
  5. </dependency>

2、自定义配置热部署,以下配置用于自定义配置热部署,可以不设置。

  1. # 热部署开关,false即不启用热部署
  2. spring.devtools.restart.enabled: true
  3. # 指定热部署的目录
  4. #spring.devtools.restart.additional-paths: src/main/java
  5. # 指定目录不更新
  6. spring.devtools.restart.exclude: test/**

3、Intellij Idea修改,如果是idea,需要改以下两个地方:

1)、勾上自动编译或者手动重新编译

File > Settings > Compiler-Build Project automatically

2)、注册

ctrl + shift + alt + / > Registry > Compiler autoMake allow when app running

注意事项

1、生产环境devtools将被禁用,如java -jar方式或者自定义的类加载器等都会识别为生产环境。

2、打包应用默认不会包含devtools,除非你禁用SpringBoot Maven插件的 excludeDevtools属性。

3、Thymeleaf无需配置 spring.thymeleaf.cache:false,devtools默认会自动设置,参考完整属性。

9.16、你如何理解 Spring Boot 配置加载顺序?

在 Spring Boot 里面,可以使用以下几种方式来加载配置。

1)properties文件;

2)YAML文件;

3)系统环境变量;

4)命令行参数;

等等……

1、开发者工具 `Devtools` 全局配置参数;

2、单元测试上的 `@TestPropertySource` 注解指定的参数;

3、单元测试上的 `@SpringBootTest` 注解指定的参数;

4、命令行指定的参数,如 `java -jar springboot.jar --name="Java技术栈"`;

5、命令行中的 `SPRING_APPLICATION_JSONJSON` 指定参数, 如 `java -Dspring.application.json='{"name":"Java技术栈"}' -jar springboot.jar`

6、`ServletConfig` 初始化参数;

7、`ServletContext` 初始化参数;

8、JNDI参数(如 `java:comp/env/spring.application.json`);

9、Java系统参数(来源:`System.getProperties()`);

10、操作系统环境变量参数;

11、`RandomValuePropertySource` 随机数,仅匹配:`ramdom.*`;

12、JAR包外面的配置文件参数(`application-{profile}.properties(YAML)`)

13、JAR包里面的配置文件参数(`application-{profile}.properties(YAML)`)

14、JAR包外面的配置文件参数(`application.properties(YAML)`)

15、JAR包里面的配置文件参数(`application.properties(YAML)`)

16、`@Configuration`配置文件上 `@PropertySource` 注解加载的参数;

17、默认参数(通过 `SpringApplication.setDefaultProperties` 指定);

数字小的优先级越高,即数字小的会覆盖数字大的参数值,我们来实践下,验证以上配置参数的加载顺序。

9.17、Spring Boot 如何定义多套不同环境配置?

提供多套配置文件,如:

applcation.properties
application-dev.properties
application-test.properties
application-prod.properties

运行时指定具体的配置文件,具体请看这篇文章《Spring Boot Profile 不同环境配置》。

9.18 Spring Boot 可以兼容老 Spring 项目吗,如何做?

可以兼容,使用 @ImportResource 注解导入老 Spring 项目配置文件。

9.19 Spring Boot 2.X 有什么新特性?与 1.X 有什么区别?

  1. 依赖 JDK 版本升级:2.x 里面的许多方法应用了 JDK 8 的许多高级新特性,至少需要 JDK 8 的支持;
  2. 第三方类库升:2.x 对第三方类库升级了所有能升级的稳定版本,例如:Spring Framework 5+、Tomcat 8.5+、Hibernate 5.2+、Thymeleaf 3+;
  3. 响应式 Spring 编程:2.x 通过启动器和自动配置全面支持 Spring 的响应式编程,响应式编程是完全异步和非阻塞的,它是基于事件驱动模型,而不是传统的线程模型;
  4. 连接池:2.x 默认使用 HikariCP 连接池;
  5. json:提供了一个 spring-boot-starter-json 启动器对 JSON 读写的支持;
  6. Quartz:2.x 提供了一个 spring-boot-starter-quartz 启动器对定时任务框架 Quartz 的支持;
  7. HTTP/2 支持:提供对HTTP/2 的支持,如:Tomcat, Undertow, Jetty;
  8. Actuator加强:在 2.x 中,对执行器端点进行了许多改进,所有的 HTTP 执行端点现在都暴露在 /actuator路径下,并对 JSON 结果集也做了改善。

9.20Spring Boot、Spring MVC 和 Spring 有什么区别?

SpringFrame

      SpringFramework 最重要的特征是依赖注入。所有 SpringModules(多模块) 不是依赖注入就是 IOC 控制反转。

当我们恰当的使用 DI 或者是 IOC 的时候,我们可以开发松耦合应用。松耦合应用的单元测试可以很容易的进行。

SpringMVC

      Spring MVC 提供了一种分离式的方法来开发 Web 应用。通过运用像 DispatcherServelet,MoudlAndView 和 ViewResolver 等一些简单的概念,开发 Web 应用将会变的非常简单。

SpringBoot

       Spring 和 SpringMVC 的问题在于需要配置大量的参数。

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">

<property name="prefix">      

 <value>/WEB-INF/views/</value>  

 </property>    

<property name="suffix">        

<value>.jsp</value>    

</property>  

</bean>

 <mvc:resources mapping="/webjars/**" location="/webjars/"/>

       Spring Boot 通过一个自动配置和启动的项来目解决这个问题。为了更快的构建产品就绪应用程序,Spring Boot 提供了一些非功能性特征。

9.21什么是 Spring Boot Stater ?

启动器是一套方便的依赖没描述符,它可以放在自己的程序中。你可以一站式的获取你所需要的 Spring 和相关技术,而不需要依赖描述符的通过示例代码搜索和复制黏贴的负载。

9.22什么是 Spring Data REST?

Spring Data TEST 可以用来发布关于 Spring 数据库的 HATEOAS RESTful 资源。

9.23RequestMapping 和 GetMapping 的不同之处在哪里?

RequestMapping 具有类属性的,可以进行 GET,POST,PUT 或者其它的注释中具有的请求方法。

GetMapping 是 GET 请求方法中的一个特例。它只是 ResquestMapping 的一个延伸,目的是为了提高清晰度。

  1.  SpringCloud

10.1 Spring Boot和Spring 是什么关系

SpringBoot底层就是Spring,简化使用Spring的方式而已,多加了好多的自动配置

10.2Spring Boot和Spring Cloud是什么关系

Spring Boot 是 Spring 的一套快速配置脚手架,可以基于Spring Boot 快速开发单个微服务,Spring Cloud是一个基于Spring Boot实现的开发工具;Spring Boot专注于快速、方便集成的单个微服务个体,Spring Cloud关注全局的服务治理框架; Spring Boot使用了默认大于配置的理念,很多集成方案已经帮你选择好了,能不配置就不配置,Spring Cloud很大的一部分是基于Spring Boot来实现,必须基于Spring Boot开发。

 可以单独使用Spring Boot开发项目,但是Spring Cloud离不开 Spring Boot。

10.3 Eureka和zookeeper的区别

著名的CAP理论指出,一个分布式系统不可能同时满足C(一致性)、A(可用性)和P(分区容错性)。由于分区容错性在是分布式系统中必须要保证的,因此我们只能在A和C之间进行权衡。在此Zookeeper保证的是CP, 而Eureka则是AP。

Zookeeper保证CP

当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接受服务直接down掉不可用。也就是说,服务注册功能对可用性的要求要高于一致性。但是zk会出现这样一种情况,当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30 ~ 120s, 且选举期间整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪。在云部署的环境下,因网络问题使得zk集群失去master节点是较大概率会发生的事,虽然服务能够最终恢复,但是漫长的选举时间导致的注册长期不可用是不能容忍的。

Eureka保证AP

Eureka看明白了这一点,因此在设计时就优先保证可用性。Eureka各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册或时如果发现连接失败,则会自动切换至其它节点,只要有一台Eureka还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)。除此之外,Eureka还有一种自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:

1. Eureka不再从注册列表中移除因为长时间没收到心跳而应该过期的服务

2. Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上(即保证当前节点依然可用)

3. 当网络稳定时,当前实例新的注册信息会被同步到其它节点中

因此, Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像zookeeper那样使整个注册服务瘫痪。

总结

Eureka作为单纯的服务注册中心来说要比zookeeper更加“专业”,因为注册服务更重要的是可用性,我们可以接受短期内达不到一致性的状况。不过Eureka目前1.X版本的实现是基于servlet的java web应用,它的极限性能肯定会受到影响。期待正在开发之中的2.X版本能够从servlet中独立出来成为单独可部署执行的服务。

10.4springcloud如何实现服务的注册?

服务在发布时 指定对应的服务名(服务名包括了IP地址和端口) 将服务注册到注册中心(eureka或者zookeeper)

 这一过程是springcloud自动实现 只需要在main方法添加@EnableDisscoveryClient  同一个服务修改端口就可以启动多个实例

调用方法:传递服务名称通过注册中心获取所有的可用实例 通过负载均衡策略调用(ribbon和feign)对应的服务

10.5eureka自我保护机制是什么?

自我保护机制的工作机制是如果在15分钟内超过85%的客户端节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,Eureka Server自动进入自我保护机制,此时会出现以下几种情况:

1、Eureka Server不再从注册列表中移除因为长时间没收到心跳而应该过期的服务。
2、Eureka Server仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上,保证当前节点依然可用。
3、当网络稳定时,当前Eureka Server新的注册信息会被同步到其它节点中。

因此Eureka Server可以很好的应对因网络故障导致部分节点失联的情况,而不会像ZK那样如果有一半不可用的情况会导致整个集群不可用而变成瘫痪。

10.6什么是服务熔断?什么是服务降级?

服务熔断的作用类似于我们家用的保险丝,当某服务出现不可用或响应超时的情况时,为了防止整个系统出现雪崩,

暂时停止对该服务的调用。

服务降级是从整个系统的负荷情况出发和考虑的,对某些负荷会比较高的情况,为了预防某些功能(业务场景)出现负荷过载或者响应慢的情况,在其内部暂时舍弃对一些非核心的接口和数据的请求,而直接返回一个提前准备好的fallback(退路)错误处理信息。这样,虽然提供的是一个有损的服务,但却保证了整个系统的稳定性和可用性。

10.7Ribbon和Feign的区别?

1.Ribbon都是调用其他服务的,但方式不同。

2.启动类注解不同,Ribbon是@RibbonClient feign的是@EnableFeignClients

3.服务指定的位置不同,Ribbon是在@RibbonClient注解上声明,Feign则是在定义抽象方法的接口中使用@FeignClient声明。

4.调用方式不同,Ribbon需要自己构建http请求,模拟http请求然后使用RestTemplate发送给其他服务,步骤相当繁琐。Feign需要将调用的方法定义成抽象方法即可。

10.8Hystrix断路器能干嘛?

服务降级整体资源快不够了,忍痛将某些服务先关掉,待渡过难关,再开启回来

服务熔断熔断机制是应对雪崩效应的一种微服务链路保护机制。当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回”错误”的响应信息。当检测到该节点微服务调用响应正常后恢复调用链路。在SpringCloud框架里熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况,当失败的调用到一定阈值,缺省是5秒内20次调用失败就会启动熔断机制。熔断机制的注解是@HystrixCommand。

服务限流

接近实时的监控除了隔离依赖服务的调用以外,Hystrix还提供了准实时的调用监控(Hystrix Dashboard),Hystrix会持续地记录所有通过Hystrix发起的请求的执行信息,并以统计报表和图形的形式展示给用户,包括每秒执行多少请求多少成功,多少失败等。Netflix通过hystrix-metrics-event-stream项目实现了对以上指标的监控。Spring Cloud也提供了Hystrix Dashboard的整合,对监控内容转化成可视化界面。

10.9分布式配置中心能干嘛?

(1)集中管理配置文件不同环境不同配置,动态化的配置更新,分环境部署比如

dev/test/prod/beta/release

(2)运行期间动态调整 置,不再需要在每个服务部署的机器上编写配置文件,服务会向配置中心统一拉取配置自己的信息

(3)当配置发生变动时,服务不需要重启即可感知到配置的变化并应用新的配置将配置信息以REST接口的形式暴露

10.10微服务之间是如何通讯的?

微服务能解决了单体应用以及SOA带来的的问题,但是微服务使整个应用服务增多,服务间通讯更复杂,也会带来大量 的问题。比如单体如何拆分成多个微服务,团队间沟通更多,运维成本增高,分布式事务问题,依赖管理变得复杂,测试 更加困难,故障更难于定位等等。

微服务架构能够解决单体架构带来的问题。但是在微服务架构中,一个整体的程序被拆分为许多子微服务。每个微服务实现某一个单一的功能,但是这使得应用程序的应用服务变多,这就使得这些微服务程序之间的通信变得十分复杂。而在程序运行过程中存在着大量的业务逻辑,这往往需要各个微服务之间交换大量的数据。这就带来了许多微服务通信的问题。但是微服务之间是如何通信的呢?

1、客户端到服务端通信,API Gateway方法。

API Gateway是解决微服务通信的一个不错的方法。以客户端为例。一个客户端可以向多个微服务中的任意一个微服务发出请求。API Gateway负责请求转发、合成和协议转换。所有请求都要先经过API Gateway,然后再将请求转发到对应的微服务中。

2、进程通信IPC

这种通信不但可以实现一对一、一对多。还可以实现同步和异步请求。

10.11什么是 Swagger?你用 Spring Boot 实现了它吗?

Swagger 广泛用于可视化 API,使用 Swagger UI 为前端开发人员提供在线沙箱。Swagger 是用于生成 RESTful Web 服务的可视化表示的工具,规范和完整框架实现。它使文档能够以与服务器相同的速度更新。当通过 Swagger 正确定义时,消费者可以使用最少量的实现逻辑来理解远程服务并与其进行交互。因此,Swagger消除了调用服务时的猜测。

10.11你所知道的微服务技术栈有哪些?请列举一二

服务注册与发现Eureka、Consul、Zookeeper等

服务调用Rest、RPC、gRPC

服务熔断器Hystrix、Envoy等

负载均衡Ribbon、Nginx等

服务接口调用(客户端调用服务的简化工具)Feign等

消息队列Kafka、RabbitMQ、ActiveMQ等

服务配置中心管理SpringCloudConfig、Chef等

服务路由(API网关)Zuul等

服务监控Zabbix、Nagios、Metrics、Spectator等

10.12Ribbon负载均衡能干嘛?

LB(负载均衡LB,即负载均衡(Load Balance),在微服务或分布式集群中经常用的一种应用。负载均衡简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA。常见的负载均衡有软件Nginx,LVS,硬件 F5等。相应的在中间件,例如:dubbo和SpringCloud中均给我们提供了负载均衡,SpringCloud的负载均衡算法可以自定义。

集中式LB即在服务的消费方和提供方之间使用独立的LB设施(可以是硬件,如F5, 也可以是软件,如nginx), 由该设施负责把访问请求通过某种策略转发至服务的提供方;

进程内LB将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的服务器。

注意: Ribbon就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址。

10.13什么是SpringCloud Config分布式配置中心

SpringCloud Config为微服务架构中的微服务提供集中化的外部配置支持,配置服务器为各个不同微服务应用的所有环境提供了一个中心化的外部配置。

第11章 Redis

11.1什么是Redis?

Redis本质上是一个Key-Value类型的内存数据库,很像memcached,整个数据库统统加载在内存当中进行操作,定期通过异步操作把数据库数据flush到硬盘上进行保存。因为是纯内存操作,Redis的性能非常出色,每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DB。 Redis的出色之处不仅仅是性能,Redis最大的魅力是支持保存多种数据结构,此外单个value的最大限制是1GB,不像 memcached只能保存1MB的数据,因此Redis可以用来实现很多有用的功能,比方说用他的List来做FIFO双向链表,实现一个轻量级的高性 能消息队列服务,用他的Set可以做高性能的tag系统等等。另外Redis也可以对存入的Key-Value设置expire时间,因此也可以被当作一 个功能加强版的memcached来用。 Redis的主要缺点是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。

11.2 redis有哪些数据类型

string

字符串

list

可以重复的集合

set

不可以重复的集合

hash

类似于Map<String,String>

zset(sorted set

带分数的set

11.3一个字符串类型的值能存储最大容量是多少?

512M

11.4 怎么理解Redis事务?

事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。

事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。

11.5 Redis事务相关的命令有哪几个?

MULTI、EXEC、DISCARD、WATCH

11.6 Redis key的过期时间和永久有效分别怎么设置?

EXPIRE和PERSIST命令。

11.7 Redis 集群如何选择数据库?


Redis 集群目前无法做数据库选择,默认在 0 数据库。


11.8 Redis持久化数据和缓存怎么做扩容?

如果Redis被当做缓存使用,使用一致性哈希实现动态扩容缩容。

如果Redis被当做一个持久化存储使用,必须使用固定的keys-to-nodes映射关系,节点的数量一旦确定不能变化。否则的话(即Redis节点需要动态变化的情况),必须使用可以在运行时进行数据再平衡的一套系统,而当前只有Redis集群可以做到这样。4、Redis主要消耗什么物理资源?

内存。

11.9 为什么Redis需要把所有数据放到内存中?

Redis为了达到最快的读写速度将数据都读到内存中,并通过异步的方式将数据写入磁盘。所以redis具有快速和数据持久化的特征。如果不将数据放在内存中,磁盘I/O速度为严重影响redis的性能。在内存越来越便宜的今天,redis将会越来越受欢迎。 如果设置了最大使用的内存,则数据已有记录数达到内存限值后不能继续插入新值。

11.10 Redis如何做内存优化?

尽可能使用散列表(hashes),散列表(是说散列表里面存储的数少)使用的内存非常小,所以你应该尽可能的将你的数据模型抽象到一个散列表里面。比如你的web系统中有一个用户对象,不要为这个用户的名称,姓氏,邮箱,密码设置单独的key,而是应该把这个用户的所有信息存储到一张散列表里面.

11.11缓存穿透

缓存系统定义:

按照KEY去查询VALUE,当KEY对应的VALUE一定不存在的时候并对KEY并发请求量很大的时候,就会对后端造成很大的压力。(查询一个必然不存在的数据。比如文章表,查询一个不存在的id,每次都会访问DB,如果有人恶意破坏,很可能直接对DB造成影响。)

由于缓存不命中,每次都要查询持久层。从而失去缓存的意义。

解决方法:

1)缓存层缓 存空值。

缓存太多空值,占用更多空间。(优化:给个空值过 期时间)

存储层更新代码了,缓存层还是空值。(优化:后台设置时主动删除空值,并缓存把值进去)

2)将数据库中所有的查询条件,放布隆过滤器中。当一个查询请求来临的时候,先经过布隆过滤器进行查,如果请求存在这个条件中,那么继续执行,如果不在,直接丢弃。

备注 

比如数据库中有10000个条件,那么布隆过滤器的容量size设置的要稍微比10000大一些,比如12000.

对于误判率的设置,根据实际项目,以及硬件设施来具体定。但一定不能设置为0,并且误判率设置的越小,哈希函数跟数组长度都会更多跟更长,那么对硬件,内存中间的要求就会相应  的高

private st atic BloomFilter<Inte ger> bloomFi lt er = BloomFilter.create(Funnels.integerFue l(), s ize, 000 01)  ;

有了siz跟误判率,那么布隆过滤器会产相应的哈希函数跟数组。 

综上:我们可以利用布隆过滤器,将redis缓存击穿制在一个可容的范围内。

11.12 哨兵模式

如果Master异常,则会进行Master-Slave切换,将其中一Slae作为Master,将之前的Master作为Slave

下线:

主观下线:Subjectively Down,简称 SDOWN,指的是当前 Sentinel 实例对某个redis服务器做出的下线判断。

客观下线:Objectively Down 简称 ODOWN,指的是多个 Sentinel 实例在对Master Server做出 SDOWN 判断,并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后,得出的Master Server下线判断,然后开启failover.

工作原理:

1)每个Sentinel以每秒钟一次的频率向它所知的MasterSlave以及其他 Sentinel 实例发送一个 PING 命令

2)如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel 标记为主观下线;

3)如果一个Master被标记为主观下线,则正在监视这个Master的所有 Sentinel 要以每秒一次的频率确认Master的确进入了主观下线状态;

4)当有足够数量的 Sentinel(大于等于配置文件指定的值)在指定的时间范围内确认Master的确进入了主观下线状态, Master会被标记为客观下线

5)在一般情况下, 每个 Sentinel 会以每 10 秒一次的频率向它已知的所有MasterSlave发送 INFO 命令

6)当Master Sentinel 标记为客观下线时,Sentinel 向下线的 Master 的所有 Slave 发送 INFO 命令的频率会从 10 秒一次改为每秒一次

7)若没有足够数量的 Sentinel 同意 Master 已经下线, Master 的客观下线状态就会被移除;

Master 重新向 Sentinel PING 命令返回有效回复, Master 的主观下线状态就会被移除;

11.13 悲观锁

执行操作前假设当前的操作肯定(或有很大几率)会被打断(悲观)。基于这个假设,我们在做操作前就会把相关资源锁定,不允许自己执行期间有其他操作干扰。

Redis不支持悲观锁。Redis作为缓存服务器使用时,以操作为主,很少写操作,相应的操作被打断的几率较少。不采用悲观锁是为了防止降低性能。

11.14 乐观锁

执行操作前假设当前操作不会被打断(乐观)。基于这个假设,我们在做操作前不会锁定资源,万一发生了其他操作的干扰,那么本次操作将被放弃。

11.15 持久化

(1)RDB持久化:

每隔一段时间,将内存中的数据集写到磁盘

Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。

保存策略:

save 9   00 1    900 秒内如果至少有 1 key 的值变化,则保存

save 300   10   300 秒内如果至少有 10 key 的值变化,则保存

save 60 1 0000  60 秒内如果至10000 key 的值变化,则保存

(2)AOF 持久化:  以日志形式记录每个更新((总结、改)操作

Redis重新启动时读取这个文件,重新执行新建、修改数据的命令恢复数据。

保存策略:

appendfsync always:每次产生一条新的修改数据的命令都执行保存操作;效率低,但是安全!

appendfsync everysec:每秒执行一次保存操作。如果在未保存当前秒内操作时发生了断电,仍然会导致一部分数据丢失(即1秒钟的数据)。

appendfsync no:从不保存,将数据交给操作系统来处理。更快,也更不安全的选择。

推荐(并且也是默认)的措施为每秒 fsync 一次, 这种 fsync 策略可以兼顾速度和安全性。

缺点:

1 比起RDB占用更多的磁盘空间

2 恢复备份速度要慢

3 每次读写都同步的话,有一定的性能压力

4 存在个别Bug,造成恢复不能

(3)选择策略:

可读的日志文本,通过操作AOF

官方推荐:

如果对数据不敏感,可以选单独用RDB;不建议单独用AOF,因为可能出现Bug;如果只是做纯内存缓存,可以都不用

11.16 Redis提供了哪几种持久化方式?

RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储。

AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾.Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大。

如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式。

你也可以同时开启两种持久化方式,在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。

11.17如何选择合适的持久化方式?

一般来说, 如果想达到足以媲美PostgreSQL的数据安全性, 你应该同时使用两种持久化功能。如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失,那么你可以只使用RDB持久化。

有很多用户都只使用AOF持久化,但并不推荐这种方式:因为定时生成RDB快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比AOF恢复的速度要快,除此之外, 使用RDB还可以避免之前提到的AOF程序的bug。

11.18分布式Redis是前期做还是后期规模上来了再做好?为什么?

既然Redis是如此的轻量(单实例只使用1M内存),为防止以后的扩容,最好的办法就是一开始就启动较多实例。即便你只有一台服务器,你也可以一开始就让Redis以分布式的方式运行,使用分区,在同一台服务器上启动多个实例。

一开始就多设置几个Redis实例,例如32或者64个实例,对大多数用户来说这操作起来可能比较麻烦,但是从长久来看做这点牺牲是值得的。

这样的话,当你的数据不断增长,需要更多的Redis服务器时,你需要做的就是仅仅将Redis实例从一台服务迁移到另外一台服务器而已(而不用考虑重新分区的问题)。一旦你添加了另一台服务器,你需要将你一半的Redis实例从第一台机器迁移到第二台机器。

11.19 Redis的内存占用情况怎么样?

给你举个例子: 100万个键值对(键是0到999999值是字符串“hello world”)在我的32位的Mac笔记本上 用了100MB。同样的数据放到一个key里只需要16MB, 这是因为键值有一个很大的开销。 在Memcached上执行也是类似的结果,但是相对Redis的开销要小一点点,因为Redis会记录类型信息引用计数等等。

当然,大键值对时两者的比例要好很多。

64位的系统比32位的需要更多的内存开销,尤其是键值对都较小时,这是因为64位的系统里指针占用了8个字节。 但是,当然,64位系统支持更大的内存,所以为了运行大型的Redis服务器或多或少的需要使用64位的系统。

11.20都有哪些办法可以降低Redis的内存使用情况呢?

如果你使用的是32位的Redis实例,可以好好利用Hash,list,sorted set,set等集合类型数据,因为通常情况下很多小的Key-Value可以用更紧凑的方式存放到一起。

11.21查看Redis使用情况及状态信息用什么命令?

info

11.22 Redis的内存用完了会发生什么?

如果达到设置的上限,Redis的写命令会返回错误信息(但是读命令还可以正常返回。)或者你可以将Redis当缓存来使用配置淘汰机制,当Redis达到内存上限时会冲刷掉旧的内容。

11.23 redis是单线程的,为什么那么快

1)完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)

2)数据结构简单,对数据操作也简单,Redis中的数据结构是专门进行设计的

3)采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗

4)使用多路I/O复用模型,非阻塞IO

5)使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求

11.24 Redis是单线程的,如何提高多核CPU的利用率?

可以在同一个服务器部署多个Redis的实例,并把他们当作不同的服务器来使用,在某些时候,无论如何一个服务器是不够的, 所以,如果你想使用多个CPU,你可以考虑一下分片(shard)。

11.25一个Redis实例最多能存放多少的keys?List、Set、Sorted Set他们最多能存放多少元素?

理论上Redis可以处理多达232的keys,并且在实际中进行了测试,每个实例至少存放了2亿5千万的keys。我们正在测试一些较大的值。

任何list、set、和sorted set都可以放232个元素。

换句话说,Redis的存储极限是系统中的可用内存值。

11.26 Redis常见性能问题和解决方案?

(1) Master最好不要做任何持久化工作,如RDB内存快照和AOF日志文件

(2) 如果数据比较重要,某个Slave开启AOF备份数据,策略设置为每秒同步一次

(3) 为了主从复制的速度和连接的稳定性,Master和Slave最好在同一个局域网内

(4) 尽量避免在压力很大的主库上增加从库

(5) 主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1 <- Slave2 <- Slave3...

这样的结构方便解决单点故障问题,实现Slave对Master的替换。如果Master挂了,可以立刻启用Slave1做Master,其他不变。

11.27 Redis相比memcached有哪些优势?

(1) memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型

(2) redis的速度比memcached快很多

  1. redis可以持久化其数据

11.28 MySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据?

redis内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略。

11.29 Redis有哪几种数据淘汰策略?

noeviction:返回错误当内存限制达到并且客户端尝试执行会让更多内存被使用的命令(大部分的写入指令,但DEL和几个例外)

allkeys-lru: 尝试回收最少使用的键(LRU),使得新添加的数据有空间存放。

volatile-lru: 尝试回收最少使用的键(LRU),但仅限于在过期集合的键,使得新添加的数据有空间存放。

allkeys-random: 回收随机的键使得新添加的数据有空间存放。

volatile-random: 回收随机的键使得新添加的数据有空间存放,但仅限于在过期集合的键。

volatile-ttl: 回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。

11.30 Redis集群方案应该怎么做?都有哪些方案?

(1)twemproxy,大概概念是,它类似于一个代理方式,使用方法和普通redis无任何区别,设置好它下属的多个redis实例后,使用时在本需要连接redis的地方改为连接twemproxy,它会以一个代理的身份接收请求并使用一致性hash算法,将请求转接到具体redis,将结果再返回twemproxy。使用方式简便(相对redis只需修改连接端口),对旧项目扩展的首选。 问题:twemproxy自身单端口实例的压力,使用一致性hash后,对redis节点数量改变时候的计算值的改变,数据无法自动移动到新的节点。

(2)codis,目前用的最多的集群方案,基本和twemproxy一致的效果,但它支持在 节点数量改变情况下,旧节点数据可恢复到新hash节点。

(3)redis cluster3.0自带的集群,特点在于他的分布式算法不是一致性hash,而是hash槽的概念,以及自身支持节点设置从节点。具体看官方文档介绍。

(4)在业务代码层实现,起几个毫无关联的redis实例,在代码层,对key 进行hash计算,然后去对应的redis实例操作数据。 这种方式对hash层代码要求比较高,考虑部分包括,节点失效后的替代算法方案,数据震荡后的自动脚本恢复,实例的监控,等等。

11.31说说Redis哈希槽的概念?

Redis集群没有使用一致性hash,而是引入了哈希槽的概念,Redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽,集群的每个节点负责一部分hash槽。

11.32 Redis集群最大节点个数是多少?

16384个。

11.33 怎么测试Redis的连通性?

ping

11.34修改配置不重启Redis会实时生效吗?

针对运行实例,有许多配置选项可以通过 CONFIG SET 命令进行修改,而无需执行任何形式的重启。 从 Redis 2.2 开始,可以从 AOF 切换到 RDB 的快照持久性或其他方式而不需要重启 Redis。检索 ‘CONFIG GET *’ 命令获取更多信息。

但偶尔重新启动是必须的,如为升级 Redis 程序到新的版本,或者当你需要修改某些目前 CONFIG 命令还不支持的配置参数的时候。

11.35 Redis有哪些适合的场景?

(1)会话缓存(Session Cache)

最常用的一种使用Redis的情景是会话缓存(session cache)。用Redis缓存会话比其他存储(如Memcached)的优势在于:Redis提供持久化。当维护一个不是严格要求一致性的缓存时,如果用户的购物车信息全部丢失,大部分人都会不高兴的,现在,他们还会这样吗?

幸运的是,随着 Redis 这些年的改进,很容易找到怎么恰当的使用Redis来缓存会话的文档。甚至广为人知的商业平台Magento也提供Redis的插件。

(2)全页缓存(FPC)

除基本的会话token之外,Redis还提供很简便的FPC平台。回到一致性问题,即使重启了Redis实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降,这是一个极大改进,类似PHP本地FPC。

再次以Magento为例,Magento提供一个插件来使用Redis作为全页缓存后端。

此外,对WordPress的用户来说,Pantheon有一个非常好的插件 wp-redis,这个插件能帮助你以最快速度加载你曾浏览过的页面。

(3)队列

Reids在内存存储引擎领域的一大优点是提供 list 和 set 操作,这使得Redis能作为一个很好的消息队列平台来使用。Redis作为队列使用的操作,就类似于本地程序语言(如Python)对 list 的 push/pop 操作。

如果你快速的在Google中搜索“Redis queues”,你马上就能找到大量的开源项目,这些项目的目的就是利用Redis创建非常好的后端工具,以满足各种队列需求。例如,Celery有一个后台就是使用Redis作为broker,你可以从这里去查看。

(4)排行榜/计数器

Redis在内存中对数字进行递增或递减的操作实现的非常好。集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操作的时候变的非常简单,Redis只是正好提供了这两种数据结构。所以,我们要从排序集合中获取到排名最靠前的10个用户–我们称之为“user_scores”,我们只需要像下面一样执行即可:

当然,这是假定你是根据你用户的分数做递增的排序。如果你想返回用户及用户的分数,你需要这样执行:

ZRANGE user_scores 0 10 WITHSCORES

Agora Games就是一个很好的例子,用Ruby实现的,它的排行榜就是使用Redis来存储数据的,你可以在这里看到。

(5)发布/订阅

最后(但肯定不是最不重要的)是Redis的发布/订阅功能。发布/订阅的使用场景确实非常多。我已看见人们在社交网络连接中使用,还可作为基于发布/订阅的脚本触发器,甚至用Redis的发布/订阅功能来建立聊天系统!(不,这是真的,你可以去核实)。

  1.  MQ

12.1 ActiveMQ 如果消息发送失败怎么办?

Activemq 有两种通信方式,点到点形式和发布订阅模式。

如果是点到点模式的话,如果消息发送不成功此 消息默认会保存到 activemq 服务端知道有消费者将其消费,所以此时消息是不会丢失的。

如果是发布订阅模式的通信方式,默认情况下只通知一次,如果接收不到此消息就没有了。这种场景只适  用于对消息送达率要求不高的情况。如果要求消息必须送达不可以丢失的话,需要配置持久订阅。每个订阅端定义一个 id, 在订阅是向 activemq 注册。发布消息和接收消息时需要配置发送模式为持久化。此时 如果客户端接收不到消息,消息会持久化到服务端,直到客户端正常接收后为止。

12.2如何使用ActiveMQ 解决分布式事务?

在互联网应用中,基本都会有用户注册的功能。在注册的同时,我们会做出如下操作:

收集用户录入信息,保存到数据库向用户的手机或邮箱发送验证码等等…

如果是传统的集中式架构,实现这个功能非常简单:开启一个本地事务,往本地数据库中插入一条用户数据,发送验证码,提交事物。

但是在分布式架构中,用户和发送验证码是两个独立的服务,它们都有各自的数据库,那么就不能通过本地事物保证操作的原子性。这时我们就需要用到 ActiveMQ(消息队列)来为我们实现这个需求。

在用户进行注册操作的时候,我们为该操作创建一条消息,当用户信息保存成功时,把这条消息发送到消息队列。验证码系统会监听消息,一旦接受到消息,就会给该用户发送验证码。

12.3 如何防止ActiveMQ消息重复发送?

解决方法很简单:增加消息状态表。通俗来说就是一个账本,用来记录消息的处理状态,每次处理消息之前,都去状态表中查询一次,如果已经有相同的消息存在,那么不处理,可以防止重复发送。

12.4使用消息队列有什么缺点?

优点就是在特殊场景下有其对应的好处,解耦、异步、削峰。

缺点有以下几个:

系统可用性降低

系统引入的外部依赖越多,越容易挂掉。本来你就是 A 系统调用 BCD 三个系统的接口就好了,人 ABCD 四个系统好好的,没啥问题,你偏加个 MQ 进来,万一 MQ 挂了咋整,MQ 一挂,整套系统崩溃的,你不就完了?如何保证消息队列的高可用,可以点击这里查看。

系统复杂度提高

硬生生加个 MQ 进来,你怎么保证消息没有重复消费?怎么处理消息丢失的情况?怎么保证消息传递的顺序性?头大头大,问题一大堆,痛苦不已。

一致性问题

A 系统处理完了直接返回成功了,人都以为你这个请求就成功了;但是问题是,要是 BCD 三个系统那里,BD 两个系统写库成功了,结果 C 系统写库失败了,咋整?你这数据就不一致了。

所以消息队列实际是一种非常复杂的架构,你引入它有很多好处,但是也得针对它带来的坏处做各种额外的技术方案和架构来规避掉,做好之后,你会发现,妈呀,系统复杂度提升了一个数量级,也许是复杂了 10 倍。但是关键时刻,用,还是得用的。

12.5消息队列的作用与使用场景?

消息队列在实际应用中常用的使用场景。异步处理,应用解耦,流量削锋和消息通讯四个场景

2.1异步处理

场景说明:用户注册后,需要发注册邮件和注册短信。传统的做法有两种 1.串行的方式;2.并行方式

(1)串行方式:将注册信息写入数据库成功后,发送注册邮件,再发送注册短信。以上三个任务全部完成后,返回给客户端

http://images2015.cnblogs.com/blog/820332/201601/820332-20160124211106000-2080222350.png

(2)并行方式:将注册信息写入数据库成功后,发送注册邮件的同时,发送注册短信。以上三个任务完成后,返回给客户端。与串行的差别是,并行的方式可以提高处理的时间

http://images2015.cnblogs.com/blog/820332/201601/820332-20160124211115703-218873208.png

假设三个业务节点每个使用50毫秒钟,不考虑网络等其他开销,则串行方式的时间是150毫秒,并行的时间可能是100毫秒。

因为CPU在单位时间内处理的请求数是一定的,假设CPU1秒内吞吐量是100次。则串行方式1秒内CPU可处理的请求量是7次(1000/150)。并行方式处理的请求量是10次(1000/100)

小结:如以上案例描述,传统的方式系统的性能(并发量,吞吐量,响应时间)会有瓶颈。如何解决这个问题呢?

引入消息队列,将不是必须的业务逻辑,异步处理。改造后的架构如下:

http://images2015.cnblogs.com/blog/820332/201601/820332-20160124211131625-1083908699.png

按照以上约定,用户的响应时间相当于是注册信息写入数据库的时间,也就是50毫秒。注册邮件,发送短信写入消息队列后,直接返回,因此写入消息队列的速度很快,基本可以忽略,因此用户的响应时间可能是50毫秒。因此架构改变后,系统的吞吐量提高到每秒20 QPS。比串行提高了3倍,比并行提高了两倍

2.2应用解耦

场景说明:用户下单后,订单系统需要通知库存系统。传统的做法是,订单系统调用库存系统的接口。如下图

http://images2015.cnblogs.com/blog/820332/201601/820332-20160124211254187-1511483255.png

传统模式的缺点:

假如库存系统无法访问,则订单减库存将失败,从而导致订单失败

订单系统与库存系统耦合

如何解决以上问题呢?引入应用消息队列后的方案,如下图:

http://images2015.cnblogs.com/blog/820332/201601/820332-20160124211307687-1914946501.png

订单系统:用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户订单下单成功

库存系统:订阅下单的消息,采用拉/推的方式,获取下单信息,库存系统根据下单信息,进行库存操作

假如:在下单时库存系统不能正常使用。也不影响正常下单,因为下单后,订单系统写入消息队列就不再关心其他的后续操作了。实现订单系统与库存系统的应用解耦

2.3流量削锋

流量削锋也是消息队列中的常用场景,一般在秒杀或团抢活动中使用广泛

应用场景:秒杀活动,一般会因为流量过大,导致流量暴增,应用挂掉。为解决这个问题,一般需要在应用前端加入消息队列。

可以控制活动的人数

可以缓解短时间内高流量压垮应用

http://images2015.cnblogs.com/blog/820332/201601/820332-20160124211333125-923847962.png

用户的请求,服务器接收后,首先写入消息队列。假如消息队列长度超过最大数量,则直接抛弃用户请求或跳转到错误页面

秒杀业务根据消息队列中的请求信息,再做后续处理

2.4日志处理

日志处理是指将消息队列用在日志处理中,比如Kafka的应用,解决大量日志传输的问题。

日志采集客户端,负责日志数据采集,定时写受写入Kafka队列

Kafka消息队列,负责日志数据的接收,存储和转发

日志处理应用:订阅并消费kafka队列中的日志数据

以下是新浪kafka日志处理应用案例:转自(http://cloud.51cto.com/art/201507/484338.htm)

http://images2015.cnblogs.com/blog/820332/201601/820332-20160124211447875-1251492581.png

(1)Kafka:接收用户日志的消息队列

(2)Logstash:做日志解析,统一成JSON输出给Elasticsearch

(3)Elasticsearch:实时日志分析服务的核心技术,一个schemaless,实时的数据存储服务,通过index组织数据,兼具强大的搜索和统计功能

(4)Kibana:基于Elasticsearch的数据可视化组件,超强的数据可视化能力是众多公司选择ELK stack的重要原因

2.5消息通讯

消息通讯是指,消息队列一般都内置了高效的通信机制,因此也可以用在纯的消息通讯。比如实现点对点消息队列,或者聊天室等

点对点通讯:

http://images2015.cnblogs.com/blog/820332/201601/820332-20160124211500718-1411703435.png

客户端A和客户端B使用同一队列,进行消息通讯。

聊天室通讯:

客户端A,客户端B,客户端N订阅同一主题,进行消息发布和接收。实现类似聊天室效果。

以上实际是消息队列的两种消息模式,点对点或发布订阅模式。模型为示意图,供参考。

12.6如何保证消息的顺序性?

顺序会错乱的俩场景:

RabbitMQ:一个 queue,多个 consumer。比如,生产者向 RabbitMQ 里发送了三条数据,顺序依次是 data1/data2/data3,压入的是 RabbitMQ 的一个内存队列。有三个消费者分别从 MQ 中消费这三条数据中的一条,结果消费者2先执行完操作,把 data2 存入数据库,然后是 data1/data3。这不明显乱了。

解决方案:

拆分多个 queue,每个 queue 一个 consumer,就是多一些 queue 而已,确实是麻烦点;或者就一个 queue 但是对应一个 consumer,然后这个 consumer 内部用内存队列做排队,然后分发给底层不同的 worker 来处理。

12.7如何保证消息队列的高可用?

镜像集群模式(高可用性)

这种模式,才是所谓的 RabbitMQ 的高可用模式。跟普通集群模式不一样的是,在镜像集群模式下,你创建的 queue,无论元数据还是 queue 里的消息都会存在于多个实例上,就是说,每个 RabbitMQ 节点都有这个 queue 的一个完整镜像,包含 queue 的全部数据的意思。然后每次你写消息到 queue 的时候,都会自动把消息同步到多个实例的 queue 上。

那么如何开启这个镜像集群模式呢?其实很简单,RabbitMQ 有很好的管理控制台,就是在后台新增一个策略,这个策略是镜像集群模式的策略,指定的时候是可以要求数据同步到所有节点的,也可以要求同步到指定数量的节点,再次创建 queue 的时候,应用这个策略,就会自动将数据同步到其他的节点上去了。

这样的话,好处在于,你任何一个机器宕机了,没事儿,其它机器(节点)还包含了这个 queue 的完整数据,别的 consumer 都可以到其它节点上去消费数据。

12.8无法被路由的消息,去了哪里?

如果没有任何设置,无法路由的消息会被直接丢弃。

无法路由的情况:Routing key不正确

解决方案:

1.使用mandatory = true配合ReturnListener,实现消息回发

2.声明交换机时,指定备份交换机。

12.9消息队列过期失效问题

假设你用的是 RabbitMQ,RabbtiMQ 是可以设置过期时间的,也就是 TTL。如果消息在 queue 中积压超过一定的时间就会被 RabbitMQ 给清理掉,这个数据就没了。那这就是第二个坑了。这就不是说数据会大量积压在 mq 里,而是大量的数据会直接搞丢。

这个情况下,就不是说要增加 consumer 消费积压的消息,因为实际上没啥积压,而是丢了大量的消息。我们可以采取一个方案,就是批量重导,这个我们之前线上也有类似的场景干过。就是大量积压的时候,我们当时就直接丢弃数据了,然后等过了高峰期以后,比如大家一起喝咖啡熬夜到晚上12点以后,用户都睡觉了。这个时候我们就开始写程序,将丢失的那批数据,写个临时程序,一点一点的查出来,然后重新灌入 mq 里面去,把白天丢的数据给他补回来。也只能是这样了。假设 1 万个订单积压在 mq 里面,没有处理,其中 1000 个订单都丢了,你只能手动写程序把那 1000 个订单给查出来,手动发到 mq 里去再补一次。

12.10消息队列满了怎么办?

·  修复现有consumer的问题,并将其停掉。

·  重新创建一个容量更大的topic,比如patition是原来的10倍。

·  编写一个临时consumer程序,消费原来积压的队列。该consumer不做任何耗时的操作,将消息均匀写入新创建的队列里。

·  将修复好的consumer部署到原来10倍的机器上消费新队列。

·  消息积压解决后,恢复原有架构。

12.11 RabbitMQ 有哪些重要的组件?

12.12 RabbitMQ 有几种广播类型?

三种广播模式:

fanout: 所有bind到此exchange的queue都可以接收消息(纯广播,绑定到RabbitMQ的接受者都能收到消息);

direct: 通过routingKey和exchange决定的那个唯一的queue可以接收消息;

topic:  所有符合routingKey(此时可以是一个表达式)的routingKey所bind的queue可以接收消息;

12.14消息如何分发?

1.Round-Robin(轮询)

默认的策略,消费者轮流,平均地收到消息。

2.Fair dispatch(公平分发)

如果要实现根据消费者的处理能力来分发消息,给空闲的消费者发送更多消息,可以用basicQos(int prefetch_count)来设置。prefetch_count的含义:当消费者有多少条消息没有响应ACK时,不再给这个消费者发送消息。

12.15如何确保消息正确地发送至 RabbitMQ? 如何确保消息接收方消费了消息?

发送方确认模式

将信道设置成 confirm 模式(发送方确认模式),则所有在信道上发布的消息都会被指派一个唯一的 ID。

一旦消息被投递到目的队列后,或者消息被写入磁盘后(可持久化的消息),信道会发送一个确认给生产者(包含消息唯一 ID)。

如果 RabbitMQ 发生内部错误从而导致消息丢失,会发送一条 nack(notacknowledged,未确认)消息。

发送方确认模式是异步的,生产者应用程序在等待确认的同时,可以继续发送消息。当确认消息到达生产者应用程序,生产者应用程序的回调方法就会被触发来处理确认消息。

12.16为什么不应该对所有的 message 都使用持久化机制?

首先,必然导致性能的下降,因为写磁盘比写 RAM 慢的多,message 的吞吐量可能有 10 倍的差距。其次,message 的持久化机制用在 RabbitMQ 的内置 cluster 方案时会出现“坑爹”问题。矛盾点在于,若 message 设置了 persistent 属性,但 queue 未设置 durable 属性,那么当该 queue 的 owner node 出现异常后,在未重建该 queue 前,发往该 queue 的 message 将被 blackholed ;若 message 设置了 persistent 属性,同时 queue 也设置了 durable 属性,那么当 queue 的 owner node 异常且无法重启的情况下,则该 queue 无法在其他 node 上重建,只能等待其 owner node 重启后,才能恢复该 queue 的使用,而在这段时间内发送给该 queue 的 message 将被 blackholed 。所以,是否要对 message 进行持久化,需要综合考虑性能需要,以及可能遇到的问题。若想达到 100,000 条/秒以上的消息吞吐量(单 RabbitMQ 服务器),则要么使用其他的方式来确保 message 的可靠 delivery ,要么使用非常快速的存储系统以支持全持久化(例如使用 SSD)。另外一种处理原则是:仅对关键消息作持久化处理(根据业务重要程度),且应该保证关键消息的量不会导致性能瓶颈。

12.16ActiveMQ和RabbitMQ的区别?

1.ActiveMq,传统的消息队列,使用Java语言编写。基于JMS(Java Message Service),采用多线程并发,资源消耗比较大。支持P2P和发布订阅两种模式。

2.RabbitMQ,基于AMQP协议实现,支持多种场景,社区活跃量大。高性能,高可用,支持海量数据。

两者区别在于JMS和AMQP,

 JMS提供了两种消息模型,peer-2-peer(点对点)以及publish-subscribe(发布订阅)模型。当采用点对点模型时,消息将发送到一个队列,该队列的消息只能被一个消费者消费。而采用发布订阅模型时,消息可以被多个消费者消费。在发布订阅模型中,生产者和消费者完全独立,不需要感知对方的存在。

在AMQP中,消息路由(messagerouting)和JMS存在一些差别,在AMQP中增加了Exchange和binding的角色。producer将消息发送给Exchange,binding决定Exchange的消息应该发送到那个queue,而consumer直接从queue中消费消息。queue和exchange的bind有consumer来决定。

12.17 RabbitMQ 中的 broker 是指什么?cluster 又是指什么?

broker 是指一个或多个 erlang node 的逻辑分组,且 node 上运行着 RabbitMQ 应用程序。cluster 是在 broker 的基础之上,增加了 node 之间共享元数据的约束。

12.18什么是元数据?元数据分为哪些类型?包括哪些内容?与 cluster 相关的元数据有哪些?元数据是如何保存的?元数据在 cluster 中是如何分布的?

在非 cluster 模式下,元数据主要分为 Queue 元数据(queue 名字和属性等)、Exchange 元数据(exchange 名字、类型和属性等)、Binding 元数据(存放路由关系的查找表)、Vhost 元数据(vhost 范围内针对前三者的名字空间约束和安全属性设置)。

在 cluster 模式下,还包括 cluster 中 node 位置信息和 node 关系信息。元数据按照 erlang node 的类型确定是仅保存于 RAM 中,还是同时保存在 RAM 和 disk 上。元数据在 cluster 中是全 node 分布的。

12.19 RabbitMQ 上的一个 queue 中存放的 message 是否有数量限制?

可以认为是无限制,因为限制取决于机器的内存,但是消息过多会导致处理效率的下降。

12.20 RabbitMQ 概念里的 channel、exchange 和 queue 这些东西是逻辑概念,还是对应着进程实体?这些东西分别起什么作用?

queue 具有自己的 erlang 进程;exchange 内部实现为保存 binding 关系的查找表;

channel 是实际进行路由工作的实体,即负责按照 routing_key 将 message 投递给queue 。由 AMQP 协议描述可知,channel 是真实 TCP 连接之上的虚拟连接,所有AMQP 命令都是通过 channel 发送的,且每一个 channel 有唯一的 ID。一个 channel 只能被单独一个操作系统线程使用,故投递到特定 channel 上的 message 是有顺序的。但一个操作系统线程上允许使用多个 channel 。channel 号为 0 的 channel 用于处理所有对于当前 connection 全局有效的帧,而 1-65535 号 channel 用于处理和特定 channel 相关的帧。AMQP 协议给出的 channel 复用模型如下其中每一个 channel 运行在一个独立的线程上,多线程共享同一个 socket。

12.21消息在什么时候会变成Dead Letter(死信)?

1.消息被拒绝并且没有设置重新入队:(NACK || Reject)&&requeue == false

2.消息过期(消息或者队列的TTL设置)

3.消息堆积,并且队列达到最大长度,先入队的消息会变成DL。

可以在声明队列的时候,指定一个Dead Letter Exchange,来实现Dead Letter的转发。

12.22 RabbitMQ如何实现延时队列?

利用TTL(队列的消息存活时间或消息的存活时间),加上死信交换机。

当然还有一种方式就是先保存到数据库,用调度器扫描发送(时间不够精准)

12.23 SpringBoot中,bean还没有初始化好,消费者就开始监听取消息,导致空指针异常,怎么让消费者在容器启动完毕后才开始监听?

RabbitMQ中有一个auto_startup参数,可以控制是否在容器启动时就监听启动

全局参数:

spring.rabbitmq.listener.auto-startup=true   ##默认是true

自定义容器,容器可以应用到消费者:

// 默认是true

factory.setAutoStartup(true);

消费者单独设置

@RabbitListener( queues = "${com.gupaoedu.thirdqueue}" ,autoStartup = "false")

  1. ElasticSearch

13.1什么是ElasticSearch? 

Elasticsearch是一个基于Lucene的搜索引擎。它提供了具有HTTP Web界面和无架构JSON文档的分布式,多租户能力的全文搜索引擎。Elasticsearch是用Java开发的,根据Apache许可条款作为开源发布。

13.2 Elasticsearch中的倒排索引是什么? 

倒排索引是搜索引擎的核心。搜索引擎的主要目标是在查找发生搜索条件的文档时提供快速搜索。倒排索引是一种像数据结构一样的散列图,可将用户从单词导向文档或网页。它是搜索引擎的核心。其主要目标是快速搜索从数百万文件中查找数据。 

13.3 elasticsearch 了解多少,说说你们公司 es 的集群架构,索引数据大小,分片有多少,以及一些调优手段。

       ES 集群架构 13 个节点,索引根据通道不同共 20+索引,根据日期,每日递增 20+,索引:10 分片,每日递增 1 亿+数据,每个通道每天索引大小控制:150GB 之内。

仅索引层面调优手段:

1.1、设计阶段调优

(1)根据业务增量需求,采取基于日期模板创建索引,通过 roll over API 滚动索引;

(2)使用别名进行索引管理;

(3)每天凌晨定时对索引做 force_merge 操作,以释放空间;

(4)采取冷热分离机制,热数据存储到 SSD,提高检索效率;冷数据定期进行 shrink操作,以缩减存储;

(5)采取 curator 进行索引的生命周期管理;

(6)仅针对需要分词的字段,合理的设置分词器;

(7)Mapping 阶段充分结合各个字段的属性,是否需要检索、是否需要存储等。……..

1.2、写入调优

(1)写入前副本数设置为 0;

(2)写入前关闭 refresh_interval 设置为-1,禁用刷新机制;

(3)写入过程中:采取 bulk 批量写入;

(4)写入后恢复副本数和刷新间隔;

(5)尽量使用自动生成的 id。

1.3、查询调优

(1)禁用 wildcard;

(2)禁用批量 terms(成百上千的场景);

(3)充分利用倒排索引机制,能 keyword 类型尽量 keyword;

(4)数据量大时候,可以先基于时间敲定索引再检索;

(5)设置合理的路由机制。

1.4、其他调优

部署调优,业务调优等。

上面的提及一部分,面试者就基本对你之前的实践或者运维经验有所评估了。

13.4 elasticsearch 索引数据多了怎么办,如何调优,部署

1 动态索引层面

基于模板+时间+rollover api 滚动创建索引,举例:设计阶段定义:blog 索引的模板格式为:blog_index_时间戳的形式,每天递增数据。这样做的好处:不至于数据量激增导致单个索引数据量非常大,接近于上线 2 的32 次幂-1,索引存储达到了 TB+甚至更大。

一旦单个索引很大,存储等各种风险也随之而来,所以要提前考虑+及早避免。

2 存储层面

冷热数据分离存储,热数据(比如最近 3 天或者一周的数据),其余为冷数据。

对于冷数据不会再写入新数据,可以考虑定期 force_merge 加 shrink 压缩操作,节省存储空间和检索效率。

3 部署层面

一旦之前没有规划,这里就属于应急策略。

结合 ES 自身的支持动态扩展的特点,动态新增机器的方式可以缓解集群压力,注意:如果之前主节点等规划合理,不需要重启集群也能完成动态新增的。

13.5、elasticsearch 是如何实现 master 选举的

前置前提:

(1)只有候选主节点(master:true)的节点才能成为主节点。

(2)最小主节点数(min_master_nodes)的目的是防止脑裂。

核对了一下代码,核心入口为 findMaster,选择主节点成功返回对应 Master,否则返回 null。选举流程大致描述如下:

第一步:确认候选主节点数达标,elasticsearch.yml 设置的值

discovery.zen.minimum_master_nodes;

第二步:比较:先判定是否具备 master 资格,具备候选主节点资格的优先返回;

若两节点都为候选主节点,则 id 小的值会主节点。注意这里的 id 为 string 类型。

13.6详细描述一下 Elasticsearch 索引文档的过程

这里的索引文档应该理解为文档写入 ES,创建索引的过程。

文档写入包含:单文档写入和批量 bulk 写入,这里只解释一下:单文档写入流程。

记住官方文档中的这个图。

https://pic4.zhimg.com/v2-8469e65076a2fed4db4bb71599c6e2af_b.jpg

第一步:客户写集群某节点写入数据,发送请求。(如果没有指定路由/协调节点,请求的节点扮演路由节点的角色。)

第二步:节点 1 接受到请求后,使用文档_id 来确定文档属于分片 0。请求会被转到另外的节点,假定节点 3。因此分片 0 的主分片分配到节点 3 上。

第三步:节点 3 在主分片上执行写操作,如果成功,则将请求并行转发到节点 1和节点 2 的副本分片上,等待结果返回。所有的副本分片都报告成功,节点 3 将向协调节点(节点 1)报告成功,节点 1 向请求客户端报告写入成功。

13.7详细描述一下 Elasticsearch 搜索的过程?

搜索拆解为“query then fetch” 两个阶段。

query 阶段的目的:定位到位置,但不取。

步骤拆解如下:

(1)假设一个索引数据有 5 主+1 副本 共 10 分片,一次请求会命中(主或者副本分片中)的一个。

(2)每个分片在本地进行查询,结果返回到本地有序的优先队列中。

(3)第 2)步骤的结果发送到协调节点,协调节点产生一个全局的排序列表。

fetch 阶段的目的:取数据。

路由节点获取所有文档,返回给客户端。

13.8 Elasticsearch 在部署时,对 Linux 的设置有哪些优化方法

(1)关闭缓存 swap;

(2)堆内存设置为:Min(节点内存/2, 32GB);

(3)设置最大文件句柄数;

(4)线程池+队列大小根据业务需要做调整;

(5)磁盘存储 raid 方式——存储有条件使用 RAID10,增加单节点性能以及避免单节点存储故障。

13.9 Elasticsearch 中的节点(比如共 20 个),其中的 10 个选了一个 master,另外 10 个选了另一个 master,怎么办?

(1)当集群 master 候选数量不小于 3 个时,可以通过设置最少投票通过数量(discovery.zen.minimum_master_nodes)超过所有候选节点一半以上来解决脑裂问题;

(2)当候选数量为两个时,只能修改为唯一的一个 master 候选,其他作为 data节点,避免脑裂问题。

13.10对于 GC 方面,在使用 Elasticsearch 时要注意什么?

(1)倒排词典的索引需要常驻内存,无法 GC,需要监控 data node 上 segmentmemory 增长趋势。

(2)各类缓存,field cache, filter cache, indexing cache, bulk queue 等等,要设置合理的大小,并且要应该根据最坏的情况来看 heap 是否够用,也就是各类缓存全部占满的时候,还有 heap 空间可以分配给其他任务吗?避免采用 clear cache等“自欺欺人”的方式来释放内存。

(3)避免返回大量结果集的搜索与聚合。确实需要大量拉取数据的场景,可以采用scan & scroll api 来实现。

(4)cluster stats 驻留内存并无法水平扩展,超大规模集群可以考虑分拆成多个集群通过 tribe node 连接。

(5)想知道 heap 够不够,必须结合实际应用场景,并对集群的 heap 使用情况做持续的监控。

(6)根据监控数据理解内存需求,合理配置各类circuit breaker,将内存溢出风险降低到最低

13.11在并发情况下,Elasticsearch 如果保证读写一致?

(1) Optimistic concurrency control can be used through the version number to ensure that the new version will not be overwritten by the old version, and the application layer will handle specific conflicts;

(2) In addition, for write operations, the consistency level supports quorum/one/all, and the default is quorum, that is, only when most fragments are available, write operations are allowed. But even if most of them are available, there may be failures to write to the copy due to reasons such as the network, so that the copy is considered to be faulty, and the shard will be rebuilt on a different node.

(3) For read operations, you can set replication to sync (default), which makes the operation return after both the primary and replica fragments are completed; if you set replication to async, you can also set the search request parameter _preference Query the primary shard for primary to ensure that the document is the latest version.

Guess you like

Origin blog.csdn.net/leader_song/article/details/132390382