首页 文章 精选 留言 我的

精选列表

搜索[面试],共4912篇文章
优秀的个人博客,低调大师

最新一期Spring Boot 面试

问题一 什么是Spring Boot? 多年来,随着新功能的增加,spring变得越来越复杂。只需访问 https://spring.io/projects 页面,我们就会看到可以在我们的应用程序中使用的所有Spring项目的不同功能。如果必须启动一个新的Spring项目,我们必须添加构建路径或添加Maven依赖关系,配置应用程序服务器,添加spring配置。因此,开始一个新的spring项目需要很多努力,因为我们现在必须从头开始做所有事情。 Spring Boot是解决这个问题的方法。Spring Boot已经建立在现有spring框架之上。使用spring启动,我们避免了之前我们必须做的所有样板代码和配置。因此,Spring Boot可以帮助我们以最少的工作量,更加健壮地使用现有的Spring功能。 问题二 Spring Boot有哪些优点? Spring Boot的优点有: 减少开发,测试时间和努力。 使用JavaConfig有助于避免使用XML。 避免大量的Maven导入和各种版本冲突。 提供意见发展方法。 通过提供默认值快速开始开发。 没有单独的Web服务器需要。这意味着你不再需要启动Tomcat,Glassfish或其他任何东西。 需要更少的配置 因为没有web.xml文件。只需添加用@ Configuration注释的类,然后添加用@Bean注释的方法,Spring将自动加载对象并像以前一样对其进行管理。您甚至可以将@Autowired添加到bean方法中,以使Spring自动装入需要的依赖关系中。 基于环境的配置使用这些属性,您可以将您正在使用的环境传递到应用程序:-Dspring.profiles.active = {enviornment}。在加载主应用程序属性文件后,Spring将在(application{environment} .properties)中加载后续的应用程序属性文件。 问题三 什么是JavaConfig? Spring JavaConfig是Spring社区的产品,它提供了配置Spring IoC容器的纯Java方法。因此它有助于避免使用XML配置。使用JavaConfig的优点在于: 面向对象的配置。由于配置被定义为JavaConfig中的类,因此用户可以充分利用Java中的面向对象功能。一个配置类可以继承另一个,重写它的@Bean方法等。 减少或消除XML配置。基于依赖注入原则的外化配置的好处已被证明。但是,许多开发人员不希望在XML和Java之间来回切换。JavaConfig为开发人员提供了一种纯Java方法来配置与XML配置概念相似的Spring容器。从技术角度来讲,只使用JavaConfig配置类来配置容器是可行的,但实际上很多人认为将JavaConfig与XML混合匹配是理想的。 类型安全和重构友好。JavaConfig提供了一种类型安全的方法来配置Spring容器。由于Java 5.0对泛型的支持,现在可以按类型而不是按名称检索bean,不需要任何强制转换或基于字符串的查找。 问题四 如何重新加载Spring Boot上的更改,而无需重新启动服务器? 这可以使用DEV工具来实现。通过这种依赖关系,您可以节省任何更改,嵌入式tomcat将重新启动。Spring Boot有一个开发工具(DevTools)模块,它有助于提高开发人员的生产力。Java开发人员面临的一个主要挑战是将文件更改自动部署到服务器并自动重启服务器。开发人员可以重新加载Spring Boot上的更改,而无需重新启动服务器。这将消除每次手动部署更改的需要。Spring Boot在发布它的第一个版本时没有这个功能。这是开发人员最需要的功能。DevTools模块完全满足开发人员的需求。该模块将在生产环境中被禁用。它还提供H2数据库控制台以更好地测试应用程序。 org.springframework.boot spring-boot-devtools true 问题五 Spring Boot中的监视器是什么? Spring boot actuator是spring启动框架中的重要功能之一。Spring boot监视器可帮助您访问生产环境中正在运行的应用程序的当前状态。有几个指标必须在生产环境中进行检查和监控。即使一些外部应用程序可能正在使用这些服务来向相关人员触发警报消息。监视器模块公开了一组可直接作为HTTP URL访问的REST端点来检查状态。 问题六 如何在Spring Boot中禁用Actuator端点安全性? 默认情况下,所有敏感的HTTP端点都是安全的,只有具有ACTUATOR角色的用户才能访问它们。安全性是使用标准的HttpServletRequest.isUserInRole方法实施的。 我们可以使用 management.security.enabled = false 来禁用安全性。只有在执行机构端点在防火墙后访问时,才建议禁用安全性。 问题七 如何在自定义端口上运行Spring Boot应用程序? 为了在自定义端口上运行Spring Boot应用程序,您可以在application.properties中指定端口。 server.port = 8090 问题八 什么是YAML? YAML是一种人类可读的数据序列化语言。它通常用于配置文件。 与属性文件相比,如果我们想要在配置文件中添加复杂的属性,YAML文件就更加结构化,而且更少混淆。可以看出YAML具有分层配置数据。 问题九 如何实现Spring Boot应用程序的安全性? 为了实现Spring Boot的安全性,我们使用 spring-boot-starter-security依赖项,并且必须添加安全配置。它只需要很少的代码。配置类将必须扩展WebSecurityConfigurerAdapter并覆盖其方法。 问题十 如何集成Spring Boot和ActiveMQ? 对于集成Spring Boot和ActiveMQ,我们使用 spring-boot-starter-activemq 依赖关系。 它只需要很少的配置,并且不需要样板代码。 问题十一 如何使用Spring Boot实现分页和排序? 使用Spring Boot实现分页非常简单。使用Spring Data-JPA可以实现将可分页的 org.springframework.data.domain.Pageable 传递给存储库方法。 问题十二 什么是Swagger?你用Spring Boot实现了它吗? Swagger广泛用于可视化API,使用Swagger UI为前端开发人员提供在线沙箱。Swagger是用于生成RESTful Web服务的可视化表示的工具,规范和完整框架实现。它使文档能够以与服务器相同的速度更新。当通过Swagger正确定义时,消费者可以使用最少量的实现逻辑来理解远程服务并与其进行交互。因此,Swagger消除了调用服务时的猜测。 问题十三 什么是Spring Profiles? Spring Profiles允许用户根据配置文件(dev,test,prod等)来注册bean。因此,当应用程序在开发中运行时,只有某些bean可以加载,而在PRODUCTION中,某些其他bean可以加载。假设我们的要求是Swagger文档仅适用于QA环境,并且禁用所有其他文档。这可以使用配置文件来完成。Spring Boot使得使用配置文件非常简单。 问题十四 什么是Spring Batch? Spring Boot Batch提供可重用的函数,这些函数在处理大量记录时非常重要,包括日志/跟踪,事务管理,作业处理统计信息,作业重新启动,跳过和资源管理。它还提供了更先进的技术服务和功能,通过优化和分区技术,可以实现极高批量和高性能批处理作业。简单以及复杂的大批量批处理作业可以高度可扩展的方式利用框架处理重要大量的信息。 问题十五 什么是FreeMarker模板? FreeMarker是一个基于Java的模板引擎,最初专注于使用MVC软件架构进行动态网页生成。使用Freemarker的主要优点是表示层和业务层的完全分离。程序员可以处理应用程序代码,而设计人员可以处理html页面设计。最后使用freemarker可以将这些结合起来,给出最终的输出页面。 问题十六 如何使用Spring Boot实现异常处理? Spring提供了一种使用ControllerAdvice处理异常的非常有用的方法。 我们通过实现一个ControlerAdvice类,来处理控制器类抛出的所有异常。 问题十七 您使用了哪些starter maven依赖项? 使用了下面的一些依赖项 spring-boot-starter-activemq spring-boot-starter-security spring-boot-starter-web 这有助于增加更少的依赖关系,并减少版本的冲突。 问题十八 什么是CSRF攻击? CSRF代表跨站请求伪造。这是一种攻击,迫使最终用户在当前通过身份验证的Web应用程序上执行不需要的操作。CSRF攻击专门针对状态改变请求,而不是数据窃取,因为攻击者无法查看对伪造请求的响应。 问题十九 什么是WebSockets? WebSocket是一种计算机通信协议,通过单个TCP连接提供全双工通信信道。 WebSocket是双向的 -使用WebSocket客户端或服务器可以发起消息发送。 WebSocket是全双工的 -客户端和服务器通信是相互独立的。 单个TCP连接 -初始连接使用HTTP,然后将此连接升级到基于套接字的连接。然后这个单一连接用于所有未来的通信 Light -与http相比,WebSocket消息数据交换要轻得多。 问题二十 什么是AOP? 在软件开发过程中,跨越应用程序多个点的功能称为交叉问题。这些交叉问题与应用程序的主要业务逻辑不同。因此,将这些横切关注与业务逻辑分开是面向方面编程(AOP)的地方。 问题二十一 什么是Apache Kafka? Apache Kafka是一个分布式发布 - 订阅消息系统。它是一个可扩展的,容错的发布 - 订阅消息系统,它使我们能够构建分布式应用程序。这是一个Apache顶级项目。Kafka适合离线和在线消息消费。 问题二十二 我们如何监视所有Spring Boot微服务? Spring Boot提供监视器端点以监控各个微服务的度量。这些端点对于获取有关应用程序的信息(如它们是否已启动)以及它们的组件(如数据库等)是否正常运行很有帮助。但是,使用监视器的一个主要缺点或困难是,我们必须单独打开应用程序的知识点以了解其状态或健康状况。想象一下涉及50个应用程序的微服务,管理员将不得不击中所有50个应用程序的执行终端。

优秀的个人博客,低调大师

面试java基础(真的很实用,点个赞呗!)

J2SE 基础 八种基本数据类型的大小,以及他们的封装类。 八种基本数据类型,int ,double ,long ,float, short,byte,character,boolean 对应的封装类型是:Integer ,Double ,Long ,Float, Short,Byte,Character,Boolean Switch能否用string做参数? 在Java 5以前,switch(expr)中,expr只能是byte、short、char、int。从Java 5开始,Java中引入了枚举类型,expr也可以是enum类型,从Java 7开始,expr还可以是字符串(String),但是长整型(long)在目前所有的版本中都是不可以的。 equals与==的区别。 http://www.importnew.com/6804.html ==与equals的主要区别是:==常用于比较原生类型,而equals()方法用于检查对象的相等性。另一个不同的点是:如果==和equals()用于比较对象,当两个引用地址相同,==返回true。而equals()可以返回true或者false主要取决于重写实现。最常见的一个例子,字符串的比较,不同情况==和equals()返回不同的结果。equals()方法最重要的一点是,能够根据业务要求去重写,按照自定义规则去判断两个对象是否相等。重写equals()方法的时候,要注意一下hashCode是否会因为对象的属性改变而改变,否则在使用散列集合储存该对象的时候会碰到坑!!理解equals()方法的存在是很重要的。 使用==比较有两种情况: 比较基础数据类型(Java中基础数据类型包括八中:short,int,long,float,double,char,byte,boolen):这种情况下,==比较的是他们的值是否相等。 引用间的比较:在这种情况下,==比较的是他们在内存中的地址,也就是说,除非引用指向的是同一个new出来的对象,此时他们使用`==`去比较得到true,否则,得到false。 使用equals进行比较: equals追根溯源,是Object类中的一个方法,在该类中,equals的实现也仅仅只是比较两个对象的内存地址是否相等,但在一些子类中,如:String、Integer 等,该方法将被重写。 以String类为例子说明eqauls与==的区别: 在开始这个例子之前,同学们需要知道JVM处理String的一些特性。Java的虚拟机在内存中开辟出一块单独的区域,用来存储字符串对象,这块内存区域被称为字符串缓冲池。当使用String a = "abc"这样的语句进行定义一个引用的时候,首先会在字符串缓冲池中查找是否已经相同的对象,如果存在,那么就直接将这个对象的引用返回给a,如果不存在,则需要新建一个值为"abc"的对象,再将新的引用返回a。String a = new String("abc");这样的语句明确告诉JVM想要产生一个新的String对象,并且值为"abc",于是就在堆内存中的某一个小角落开辟了一个新的String对象。 - `==`在比较引用的情况下,会去比较两个引用的内存地址是否相等。 ``` String str1 = "abc"; String str2 = "abc"; System.out.println(str1 == str2); System.out.println(str1.equals(str2)); String str2 = new String("abc"); System.out.println(str1 == str2); System.out.println(str1.equals(str2)); ``` 以上代码将会输出 true true false true **第一个true:**因为在str2赋值之前,str1的赋值操作就已经在内存中创建了一个值为"abc"的对象了,然后str2将会与str1指向相同的地址。 **第二个true:**因为`String`已经重写了`equals`方法:为了方便大家阅读我贴出来,并且在注释用进行分析: ``` public boolean equals(Object anObject) { //如果比较的对象与自身内存地址相等的话 //就说明他两指向的是同一个对象 //所以此时equals的返回值跟==的结果是一样的。 if (this == anObject) { return true; } //当比较的对象与自身的内存地址不相等,并且 //比较的对象是String类型的时候 //将会执行这个分支 if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; //在这里循环遍历两个String中的char while (n-- != 0) { //只要有一个不相等,那么就会返回false if (v1[i] != v2[i]) return false; i++; } return true; } } return false; } ``` 进行以上分析之后,就不难理解第一段代码中的实例程序输出了。 Object有哪些公用方法? http://www.cnblogs.com/yumo/p/4908315.html 1.clone方法 保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常。 主要是JAVA里除了8种基本类型传参数是值传递,其他的类对象传参数都是引用传递,我们有时候不希望在方法里讲参数改变,这是就需要在类中复写clone方法。 2.getClass方法 final方法,获得运行时类型。 3.toString方法 该方法用得比较多,一般子类都有覆盖。 4.finalize方法 该方法用于释放资源。因为无法确定该方法什么时候被调用,很少使用。 5.equals方法 该方法是非常重要的一个方法。一般equals和==是不一样的,但是在Object中两者是一样的。子类一般都要重写这个方法。 6.hashCode方法 该方法用于哈希查找,可以减少在查找中使用equals的次数,重写了equals方法一般都要重写hashCode方法。这个方法在一些具有哈希功能的Collection中用到。 一般必须满足obj1.equals(obj2)==true。可以推出obj1.hashCode()==obj2.hashCode(),但是hashCode相等不一定就满足equals。不过为了提高效率,应该尽量使上面两个条件接近等价。 如果不重写hashCode(),在HashSet中添加两个equals的对象,会将两个对象都加入进去。 7.wait方法 wait方法就是使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait()方法一直等待,直到获得锁或者被中断。wait(long timeout)设定一个超时间隔,如果在规定时间内没有获得锁就返回。 调用该方法后当前线程进入睡眠状态,直到以下事件发生。 (1)其他线程调用了该对象的notify方法。 (2)其他线程调用了该对象的notifyAll方法。 (3)其他线程调用了interrupt中断该线程。 (4)时间间隔到了。 此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常。 8.notify方法 该方法唤醒在该对象上等待的某个线程。 9.notifyAll方法 该方法唤醒在该对象上等待的所有线程。 Java的四种引用,强弱软虚,用到的场景。 JDK1.2之前只有强引用,其他几种引用都是在JDK1.2之后引入的. 强引用(Strong Reference) 最常用的引用类型,如Object obj = new Object(); 。只要强引用存在则GC时则必定不被回收。 软引用(Soft Reference) 用于描述还有用但非必须的对象,当堆将发生OOM(Out Of Memory)时则会回收软引用所指向的内存空间,若回收后依然空间不足才会抛出OOM。一般用于实现内存敏感的高速缓存。 当真正对象被标记finalizable以及的finalize()方法调用之后并且内存已经清理, 那么如果SoftReference object还存在就被加入到它的 ReferenceQueue.只有前面几步完成后,Soft Reference和Weak Reference的get方法才会返回null 弱引用(Weak Reference) 发生GC时必定回收弱引用指向的内存空间。 和软引用加入队列的时机相同 虚引用(Phantom Reference) 又称为幽灵引用或幻影引用,虚引用既不会影响对象的生命周期,也无法通过虚引用来获取对象实例,仅用于在发生GC时接收一个系统通知。 当一个对象的finalize方法已经被调用了之后,这个对象的幽灵引用会被加入到队列中。通过检查该队列里面的内容就知道一个对象是不是已经准备要被回收了. 虚引用和软引用和弱引用都不同,它会在内存没有清理的时候被加入引用队列.虚引用的建立必须要传入引用队列,其他可以没有 Hashcode的作用。 http://c610367182.iteye.com/blog/1930676 以Java.lang.Object来理解,JVM每new一个Object,它都会将这个Object丢到一个Hash哈希表中去,这样的话,下次做Object的比较或者取这个对象的时候,它会根据对象的hashcode再从Hash表中取这个对象。这样做的目的是提高取对象的效率。具体过程是这样: new Object(),JVM根据这个对象的Hashcode值,放入到对应的Hash表对应的Key上,如果不同的对象确产生了相同的hash值,也就是发生了Hash key相同导致冲突的情况,那么就在这个Hash key的地方产生一个链表,将所有产生相同hashcode的对象放到这个单链表上去,串在一起。 比较两个对象的时候,首先根据他们的hashcode去hash表中找他的对象,当两个对象的hashcode相同,那么就是说他们这两个对象放在Hash表中的同一个key上,那么他们一定在这个key上的链表上。那么此时就只能根据Object的equal方法来比较这个对象是否equal。当两个对象的hashcode不同的话,肯定他们不能equal. String、StringBuffer与StringBuilder的区别。 Java 平台提供了两种类型的字符串:String和StringBuffer / StringBuilder,它们可以储存和操作字符串。其中String是只读字符串,也就意味着String引用的字符串内容是不能被改变的。而StringBuffer和StringBulder类表示的字符串对象可以直接进行修改。StringBuilder是JDK1.5引入的,它和StringBuffer的方法完全相同,区别在于它是单线程环境下使用的,因为它的所有方面都没有被synchronized修饰,因此它的效率也比StringBuffer略高。 try catch finally,try里有return,finally还执行么? 会执行,在方法 返回调用者前执行。Java允许在finally中改变返回值的做法是不好的,因为如果存在finally代码块,try中的return语句不会立马返回调用者,而是纪录下返回值待finally代码块执行完毕之后再向调用者返回其值,然后如果在finally中修改了返回值,这会对程序造成很大的困扰,C#中就从语法规定不能做这样的事。 Excption与Error区别 Error表示系统级的错误和程序不必处理的异常,是恢复不是不可能但很困难的情况下的一种严重问题;比如内存溢出,不可能指望程序能处理这样的状况;Exception表示需要捕捉或者需要程序进行处理的异常,是一种设计或实现问题;也就是说,它表示如果程序运行正常,从不会发生的情况。 Excption与Error包结构。OOM你遇到过哪些情况,SOF你遇到过哪些情况。 http://www.cnblogs.com/yumo/p/4909617.html Java异常架构图 image Throwable Throwable是 Java 语言中所有错误或异常的超类。 Throwable包含两个子类: Error 和 Exception 。它们通常用于指示发生了异常情况。 Throwable包含了其线程创建时线程执行堆栈的快照,它提供了printStackTrace()等接口用于获取堆栈跟踪数据等信息。 Exception Exception及其子类是 Throwable 的一种形式,它指出了合理的应用程序想要捕获的条件。 RuntimeException RuntimeException是那些可能在 Java 虚拟机正常运行期间抛出的异常的超类。 编译器不会检查RuntimeException异常。 例如,除数为零时,抛出ArithmeticException异常。RuntimeException是ArithmeticException的超类。当代码发生除数为零的情况时,倘若既"没有通过throws声明抛出ArithmeticException异常",也"没有通过try...catch...处理该异常",也能通过编译。这就是我们所说的"编译器不会检查RuntimeException异常"! 如果代码会产生RuntimeException异常,则需要通过修改代码进行避免。 例如,若会发生除数为零的情况,则需要通过代码避免该情况的发生! Error 和Exception一样, Error也是Throwable的子类。 它用于指示合理的应用程序不应该试图捕获的严重问题,大多数这样的错误都是异常条件。 和RuntimeException一样, 编译器也不会检查Error。 Java将可抛出(Throwable)的结构分为三种类型: 被检查的异常(Checked Exception),运行时异常(RuntimeException)和错误(Error)。 (01) 运行时异常 定义 : RuntimeException及其子类都被称为运行时异常。 特点 : Java编译器不会检查它。 也就是说,当程序中可能出现这类异常时,倘若既"没有通过throws声明抛出它",也"没有用try-catch语句捕获它",还是会编译通过。例如,除数为零时产生的ArithmeticException异常,数组越界时产生的IndexOutOfBoundsException异常,fail-fail机制产生的ConcurrentModificationException异常等,都属于运行时异常。 虽然Java编译器不会检查运行时异常,但是我们也可以通过throws进行声明抛出,也可以通过try-catch对它进行捕获处理。 如果产生运行时异常,则需要通过修改代码来进行避免。 例如,若会发生除数为零的情况,则需要通过代码避免该情况的发生! (02) 被检查的异常 定义 : Exception类本身,以及Exception的子类中除了"运行时异常"之外的其它子类都属于被检查异常。 特点 : Java编译器会检查它。 此类异常,要么通过throws进行声明抛出,要么通过try-catch进行捕获处理,否则不能通过编译。例如,CloneNotSupportedException就属于被检查异常。当通过clone()接口去克隆一个对象,而该对象对应的类没有实现Cloneable接口,就会抛出CloneNotSupportedException异常。 被检查异常通常都是可以恢复的。 (03) 错误 定义 : Error类及其子类。 特点 : 和运行时异常一样,编译器也不会对错误进行检查。 当资源不足、约束失败、或是其它程序无法继续运行的条件发生时,就产生错误。程序本身无法修复这些错误的。例如,VirtualMachineError就属于错误。 按照Java惯例,我们是不应该是实现任何新的Error子类的! 对于上面的3种结构,我们在抛出异常或错误时,到底该哪一种?《Effective Java》中给出的建议是: 对于可以恢复的条件使用被检查异常,对于程序错误使用运行时异常。 OOM: OutOfMemoryError异常 除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生OutOfMemoryError(OOM)异常的可能, Java Heap 溢出 一般的异常信息:java.lang.OutOfMemoryError:Java heap spacess java堆用于存储对象实例,我们只要不断的创建对象,并且保证GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,就会在对象数量达到最大堆容量限制后产生内存溢出异常。 出现这种异常,一般手段是先通过内存映像分析工具(如Eclipse Memory Analyzer)对dump出来的堆转存快照进行分析,重点是确认内存中的对象是否是必要的,先分清是因为内存泄漏(Memory Leak)还是内存溢出(Memory Overflow)。 如果是内存泄漏,可进一步通过工具查看泄漏对象到GC Roots的引用链。于是就能找到泄漏对象时通过怎样的路径与GC Roots相关联并导致垃圾收集器无法自动回收。 如果不存在泄漏,那就应该检查虚拟机的参数(-Xmx与-Xms)的设置是否适当。 虚拟机栈和本地方法栈溢出 如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。 如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常 这里需要注意当栈的大小越大可分配的线程数就越少。 运行时常量池溢出 异常信息:java.lang.OutOfMemoryError:PermGen space 如果要向运行时常量池中添加内容,最简单的做法就是使用String.intern()这个Native方法。该方法的作用是:如果池中已经包含一个等于此String的字符串,则返回代表池中这个字符串的String对象;否则,将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。由于常量池分配在方法区内,我们可以通过-XX:PermSize和-XX:MaxPermSize限制方法区的大小,从而间接限制其中常量池的容量。 方法区溢出 方法区用于存放Class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。 异常信息:java.lang.OutOfMemoryError:PermGen space 方法区溢出也是一种常见的内存溢出异常,一个类如果要被垃圾收集器回收,判定条件是很苛刻的。在经常动态生成大量Class的应用中,要特别注意这点。 Java面向对象的三个特征与含义。 继承:继承是从已有类得到继承信息创建新类的过程。提供继承信息的类被称为父类(超类、基类);得到继承信息的类被称为子类(派生类)。继承让变化中的软件系统有了一定的延续性,同时继承也是封装程序中可变因素的重要手段。 封装:通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。面向对象的本质就是将现实世界描绘成一系列完全自治、封闭的对象。我们在类中编写的方法就是对实现细节的一种封装;我们编写一个类就是对数据和数据操作的封装。可以说,封装就是隐藏一切可隐藏的东西,只向外界提供最简单的编程接口(可以想想普通洗衣机和全自动洗衣机的差别,明显全自动洗衣机封装更好因此操作起来更简单;我们现在使用的智能手机也是封装得足够好的,因为几个按键就搞定了所有的事情)。 多态:多态性是指允许不同子类型的对象对同一消息作出不同的响应。简单的说就是用同样的对象引用调用同样的方法但是做了不同的事情。多态性分为编译时的多态性和运行时的多态性。如果将对象的方法视为对象向外界提供的服务,那么运行时的多态性可以解释为:当A系统访问B系统提供的服务时,B系统有多种提供服务的方式,但一切对A系统来说都是透明的(就像电动剃须刀是A系统,它的供电系统是B系统,B系统可以使用电池供电或者用交流电,甚至还有可能是太阳能,A系统只会通过B类对象调用供电的方法,但并不知道供电系统的底层实现是什么,究竟通过何种方式获得了动力)。方法重载(overload)实现的是编译时的多态性(也称为前绑定),而方法重写(override)实现的是运行时的多态性(也称为后绑定)。运行时的多态是面向对象最精髓的东西,要实现多态需要做两件事:1. 方法重写(子类继承父类并重写父类中已有的或抽象的方法);2. 对象造型(用父类型引用引用子类型对象,这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为)。 Override和Overload的含义与区别。 Overload:顾名思义,就是Over(重新)——load(加载),所以中文名称是重载。它可以表现类的多态性,可以是函数里面可以有相同的函数名但是参数名、类型不能相同;或者说可以改变参数、类型但是函数名字依然不变。 Override:就是ride(重写)的意思,在子类继承父类的时候子类中可以定义某方法与其父类有相同的名称和参数,当子类在调用这一函数时自动调用子类的方法,而父类相当于被覆盖(重写)了。 方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被“屏蔽”了。如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。Overloaded的方法是可以改变返回值的类型。 Interface与abstract类的区别。 抽象类和接口都不能够实例化,但可以定义抽象类和接口类型的引用。一个类如果继承了某个抽象类或者实现了某个接口都需要对其中的抽象方法全部进行实现,否则该类仍然需要被声明为抽象类。接口比抽象类更加抽象,因为抽象类中可以定义构造器,可以有抽象方法和具体方法,而接口中不能定义构造器而且其中的方法全部都是抽象方法。抽象类中的成员可以是private、默认、protected、public的,而接口中的成员全都是public的。抽象类中可以定义成员变量,而接口中定义的成员变量实际上都是常量。有抽象方法的类必须被声明为抽象类,而抽象类未必要有抽象方法。 Static class 与non static class的区别。 内部静态类不需要有指向外部类的引用。但非静态内部类需要持有对外部类的引用。非静态内部类能够访问外部类的静态和非静态成员。静态类不能访问外部类的非静态成员。他只能访问外部类的静态成员。一个非静态内部类不能脱离外部类实体被创建,一个非静态内部类可以访问外部类的数据和方法,因为他就在外部类里面。 java多态的实现原理。 http://blog.csdn.net/zzzhangzhun/article/details/51095075 当JVM执行Java字节码时,类型信息会存储在方法区中,为了优化对象的调用方法的速度,方法区的类型信息会增加一个指针,该指针指向一个记录该类方法的方法表,方法表中的每一个项都是对应方法的指针。 方法区:方法区和JAVA堆一样,是各个线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。 运行时常量池:它是方法区的一部分,Class文件中除了有类的版本、方法、字段等描述信息外,还有一项信息是常量池,用于存放编译器生成的各种符号引用,这部分信息在类加载时进入方法区的运行时常量池中。 方法区的内存回收目标是针对常量池的回收及对类型的卸载。 方法表的构造 由于java的单继承机制,一个类只能继承一个父类,而所有的类又都继承Object类,方法表中最先存放的是Object的方法,接下来是父类的方法,最后是该类本身的方法。如果子类改写了父类的方法,那么子类和父类的那些同名的方法共享一个方法表项。 由于这样的特性,使得方法表的偏移量总是固定的,例如,对于任何类来说,其方法表的equals方法的偏移量总是一个定值,所有继承父类的子类的方法表中,其父类所定义的方法的偏移量也总是一个定值。 实例 假设Class A是Class B的子类,并且A改写了B的方法的method(),那么B来说,method方法的指针指向B的method方法入口;对于A来说,A的方法表的method项指向自身的method而非父类的。 流程:调用方法时,虚拟机通过对象引用得到方法区中类型信息的方法表的指针入口,查询类的方法表 ,根据实例方法的符号引用解析出该方法在方法表的偏移量,子类对象声明为父类类型时,形式上调用的是父类的方法,此时虚拟机会从实际的方法表中找到方法地址,从而定位到实际类的方法。 注:所有引用为父类,但方法区的类型信息中存放的是子类的信息,所以调用的是子类的方法表。 foreach与正常for循环效率对比。 http://904510742.iteye.com/blog/2118331 直接for循环效率最高,其次是迭代器和 ForEach操作。 作为语法糖,其实 ForEach 编译成 字节码之后,使用的是迭代器实现的,反编译后,testForEach方法如下: public static void testForEach(List list) { for (Iterator iterator = list.iterator(); iterator.hasNext();) { Object t = iterator.next(); Object obj = t; } } 可以看到,只比迭代器遍历多了生成中间变量这一步,因为性能也略微下降了一些。 反射机制 JAVA反射机制是在运行状态中, 对于任意一个类, 都能够知道这个类的所有属性和方法; 对于任意一个对象, 都能够调用它的任意一个方法和属性; 这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制. 主要作用有三: 运行时取得类的方法和字段的相关信息。 创建某个类的新实例(.newInstance()) 取得字段引用直接获取和设置对象字段,无论访问修饰符是什么。 用处如下: 观察或操作应用程序的运行时行为。 调试或测试程序,因为可以直接访问方法、构造函数和成员字段。 通过名字调用不知道的方法并使用该信息来创建对象和调用方法。 String类内部实现,能否改变String对象内容 String源码分析 http://blog.csdn.net/zhangjg_blog/article/details/18319521 try catch 块,try里有return,finally也有return,如何执行 http://qing0991.blog.51cto.com/1640542/1387200 泛型的优缺点 优点: 使用泛型类型可以最大限度地重用代码、保护类型的安全以及提高性能。 泛型最常见的用途是创建集合类。 缺点: 在性能上不如数组快。 泛型常用特点,List<String>能否转为List<Object> 能,但是利用类都继承自Object,所以使用是每次调用里面的函数都要通过强制转换还原回原来的类,这样既不安全,运行速度也慢。 解析XML的几种方式的原理与特点:DOM、SAX、PULL。 http://www.cnblogs.com/HaroldTihan/p/4316397.html Java与C++对比。 http://developer.51cto.com/art/201106/270422.htm Java1.7与1.8新特性。 http://blog.chinaunix.net/uid-29618857-id-4416835.html JNI的使用。 http://landerlyoung.github.io/blog/2014/10/16/java-zhong-jnide-shi-yong/ 集合 ArrayList、LinkedList、Vector的底层实现和区别 从同步性来看,ArrayList和LinkedList是不同步的,而Vector是的。所以线程安全的话,可以使用ArrayList或LinkedList,可以节省为同步而耗费的开销。但在多线程下,有时候就不得不使用Vector了。当然,也可以通过一些办法包装ArrayList、LinkedList,使我们也达到同步,但效率可能会有所降低。 从内部实现机制来讲ArrayList和Vector都是使用Object的数组形式来存储的。当你向这两种类型中增加元素的时候,如果元素的数目超出了内部数组目前的长度它们都需要扩展内部数组的长度,Vector缺省情况下自动增长原来一倍的数组长度,ArrayList是原来的50%,所以最后你获得的这个集合所占的空间总是比你实际需要的要大。如果你要在集合中保存大量的数据,那么使用Vector有一些优势,因为你可以通过设置集合的初始化大小来避免不必要的资源开销。 ArrayList和Vector中,从指定的位置(用index)检索一个对象,或在集合的末尾插入、删除一个对象的时间是一样的,可表示为O(1)。但是,如果在集合的其他位置增加或者删除元素那么花费的时间会呈线性增长O(n-i),其中n代表集合中元素的个数,i代表元素增加或移除元素的索引位置,因为在进行上述操作的时候集合中第i和第i个元素之后的所有元素都要执行(n-i)个对象的位移操作。LinkedList底层是由双向循环链表实现的,LinkedList在插入、删除集合中任何位置的元素所花费的时间都是一样的O(1),但它在索引一个元素的时候比较慢,为O(i),其中i是索引的位置,如果只是查找特定位置的元素或只在集合的末端增加、移除元素,那么使用Vector或ArrayList都可以。如果是对其它指定位置的插入、删除操作,最好选择LinkedList。 HashMap和HashTable的底层实现和区别,两者和ConcurrentHashMap的区别。 http://blog.csdn.net/xuefeng0707/article/details/40834595 HashTable线程安全则是依靠方法简单粗暴的sychronized修饰,HashMap则没有相关的线程安全问题考虑。。 在以前的版本貌似ConcurrentHashMap引入了一个“分段锁”的概念,具体可以理解为把一个大的Map拆分成N个小的HashTable,根据key.hashCode()来决定把key放到哪个HashTable中。在ConcurrentHashMap中,就是把Map分成了N个Segment,put和get的时候,都是现根据key.hashCode()算出放到哪个Segment中。 通过把整个Map分为N个Segment(类似HashTable),可以提供相同的线程安全,但是效率提升N倍。 HashMap的hashcode的作用?什么时候需要重写?如何解决哈希冲突?查找的时候流程是如何? 从源码分析HashMap Arraylist和HashMap如何扩容?负载因子有什么作用?如何保证读写进程安全? http://m.blog.csdn.net/article/details?id=48956087 http://hovertree.com/h/bjaf/2jdr60li.htm ArrayList 本身不是线程安全的。 所以正确的做法是去用 java.util.concurrent 里的 CopyOnWriteArrayList 或者某个同步的 Queue 类。 HashMap实现不是同步的。如果多个线程同时访问一个哈希映射,而其中至少一个线程从结构上修改了该映射,则它必须 保持外部同步。(结构上的修改是指添加或删除一个或多个映射关系的任何操作;仅改变与实例已经包含的键关联的值不是结构上的修改。)这一般通过对自然封装该映射的对象进行同步操作来完成。如果不存在这样的对象,则应该使用 Collections.synchronizedMap 方法来“包装”该映射。最好在创建时完成这一操作,以防止对映射进行意外的非同步访问. TreeMap、HashMap、LinkedHashMap的底层实现区别。 http://blog.csdn.net/lolashe/article/details/20806319 Collection包结构,与Collections的区别。 Collection是一个接口,它是Set、List等容器的父接口;Collections是一个工具类,提供了一系列的静态方法来辅助容器操作,这些方法包括对容器的搜索、排序、线程安全化等等。 Set、List之间的区别是什么? http://developer.51cto.com/art/201309/410205_all.htm Map、Set、List、Queue、Stack的特点与用法。 http://www.cnblogs.com/yumo/p/4908718.html Collection 是对象集合, Collection 有两个子接口 List 和 Set List 可以通过下标 (1,2..) 来取得值,值可以重复 而 Set 只能通过游标来取值,并且值是不能重复的 ArrayList , Vector , LinkedList 是 List 的实现类 ArrayList 是线程不安全的, Vector 是线程安全的,这两个类底层都是由数组实现的 LinkedList 是线程不安全的,底层是由链表实现的 Map 是键值对集合 HashTable 和 HashMap 是 Map 的实现类 HashTable 是线程安全的,不能存储 null 值 HashMap 不是线程安全的,可以存储 null 值 Stack类:继承自Vector,实现一个后进先出的栈。提供了几个基本方法,push、pop、peak、empty、search等。 Queue接口:提供了几个基本方法,offer、poll、peek等。已知实现类有LinkedList、PriorityQueue等。

优秀的个人博客,低调大师

春季最新最全面 JAVA 面试题 附答案

包含的重点内容: JAVA基础 JVM 知识 开源框架知识 操作系统 多线程 TCP 与 HTTP 架构设计与分布式 算法 数据库知识 消息队列 Redis,Memcached 搜索 JAVA基础 JAVA中的几种基本类型,各占用多少字节? image 下图单位是bit,非字节 1B=8bit image String能被继承吗?为什么? 不可以,因为String类有final修饰符,而final修饰的类是不能被继承的,实现细节不允许改变。平常我们定义的String str=”a”;其实和String str=new String(“a”)还是有差异的。 前者默认调用的是String.valueOf来返回String实例对象,至于调用哪个则取决于你的赋值,比如String num=1,调用的是 public static String valueOf(int i) { return Integer.toString(i); } 后者则是调用如下部分: public String(String original) { this.value = original.value; this.hash = original.hash; } 最后我们的变量都存储在一个char数组中 private final char value[]; String, Stringbuffer, StringBuilder 的区别。 String 字符串常量(final修饰,不可被继承),String是常量,当创建之后即不能更改。(可以通过StringBuffer和StringBuilder创建String对象(常用的两个字符串操作类)。) StringBuffer 字符串变量(线程安全),其也是final类别的,不允许被继承,其中的绝大多数方法都进行了同步处理,包括常用的Append方法也做了同步处理(synchronized修饰)。其自jdk1.0起就已经出现。其toString方法会进行对象缓存,以减少元素复制开销。 public synchronized String toString() { if (toStringCache == null) { toStringCache = Arrays.copyOfRange(value, 0, count); } return new String(toStringCache, true); } StringBuilder 字符串变量(非线程安全)其自jdk1.5起开始出现。与StringBuffer一样都继承和实现了同样的接口和类,方法除了没使用synch修饰以外基本一致,不同之处在于最后toString的时候,会直接返回一个新对象。 public String toString() { // Create a copy, don’t share the array return new String(value, 0, count); } ArrayList 和 LinkedList 有什么区别。 ArrayList和LinkedList都实现了List接口,有以下的不同点: 1、ArrayList是基于索引的数据接口,它的底层是数组。它可以以O(1)时间复杂度对元素进行随机访问。与此对应,LinkedList是以元素列表的形式存储它的数据,每一个元素都和它的前一个和后一个元素链接在一起,在这种情况下,查找某个元素的时间复杂度是O(n)。 2、相对于ArrayList,LinkedList的插入,添加,删除操作速度更快,因为当元素被添加到集合任意位置的时候,不需要像数组那样重新计算大小或者是更新索引。 3、LinkedList比ArrayList更占内存,因为LinkedList为每一个节点存储了两个引用,一个指向前一个元素,一个指向下一个元素。 讲讲类的实例化顺序,比如父类静态数据,构造函数,字段,子类静态数据,构造函数,字段,当 new 的时候, 他们的执行顺序。 此题考察的是类加载器实例化时进行的操作步骤(加载–>连接->初始化)。 父类静态代变量、 父类静态代码块、 子类静态变量、 子类静态代码块、 父类非静态变量(父类实例成员变量)、 父类构造函数、 子类非静态变量(子类实例成员变量)、 子类构造函数。 测试demo:http://blog.csdn.net/u014042066/article/details/77574956 参阅我的博客《深入理解类加载》:http://blog.csdn.net/u014042066/article/details/77394480 用过哪些 Map 类,都有什么区别,HashMap 是线程安全的吗,并发下使用的 Map 是什么,他们内部原理分别是什么,比如存储方式, hashcode,扩容, 默认容量等。 hashMap是线程不安全的,HashMap是数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的,采用哈希表来存储的, 参照该链接:https://zhuanlan.zhihu.com/p/21673805 JAVA8 的 ConcurrentHashMap 为什么放弃了分段锁,有什么问题吗,如果你来设计,你如何设计。 参照:https://yq.aliyun.com/articles/36781 有没有有顺序的 Map 实现类, 如果有, 他们是怎么保证有序的。 TreeMap和LinkedHashMap是有序的(TreeMap默认升序,LinkedHashMap则记录了插入顺序)。 参照:http://uule.iteye.com/blog/1522291 抽象类和接口的区别,类可以继承多个类么,接口可以继承多个接口么,类可以实现多个接口么。 1、抽象类和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象。 2、抽象类要被子类继承,接口要被类实现。 3、接口只能做方法申明,抽象类中可以做方法申明,也可以做方法实现 4、接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。 5、抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,一个实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类。 6、抽象方法只能申明,不能实现。abstract void abc();不能写成abstract void abc(){}。 7、抽象类里可以没有抽象方法 8、如果一个类里有抽象方法,那么这个类只能是抽象类 9、抽象方法要被实现,所以不能是静态的,也不能是私有的。 10、接口可继承接口,并可多继承接口,但类只能单根继承。 继承和聚合的区别在哪。 继承指的是一个类(称为子类、子接口)继承另外的一个类(称为父类、父接口)的功能,并可以增加它自己的新功能的能力,继承是类与类或者接口与接口之间最常见的关系;在Java中此类关系通过关键字extends明确标识,在设计时一般没有争议性; image.png 聚合是关联关系的一种特例,他体现的是整体与部分、拥有的关系,即has-a的关系,此时整体与部分之间是可分离的,他们可以具有各自的生命周期,部分可以属于多个整体对象,也可以为多个整体对象共享;比如计算机与CPU、公司与员工的关系等;表现在代码层面,和关联关系是一致的,只能从语义级别来区分; image.png 参考:http://www.cnblogs.com/jiqing9006/p/5915023.html 讲讲你理解的 nio和 bio 的区别是啥,谈谈 reactor 模型。 IO是面向流的,NIO是面向缓冲区的 参考:https://zhuanlan.zhihu.com/p/23488863http://developer.51cto.com/art/201103/252367.htmhttp://www.jianshu.com/p/3f703d3d804c 反射的原理,反射创建类实例的三种方式是什么 参照:http://www.jianshu.com/p/3ea4a6b57f87?amp http://blog.csdn.net/yongjian1092/article/details/7364451 反射中,Class.forName 和 ClassLoader 区别。 https://my.oschina.net/gpzhang/blog/486743 描述动态代理的几种实现方式,分别说出相应的优缺点。 Jdk cglib jdk底层是利用反射机制,需要基于接口方式,这是由于 Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); Cglib则是基于asm框架,实现了无反射机制进行代理,利用空间来换取了时间,代理效率高于jdkhttp://lrd.ele.me/2017/01/09/dynamic_proxy/ 动态代理与 cglib 实现的区别 同上(基于invocationHandler和methodInterceptor) 为什么 CGlib 方式可以对接口实现代理。 同上 final 的用途****类、变量、方法 http://www.importnew.com/7553.html 写出三种单例模式实现。 懒汉式单例,饿汉式单例,双重检查等 参考:https://my.oschina.net/dyyweb/blog/609021 如何在父类中为子类自动完成所有的 hashcode 和 equals 实现?这么做有何优劣。 同时复写hashcode和equals方法,优势可以添加自定义逻辑,且不必调用超类的实现。 参照:http://java-min.iteye.com/blog/1416727 请结合 OO 设计理念,谈谈访问修饰符 public、private、protected、default 在应用设计中的作用。 访问修饰符,主要标示修饰块的作用域,方便隔离防护 image.png public: Java语言中访问限制最宽的修饰符,一般称之为“公共的”。被其修饰的类、属性以及方法不 仅可以跨类访问,而且允许跨包(package)访问。 private: Java语言中对访问权限限制的最窄的修饰符,一般称之为“私有的”。被其修饰的类、属性以 及方法只能被该类的对象访问,其子类不能访问,更不能允许跨包访问。 protect: 介于public 和 private 之间的一种访问修饰符,一般称之为“保护形”。被其修饰的类、 属性以及方法只能被类本身的方法及子类访问,即使子类在不同的包中也可以访问。 default:即不加任何访问修饰符,通常称为“默认访问模式“。该模式下,只允许在同一个包中进行访 问。 深拷贝和浅拷贝区别。 http://www.oschina.net/translate/java-copy-shallow-vs-deep-in-which-you-will-swim 数组和链表数据结构描述,各自的时间复杂度 http://blog.csdn.net/snow_wu/article/details/53172721 error 和 exception 的区别,CheckedException,RuntimeException 的区别 http://blog.csdn.net/woshixuye/article/details/8230407 请列出 5 个运行时异常。 同上 在自己的代码中,如果创建一个 java.lang.String 对象,这个对象是否可以被类加载器加载?为什么 类加载无须等到“首次使用该类”时加载,jvm允许预加载某些类。。。。http://www.cnblogs.com/jasonstorm/p/5663864.html 说一说你对 java.lang.Object 对象中 hashCode 和 equals 方法的理解。在什么场景下需要重新实现这两个方法。 参考上边试题 在 jdk1.5 中,引入了泛型,泛型的存在是用来解决什么问题。 泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数,泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,以提高代码的重用率http://baike.baidu.com/item/java%E6%B3%9B%E5%9E%8B 这样的 a.hashcode() 有什么用,与 a.equals(b)有什么关系。 hashcode hashcode()方法提供了对象的hashCode值,是一个native方法,返回的默认值与System.identityHashCode(obj)一致。 通常这个值是对象头部的一部分二进制位组成的数字,具有一定的标识对象的意义存在,但绝不定于地址。 作用是:用一个数字来标识对象。比如在HashMap、HashSet等类似的集合类中,如果用某个对象本身作为Key,即要基于这个对象实现Hash的写入和查找,那么对象本身如何实现这个呢?就是基于hashcode这样一个数字来完成的,只有数字才能完成计算和对比操作。 **hashcode是否唯一 ** hashcode只能说是标识对象,在hash算法中可以将对象相对离散开,这样就可以在查找数据的时候根据这个key快速缩小数据的范围,但hashcode不一定是唯一的,所以hash算法中定位到具体的链表后,需要循环链表,然后通过equals方法来对比Key是否是一样的。 **equals与hashcode的关系 ** equals相等两个对象,则hashcode一定要相等。但是hashcode相等的两个对象不一定equals相等。https://segmentfault.com/a/1190000004520827 有没有可能 2 个不相等的对象有相同的 hashcode。 有 Java 中的 HashSet 内部是如何工作的。 底层是基于hashmap实现的http://wiki.jikexueyuan.com/project/java-collection/hashset.html **什么是序列化,怎么序列化,为什么序列化,反序列化会遇到什么问题,如何解决。 **http://www.importnew.com/17964.html JVM 知识 什么情况****下会发生栈内存溢出。 如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常。 如果虚拟机在动态扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。 参照:http://wiki.jikexueyuan.com/project/java-vm/storage.html JVM 的内存结构,Eden 和 Survivor 比例。 image eden 和 survior 是按8比1分配的http://blog.csdn.net/lojze_ly/article/details/49456255 jvm 中一次完整的 GC 流程是怎样的,对象如何晋升到老年代,说说你知道的几种主要的jvm 参数。 对象诞生即新生代->eden,在进行minor gc过程中,如果依旧存活,移动到from,变成Survivor,进行标记代数,如此检查一定次数后,晋升为老年代,http://www.cnblogs.com/redcreen/archive/2011/05/04/2037056.htmlhttp://ifeve.com/useful-jvm-flags/https://wangkang007.gitbooks.io/jvm/content/jvmcan_shu_xiang_jie.html 你知道哪几种垃圾收集器,各自的优缺点,重点讲下 cms,包括原理,流程,优缺点 Serial、parNew、ParallelScavenge、SerialOld、ParallelOld、CMS、G1https://wangkang007.gitbooks.io/jvm/content/chapter1.html 垃圾回收算法的实现原理。 http://www.importnew.com/13493.html 当出现了内存溢出,你怎么排错。 首先分析是什么类型的内存溢出,对应的调整参数或者优化代码。https://wangkang007.gitbooks.io/jvm/content/4jvmdiao_you.html JVM 内存模型的相关知识了解多少,比如重排序,内存屏障,happen-before,主内存,工作内存等。 内存屏障:为了保障执行顺序和可见性的一条cpu指令 重排序:为了提高性能,编译器和处理器会对执行进行重拍 happen-before:操作间执行的顺序关系。有些操作先发生。 主内存:共享变量存储的区域即是主内存 工作内存:每个线程copy的本地内存,存储了该线程以读/写共享变量的副本http://ifeve.com/java-memory-model-1/http://www.jianshu.com/p/d3fda02d4caehttp://blog.csdn.net/kenzyq/article/details/50918457 简单说说你了解的类加载器。 类加载器的分类(bootstrap,ext,app,curstom),类加载的流程(load-link-init)http://blog.csdn.net/gjanyanlig/article/details/6818655/ 讲讲 JAVA 的反射机制。 Java程序在运行状态可以动态的获取类的所有属性和方法,并实例化该类,调用方法的功能http://baike.baidu.com/link?url=C7p1PeLa3ploAgkfAOK-4XHE8HzQuOAB7K5GPcK_zpbAa_Aw-nO3997K1oir8N–1_wxXZfOThFrEcA0LjVP6wNOwidVTkLBzKlQVK6JvXYvVNhDWV9yF-NIOebtg1hwsnagsjUhOE2wxmiup20RRa#7 你们线上应用的 JVM 参数有哪些。 -server Xms6000M -Xmx6000M -Xmn500M -XX:PermSize=500M -XX:MaxPermSize=500M -XX:SurvivorRatio=65536 -XX:MaxTenuringThreshold=0 -Xnoclassgc -XX:+DisableExplicitGC -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+CMSClassUnloadingEnabled -XX:-CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=90 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+PrintClassHistogram -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -Xloggc:log/gc.log g1 和 cms 区别,吞吐量优先和响应优先的垃圾收集器选择。 Cms是以获取最短回收停顿时间为目标的收集器。基于标记-清除算法实现。比较占用cpu资源,切易造成碎片。 G1是面向服务端的垃圾收集器,是jdk9默认的收集器,基于标记-整理算法实现。可利用多核、多cpu,保留分代,实现可预测停顿,可控。http://blog.csdn.net/linhu007/article/details/48897597 请解释如下 jvm 参数的含义: -server -Xms512m -Xmx512m -Xss1024K -XX:PermSize=256m -XX:MaxPermSize=512m -XX:MaxTenuringThreshold=20 XX:CMSInitiatingOccupancyFraction=80 -XX:+UseCMSInitiatingOccupancyOnly。 Server模式启动 最小堆内存512m 最大512m 每个线程栈空间1m 永久代256 最大永久代256 最大转为老年代检查次数20 Cms回收开启时机:内存占用80% 命令JVM不基于运行时收集的数据来启动CMS垃圾收集周期 开源框架知识 简单讲讲 tomcat 结构,以及其类加载器流程。 Server- –多个service Container级别的:–>engine–》host–>context Listenter Connector Logging、Naming、Session、JMX等等 image 通过WebappClassLoader 加载classhttp://www.ibm.com/developerworks/cn/java/j-lo-tomcat1/http://blog.csdn.net/dc_726/article/details/11873343http://www.cnblogs.com/xing901022/p/4574961.htmlhttp://www.jianshu.com/p/62ec977996df tomcat 如何调优,涉及哪些参数。 硬件上选择,操作系统选择,版本选择,jdk选择,配置jvm参数,配置connector的线程数量,开启gzip压缩,trimSpaces,集群等http://blog.csdn.net/lifetragedy/article/details/7708724 讲讲 Spring 加载流程。 通过listener入口,核心是在AbstractApplicationContext的refresh方法,在此处进行装载bean工厂,bean,创建bean实例,拦截器,后置处理器等。https://www.ibm.com/developerworks/cn/java/j-lo-spring-principle/ 讲讲 Spring 事务的传播属性。 七种传播属性。 事务传播行为 所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。在TransactionDefinition定义中包括了如下几个表示传播行为的常量: TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。 TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。 TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。 TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。 TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。 TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。 TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。https://www.ibm.com/developerworks/cn/education/opensource/os-cn-spring-trans/ Spring 如何管理事务的。 编程式和声明式 同上 Spring 怎么配置事务(具体说出一些关键的 xml 元素)。 说说你对 Spring 的理解,非单例注入的原理?它的生命周期?循环注入的原理, aop 的实现原理,说说 aop 中的几个术语,它们是怎么相互工作的。 核心组件:bean,context,core,单例注入是通过单例beanFactory进行创建,生命周期是在创建的时候通过接口实现开启,循环注入是通过后置处理器,aop其实就是通过反射进行动态代理,pointcut,advice等。 Aop相关:http://blog.csdn.net/csh624366188/article/details/7651702/ Springmvc 中 DispatcherServlet 初始化过程。 入口是web.xml中配置的ds,ds继承了HttpServletBean,FrameworkServlet,通过其中的init方法进行初始化装载bean和实例,initServletBean是实际完成上下文工作和bean初始化的方法。http://www.mamicode.com/info-detail-512105.html 操作系统 Linux 系统下你关注过哪些内核参数,说说你知道的。 image.png Tcp/ip io cpu memory net.ipv4.tcp_syncookies = 1 启用syncookies net.ipv4.tcp_max_syn_backlog = 8192 SYN队列长度 net.ipv4.tcp_synack_retries=2 SYN ACK重试次数 net.ipv4.tcp_fin_timeout = 30 主动关闭方FIN-WAIT-2超时时间 net.ipv4.tcp_keepalive_time = 1200 TCP发送keepalive消息的频度 net.ipv4.tcp_tw_reuse = 1 开启TIME-WAIT重用 net.ipv4.tcp_tw_recycle = 1 开启TIME-WAIT快速回收 net.ipv4.ip_local_port_range = 1024 65000 向外连接的端口范围 net.ipv4.tcp_max_tw_buckets = 5000 最大TIME-WAIT数量,超过立即清除 net.ipv4.tcp_syn_retries = 2 SYN重试次数 echo “fs.file-max=65535” >> /etc/sysctl.conf sysctl -p http://www.haiyun.me/category/system/ Linux 下 IO 模型有几种,各自的含义是什么。 阻塞式io,非阻塞io,io复用模型,信号驱动io模型,异步io模型。https://yq.aliyun.com/articles/46404https://yq.aliyun.com/articles/46402 epoll 和 poll 有什么区别。 select的本质是采用32个整数的32位,即3232= 1024来标识,fd值为1-1024。当fd的值超过1024限制时,就必须修改FD_SETSIZE的大小。这个时候就可以标识32max值范围的fd。 对于单进程多线程,每个线程处理多个fd的情况,select是不适合的。 1.所有的线程均是从1-32*max进行扫描,每个线程处理的均是一段fd值,这样做有点浪费 2.1024上限问题,一个处理多个用户的进程,fd值远远大于1024 所以这个时候应该采用poll, poll传递的是数组头指针和该数组的长度,只要数组的长度不是很长,性能还是很不错的,因为poll一次在内核中申请4K(一个页的大小来存放fd),尽量控制在4K以内 epoll还是poll的一种优化,返回后不需要对所有的fd进行遍历,在内核中维持了fd的列表。select和poll是将这个内核列表维持在用户态,然后传递到内核中。但是只有在2.6的内核才支持。 epoll更适合于处理大量的fd ,且活跃fd不是很多的情况,毕竟fd较多还是一个串行的操作https://yq.aliyun.com/articles/10525 平时用到哪些 Linux 命令。 Ls,find,tar,tail,cp,rm,vi,grep,ps,pkill等等https://yq.aliyun.com/articles/69417?spm=5176.100240.searchblog.18.Zrbh9R 用一行命令查看文件的最后五行。 Tail -n 5 filename 用一行命令输出正在运行的 java 进程。 ps -ef|grep Java 介绍下你理解的操作系统中线程切换过程。 控制权的转换,根据优先级切换上下文(用户,寄存器,系统)http://www.cnblogs.com/kkshaq/p/4544426.html 进程和线程的区别。 Linux 实现并没有区分这两个概念(进程和线程) 1. 进程:程序的一次执行 2. 线程:CPU的基本调度单位 一个进程可以包含多个线程。 http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html 多线程 多线程的几种实现方式,什么是线程安全。 实现runable接口,继承thread类。http://ifeve.com/java-multi-threading-concurrency-interview-questions-with-answers/ volatile 的原理,作用,能代替锁么。 Volatile利用内存栅栏机制来保持变量的一致性。不能代替锁,其只具备数据可见性一致性,不具备原子性。http://blog.csdn.net/gongzi2311/article/details/20715185 画一个线程的生命周期状态图。 新建,可运行,运行中, 睡眠,阻塞,等待,死亡。 image.png http://ifeve.com/thread-status sleep 和 wait 的区别。 Sleep是休眠线程,wait是等待,sleep是thread的静态方法,wait则是object的方法。 Sleep依旧持有锁,并在指定时间自动唤醒。wait则释放锁。http://www.jianshu.com/p/4ec3f4b3903d Lock 与 Synchronized 的区别。 首先两者都保持了并发场景下的原子性和可见性,区别则是synchronized的释放锁机制是交由其自身控制,且互斥性在某些场景下不符合逻辑,无法进行干预,不可人为中断等。 而lock常用的则有ReentrantLock和readwritelock两者,添加了类似锁投票、定时锁等候和可中断锁等候的一些特性。此外,它还提供了在激烈争用情况下更佳的性能。http://blog.csdn.net/vking_wang/article/details/9952063 synchronized 的原理是什么,解释以下名词:重排序,自旋锁,偏向锁,轻量级锁,可重入锁,公平锁,非公平锁,乐观锁,悲观锁。 Synchronized底层是通过监视器的enter和exit实现https://my.oschina.net/cnarthurs/blog/847801http://blog.csdn.net/a314773862/article/details/54095819 用过哪些原子类,他们的原理是什么。 AtomicInteger; AtomicLong; AtomicReference; AtomicBoolean;基于CAS原语实现 ,比较并交换、加载链接/条件存储,最坏的情况下是旋转锁https://www.ibm.com/developerworks/cn/java/j-jtp11234/index.htmlhttp://www.jmatrix.org/java/848.html 用过线程池吗,newCache 和 newFixed 有什么区别,他们的原理简单概括下,构造函数的各个参数的含义是什么,比如 coreSize,maxsize 等 newSingleThreadExecutor返回以个包含单线程的Executor,将多个任务交给此Exector时,这个线程处理完一个任务后接着处理下一个任务,若该线程出现异常,将会有一个新的线程来替代。 newFixedThreadPool返回一个包含指定数目线程的线程池,如果任务数量多于线程数目,那么没有没有执行的任务必须等待,直到有任务完成为止。 newCachedThreadPool根据用户的任务数创建相应的线程来处理,该线程池不会对线程数目加以限制,完全依赖于JVM能创建线程的数量,可能引起内存不足。 底层是基于ThreadPoolExecutor实现,借助reentrantlock保证并发。 coreSize核心线程数,maxsize最大线程数。http://ifeve.com/java-threadpoolexecutor/ 线程池的关闭方式有几种,各自的区别是什么。 Shutdown shutdownNow tryTerminate 清空工作队列,终止线程池中各个线程,销毁线程池http://blog.csdn.net/xxcupid/article/details/51993235 假如有一个第三方接口,有很多个线程去调用获取数据,现在规定每秒钟最多有 10 个线程同时调用它,如何做到。 ScheduledThreadPoolExecutor 设置定时,进行调度。 public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory) { super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS, new DelayedWorkQueue(), threadFactory); } http://ifeve.com/java-scheduledthreadpoolexecutor/ spring 的 controller 是单例还是多例,怎么保证并发的安全。 单例 通过单例工厂 DefaultSingletonBeanRegistry实现单例 通过保AsyncTaskExecutor持安全 用三个线程按顺序循环打印 abc 三个字母,比如 abcabcabc。 public static void main(String[] args) { final String str=”abc”; ExecutorService executorService= Executors.newFixedThreadPool(3); executorService.execute(new Runnable() { @Override public void run() { System.out.println(“1”+str); } }); executorService.execute(new Runnable() { @Override public void run() { System.out.println(“2”+str); } }); executorService.execute(new Runnable() { @Override public void run() { System.out.println(“2”+str); } }); } ThreadLocal 用过么,用途是什么,原理是什么,用的时候要注意什么。 Threadlocal底层是通过threadlocalMap进行存储键值 每个ThreadLocal类创建一个Map,然后用线程的ID作为Map的key,实例对象作为Map的value,这样就能达到各个线程的值隔离的效果。 ThreadLocal的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或者组件之间一些公共变量的传递的复杂度。 **谁设置谁负责移除 **http://qifuguang.me/2015/09/02/[Java%E5%B9%B6%E5%8F%91%E5%8C%85%E5%AD%A6%E4%B9%A0%E4%B8%83]%E8%A7%A3%E5%AF%86ThreadLocal/ 如果让你实现一个并发安全的链表,你会怎么做。 Collections.synchronizedList() ConcurrentLinkedQueuehttp://blog.csdn.net/xingjiarong/article/details/48046751 有哪些无锁数据结构,他们实现的原理是什么。 LockFree,CAS 基于jdk提供的原子类原语实现,例如AtomicReferencehttp://blog.csdn.net/b_h_l/article/details/8704480 讲讲 java 同步机制的 wait 和 notify。 首先这两个方法只能在同步代码块中调用,wait会释放掉对象锁,等待notify唤醒。http://blog.csdn.net/ithomer/article/details/7685594 多线程如果线程挂住了怎么办。 根据具体情况(sleep,wait,join等),酌情选择notifyAll,notify进行线程唤醒。http://blog.chinaunix.net/uid-122937-id-215913.html countdowlatch 和 cyclicbarrier 的内部原理和用法,以及相互之间的差别。 CountDownLatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它运行一个或者多个线程一直处于等待状态。 CyclicBarrier要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行。 CyclicBarrier初始化的时候,设置一个屏障数。线程调用await()方法的时候,这个线程就会被阻塞,当调用await()的线程数量到达屏障数的时候,主线程就会取消所有被阻塞线程的状态。 前者是递减,不可循环,后者是递加,可循环用 countdowlatch 基于abq cb基于ReentrantLock Conditionhttp://www.jianshu.com/p/a101ae9797e3http://blog.csdn.net/tolcf/article/details/50925145 使用 synchronized 修饰静态方法和非静态方法有什么区别。 对象锁和类锁https://yq.aliyun.com/articles/24226 简述 ConcurrentLinkedQueue LinkedBlockingQueue 的用处和不同之处。 LinkedBlockingQueue 是一个基于单向链表的、范围任意的(其实是有界的)、FIFO 阻塞队列。ConcurrentLinkedQueue是一个基于链接节点的无界线程安全队列,它采用先进先出的规则对节点进行排序,当我们添加一个元素的时候,它会添加到队列的尾部,当我们获取一个元素时,它会返回队列头部的元素。它采用了“wait-free”算法来实现,该算法在Michael & Scott算法上进行了一些修改, Michael & Scott算法的详细信息可以参见参考资料一。http://ifeve.com/concurrentlinkedqueue/http://ifeve.com/juc-linkedblockingqueue/http://blog.csdn.net/xiaohulunb/article/details/38932923 导致线程死锁的原因?怎么解除线程死锁。 死锁问题是多线程特有的问题,它可以被认为是线程间切换消耗系统性能的一种极端情况。在死锁时,线程间相互等待资源,而又不释放自身的资源,导致无穷无尽的等待,其结果是系统任务永远无法执行完成。死锁问题是在多线程开发中应该坚决避免和杜绝的问题。 **一般来说,要出现死锁问题需要满足以下条件: ** 1. 互斥条件:一个资源每次只能被一个线程使用。 2. 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。 3. 不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺。 4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。 只要破坏死锁 4 个必要条件之一中的任何一个,死锁问题就能被解决。https://www.ibm.com/developerworks/cn/java/j-lo-deadlock/ 调非常多个线程(可能是不同机器),相互之间需要等待协,才能完成某种工作,问怎么设计这种协调方案。 此问题的本质是保持顺序执行。可以使用executors TCP 与 HTTP http1.0 和 http1.1 有什么区别。 HTTP 1.0主要有以下几点变化: 请求和相应可以由于多行首部字段构成 响应对象前面添加了一个响应状态行 响应对象不局限于超文本 服务器与客户端之间的连接在每次请求之后都会关闭 实现了Expires等传输内容的缓存控制 内容编码Accept-Encoding、字符集Accept-Charset等协商内容的支持 这时候开始有了请求及返回首部的概念,开始传输不限于文本(其他二进制内容) HTTP 1.1加入了很多重要的性能优化:持久连接、分块编码传输、字节范围请求、增强的缓存机制、传输编码及请求管道。http://imweb.io/topic/554c5879718ba1240cc1dd8a TCP 三次握手和四次挥手的流程,为什么断开连接要 4 次,如果握手只有两次,会出现什么。 第一次握手(SYN=1, seq=x): 客户端发送一个 TCP 的 SYN 标志位置1的包,指明客户端打算连接的服务器的端口,以及初始序号 X,保存在包头的序列号(Sequence Number)字段里。 发送完毕后,客户端进入 SYN_SEND 状态。 第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1): 服务器发回确认包(ACK)应答。即 SYN 标志位和 ACK 标志位均为1。服务器端选择自己 ISN 序列号,放到 Seq 域里,同时将确认序号(Acknowledgement Number)设置为客户的 ISN 加1,即X+1。 发送完毕后,服务器端进入 SYN_RCVD 状态。 第三次握手(ACK=1,ACKnum=y+1) 客户端再次发送确认包(ACK),SYN 标志位为0,ACK 标志位为1,并且把服务器发来 ACK 的序号字段+1,放在确定字段中发送给对方,并且在数据段放写ISN的+1 发送完毕后,客户端进入 ESTABLISHED 状态,当服务器端接收到这个包时,也进入 ESTABLISHED 状态,TCP 握手结束。 第一次挥手(FIN=1,seq=x) 假设客户端想要关闭连接,客户端发送一个 FIN 标志位置为1的包,表示自己已经没有数据可以发送了,但是仍然可以接受数据。 发送完毕后,客户端进入 FIN_WAIT_1 状态。 第二次挥手(ACK=1,ACKnum=x+1) 服务器端确认客户端的 FIN 包,发送一个确认包,表明自己接受到了客户端关闭连接的请求,但还没有准备好关闭连接。 发送完毕后,服务器端进入 CLOSE_WAIT 状态,客户端接收到这个确认包之后,进入 FIN_WAIT_2 状态,等待服务器端关闭连接。 第三次挥手(FIN=1,seq=y) 服务器端准备好关闭连接时,向客户端发送结束连接请求,FIN 置为1。 发送完毕后,服务器端进入 LAST_ACK 状态,等待来自客户端的最后一个ACK。 第四次挥手(ACK=1,ACKnum=y+1) 客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入 TIME_WAIT状态,等待可能出现的要求重传的 ACK 包。 服务器端接收到这个确认包之后,关闭连接,进入 CLOSED 状态。 客户端等待了某个固定时间(两个最大段生命周期,2MSL,2 Maximum Segment Lifetime)之后,没有收到服务器端的 ACK ,认为服务器端已经正常关闭连接,于是自己也关闭连接,进入 CLOSED 状态。 两次后会重传直到超时。如果多了会有大量半链接阻塞队列。https://segmentfault.com/a/1190000006885287https://hit-alibaba.github.io/interview/basic/network/TCP.html TIME_WAIT 和 CLOSE_WAIT 的区别。 TIME_WAIT状态就是用来重发可能丢失的ACK报文。 TIME_WAIT 表示主动关闭,CLOSE_WAIT 表示被动关闭。 说说你知道的几种 HTTP 响应码,比如 200, 302, 404。 1xx:信息,请求收到,继续处理 2xx:成功,行为被成功地接受、理解和采纳 3xx:重定向,为了完成请求,必须进一步执行的动作 4xx:客户端错误,请求包含语法错误或者请求无法实现 5xx:服务器错误,服务器不能实现一种明显无效的请求 200 ok 一切正常 302 Moved Temporatily 文件临时移出 404 not foundhttps://my.oschina.net/gavinjin/blog/42856 当你用浏览器打开一个链接的时候,计算机做了哪些工作步骤。 Dns解析–>端口分析–>tcp请求–>服务器处理请求–>服务器响应–>浏览器解析—>链接关闭 TCP/IP 如何保证可靠性,说说 TCP 头的结构。 使用序号,对收到的TCP报文段进行排序以及检测重复的数据;使用校验和来检测报文段的错误;使用确认和计时器来检测和纠正丢包或延时。//TCP头部,总长度20字节 typedef struct _tcp_hdr { unsigned short src_port; //源端口号 unsigned short dst_port; //目的端口号 unsigned int seq_no; //序列号 unsigned int ack_no; //确认号 if LITTLE_ENDIAN unsigned char reserved_1:4; //保留6位中的4位首部长度 unsigned char thl:4; //tcp头部长度 unsigned char flag:6; //6位标志 unsigned char reseverd_2:2; //保留6位中的2位 else unsigned char thl:4; //tcp头部长度 unsigned char reserved_1:4; //保留6位中的4位首部长度 unsigned char reseverd_2:2; //保留6位中的2位 unsigned char flag:6; //6位标志 endif unsigned short wnd_size; //16位窗口大小 unsigned short chk_sum; //16位TCP检验和 unsigned short urgt_p; //16为紧急指针 }tcp_hdr; https://zh.bywiki.com/zh-hans/%E4%BC%A0%E8%BE%93%E6%8E%A7%E5%88%B6%E5%8D%8F%E8%AE%AE 如何避免浏览器缓存。 无法被浏览器缓存的请求: HTTP信息头中包含Cache-Control:no-cache,pragma:no-cache,或Cache-Control:max-age=0等告诉浏览器不用缓存的请求 需要根据Cookie,认证信息等决定输入内容的动态请求是不能被缓存的 经过HTTPS安全加密的请求(有人也经过测试发现,ie其实在头部加入Cache-Control:max-age信息,firefox在头部加入Cache-Control:Public之后,能够对HTTPS的资源进行缓存,参考《HTTPS的七个误解》) POST请求无法被缓存 HTTP响应头中不包含Last-Modified/Etag,也不包含Cache-Control/Expires的请求无法被缓存http://www.alloyteam.com/2012/03/web-cache-2-browser-cache/ 简述 Http 请求 get 和 post 的区别以及数据包格式。 image.png image.png http://www.w3school.com.cn/tags/html_ref_httpmethods.asphttp://www.360doc.com/content/12/0612/14/8093902_217673378.shtml 简述 HTTP 请求的报文格式。 参考上面 HTTPS 的加密方式是什么,讲讲整个加密解密流程。 加密方式是tls/ssl,底层是通过对称算法,非对称,hash算法实现 客户端发起HTTPS请求 –》2. 服务端的配置 –》 3. 传送证书 —》4. 客户端解析证书 5. 传送加密信息 6. 服务段解密信息 7. 传输加密后的信息 8. 客户端解密信息http://www.cnblogs.com/zhuqil/archive/2012/07/23/2604572.html 架构设计与分布式 常见的缓存策略有哪些,你们项目中用到了什么缓存系统,如何设计的。 Cdn缓存,redis缓存,ehcache缓存等 Cdn 图片资源 js等, redis一主一从 echcache缓存数据 用 java 自己实现一个 LRU。 final int cacheSize = 100; Map 分布式集群下如何做到唯一序列号。 Redis生成,mongodb的objectId,zk生成http://www.cnblogs.com/haoxinyue/p/5208136.html 设计一个秒杀系统,30 分钟没付款就自动关闭交易。 分流 – 限流–异步–公平性(只能参加一次)–用户体验(第几位,多少分钟,一抢完) 容错处理 Redis 队列 mysql 30分钟关闭 可以借助redis的发布订阅机制 在失效时进行后续操作,其他mq也可以http://www.infoq.com/cn/articles/yhd-11-11-queuing-system-design 如何使用 redis 和 zookeeper 实现分布式锁?有什么区别优缺点,分别适用什么场景。 首先分布式锁实现常见的有数据库锁(表记录),缓存锁,基于zk(临时有序节点可以实现的)的三种 Redis适用于对性能要求特别高的场景。redis可以每秒执行10w次,内网延迟不超过1ms 缺点是数据存放于内存,宕机后锁丢失。 锁无法释放?使用Zookeeper可以有效的解决锁无法释放的问题,因为在创建锁的时候,客户端会在ZK中创建一个临时节点,一旦客户端获取到锁之后突然挂掉(Session连接断开),那么这个临时节点就会自动删除掉。其他客户端就可以再次获得锁。 非阻塞锁?使用Zookeeper可以实现阻塞的锁,客户端可以通过在ZK中创建顺序节点,并且在节点上绑定监听器,一旦节点有变化,Zookeeper会通知客户端,客户端可以检查自己创建的节点是不是当前所有节点中序号最小的,如果是,那么自己就获取到锁,便可以执行业务逻辑了。 不可重入?使用Zookeeper也可以有效的解决不可重入的问题,客户端在创建节点的时候,把当前客户端的主机信息和线程信息直接写入到节点中,下次想要获取锁的时候和当前最小的节点中的数据比对一下就可以了。如果和自己的信息一样,那么自己直接获取到锁,如果不一样就再创建一个临时的顺序节点,参与排队。 单点问题?使用Zookeeper可以有效的解决单点问题,ZK是集群部署的,只要集群中有半数以上的机器存活,就可以对外提供服务。 http://www.hollischuang.com/archives/1716 如果有人恶意创建非法连接,怎么解决。 可以使用filter过滤处理 分布式事务的原理,优缺点,如何使用分布式事务。 Two Phase commit协议 优点是可以管理多机事务,拥有无线扩展性 确定是易用性难,承担延时风险 JTA,atomiks等https://yq.aliyun.com/webinar/join/185?spm=5176.8067841.0.0.RL4GDa 什么是一致性 hash。 一致性hash是一种分布式hash实现算法。满足平衡性 单调性 分散性 和负载。http://blog.csdn.net/cywosp/article/details/23397179/ 什么是 restful,讲讲你理解的 restful。 REST 指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是 RESTful。http://baike.baidu.com/link?url=fTSAdL-EyYvTp9z7mZsCOdS3kbs4VKKAnpBLg3WS_1Z4cmLMp3S-zrjcy5wakLTO5AIoPTopWVkG-IenloPKxq 如何设计建立和保持 100w 的长连接。 服务器内核调优(tcp,文件数),客户端调优,框架选择(netty) 如何防止缓存雪崩。 缓存雪崩可能是因为数据未加载到缓存中,或者缓存同一时间大面积的失效,从而导致所有请求都去查数据库,导致数据库CPU和内存负载过高,甚至宕机。 **解决思路: ** 1,采用加锁计数,或者使用合理的队列数量来避免缓存失效时对数据库造成太大的压力。这种办法虽然能缓解数据库的压力,但是同时又降低了系统的吞吐量。 2,分析用户行为,尽量让失效时间点均匀分布。避免缓存雪崩的出现。 3,如果是因为某台缓存服务器宕机,可以考虑做主备,比如:redis主备,但是双缓存涉及到更新事务的问题,update可能读到脏数据,需要好好解决。 http://www.cnblogs.com/jinjiangongzuoshi/archive/2016/03/03/5240280.html 解释什么是 MESI 协议(缓存一致性)。 MESI是四种缓存段状态的首字母缩写,任何多核系统中的缓存段都处于这四种状态之一。我将以相反的顺序逐个讲解,因为这个顺序更合理: 失效(Invalid)缓存段,要么已经不在缓存中,要么它的内容已经过时。为了达到缓存的目的,这种状态的段将会被忽略。一旦缓存段被标记为失效,那效果就等同于它从来没被加载到缓存中。共享(Shared)缓存段,它是和主内存内容保持一致的一份拷贝,在这种状态下的缓存段只能被读取,不能被写入。多组缓存可以同时拥有针对同一内存地址的共享缓存段,这就是名称的由来。独占(Exclusive)缓存段,和S状态一样,也是和主内存内容保持一致的一份拷贝。区别在于,如果一个处理器持有了某个E状态的缓存段,那其他处理器就不能同时持有它,所以叫“独占”。这意味着,如果其他处理器原本也持有同一缓存段,那么它会马上变成“失效”状态。已修改(Modified)缓存段,属于脏段,它们已经被所属的处理器修改了。如果一个段处于已修改状态,那么它在其他处理器缓存中的拷贝马上会变成失效状态,这个规律和E状态一样。此外,已修改缓存段如果被丢弃或标记为失效,那么先要把它的内容回写到内存中——这和回写模式下常规的脏段处理方式一样。 说说你知道的几种 HASH 算法,简单的也可以。 哈希(Hash)算法,即散列函数。 它是一种单向密码体制,即它是一个从明文到密文的不可逆的映射,只有加密过程,没有解密过程。 同时,哈希函数可以将任意长度的输入经过变化以后得到固定长度的输出 MD4 MD5 SHAhttp://blog.jobbole.com/106733/ 什么是 paxos 算法。 Paxos算法是莱斯利·兰伯特(Leslie Lamport,就是 LaTeX 中的”La”,此人现在在微软研究院)于1990年提出的一种基于消息传递的一致性算法。 http://baike.baidu.com/item/Paxos%20%E7%AE%97%E6%B3%95 什么是 zab 协议。 ZAB 是 Zookeeper 原子广播协议的简称 整个ZAB协议主要包括消息广播和崩溃恢复两个过程,进一步可以分为三个阶段,分别是: **发现 Discovery 同步 Synchronization 广播 Broadcast ** 组成ZAB协议的每一个分布式进程,都会循环执行这三个阶段,将这样一个循环称为一个主进程周期。https://zzzvvvxxxd.github.io/2016/08/09/ZAB/ 一个在线文档系统,文档可以被编辑,如何防止多人同时对同一份文档进行编辑更新。 点击编辑的时候,利用redis进行加锁setNX完了之后 expire 一下 也可以用版本号进行控制 线上系统突然变得异常缓慢,你如何查找问题。 逐级排查(网络,磁盘,内存,cpu),数据库,日志,中间件等也可通过监控工具排查。 说说你平时用到的设计模式。 单例, 代理,模板,策略,命令http://www.jianshu.com/p/bdf65e4afbb0 Dubbo 的原理,数据怎么流转的,怎么实现集群,负载均衡,服务注册和发现。重试转发,快速失败的策略是怎样的。 Dubbo[]是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。 Cluster 实现集群 在集群负载均衡时,Dubbo提供了多种均衡策略,缺省为random随机调用。 Random LoadBalance:随机,按权重比率设置随机概率。 RoundRobin LoadBalance:轮循,按公约后的权重比率设置轮循比率。 LeastActive LoadBalance:最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。 ConsistentHash LoadBalance:一致性Hash,相同参数的请求总是发到同一提供者。当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。 快速失败,只发起一次调用,失败立即报错。 https://my.oschina.net/u/1378920/blog/693374 一次 RPC 请求的流程是什么。 1)服务消费方(client)调用以本地调用方式调用服务; 2)client stub接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体; 3)client stub找到服务地址,并将消息发送到服务端; 4)server stub收到消息后进行解码; 5)server stub根据解码结果调用本地的服务; 6)本地服务执行并将结果返回给server stub; 7)server stub将返回结果打包成消息并发送至消费方; 8)client stub接收到消息,并进行解码; 9)服务消费方得到最终结果。 异步模式的用途和意义。 异步模式使用与服务器多核,并发严重的场景 可提高服务吞吐量大,不容易受到冲击,可以采用并发策略,提高响应时间 **缓存数据过期后的更新如何设计。 ** 失效:应用程序先从cache取数据,没有得到,则从数据库中取数据,成功后,放到缓存中。 命中:应用程序从cache中取数据,取到后返回。 更新:先把数据存到数据库中,成功后,再让缓存失效。 编程中自己都怎么考虑一些设计原则的,比如开闭原则,以及在工作中的应用。 开闭原则(Open Close Principle) 一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。 里氏代换原则(Liskov Substitution Principle) 子类型必须能够替换掉它们的父类型。 依赖倒转原则(Dependence Inversion Principle) 高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。即针对接口编程,不要针对实现编程 接口隔离原则(Interface Segregation Principle) 建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少 组合/聚合复用原则 说要尽量的使用合成和聚合,而不是继承关系达到复用的目的 迪米特法则(Law Of Demeter) 迪米特法则其根本思想,是强调了类之间的松耦合,类之间的耦合越弱,越有利于复用,一个处在弱耦合的类被修改,不会对有关系的类造成影响,也就是说,信息的隐藏促进了软件的复用。 单一职责原则(Single Responsibility Principle) 一个类只负责一项职责,应该仅有一个引起它变化的原因http://www.banzg.com/archives/225.html 设计一个社交网站中的“私信”功能,要求高并发、可扩展等等。 画一下架构图。 **MVC 模式,即常见的 MVC 框架。 ** SSM SSH SSI等 聊了下曾经参与设计的服务器架构。应用服务器怎么监控性能,各种方式的区别。如何设计一套高并发支付方案,架构如何设计。如何实现负载均衡,有哪些算法可以实现。Zookeeper 的用途,选举的原理是什么。Mybatis 的底层实现原理。请思考一个方案,设计一个可以控制缓存总体大小的自动适应的本地缓存。请思考一个方案,实现分布式环境下的 countDownLatch。后台系统怎么防止请求重复提交。可以通过token值进行防止重复提交,存放到redis中,在表单初始化的时候隐藏在表单中,添加的时候在移除。判断这个状态即可防止重复提交。 如何看待缓存的使用(本地缓存,集中式缓存),简述本地缓存和集中式缓存和优缺点。本地缓存在并发使用时的注意事项。描述一个服务从发布到被消费的详细过程。讲讲你理解的服务治理。如何做到接口的幂等性。 算法题 10 亿个数字里里面找最小的 10 个。有 1 亿个数字,其中有 2 个是重复的,快速找到它,时间和空间要最优。2 亿个随机生成的无序整数,找出中间大小的值。给一个不知道长度的(可能很大)输入字符串,设计一种方案,将重复的字符排重。遍历二叉树。有 3n+1 个数字,其中 3n 个中是重复的,只有 1 个是不重复的,怎么找出来。写一个字符串反转函数。常用的排序算法,快排,归并、冒泡。 快排的最优时间复杂度,最差复杂度。冒泡排序的优化方案。二分查找的时间复杂度,优势。一个已经构建好的 TreeSet,怎么完成倒排序。什么是 B+树,B-树,列出实际的使用场景。 数据库知识 数据库隔离级别有哪些,各自的含义是什么,MYSQL 默认的隔离级别是是什么。 ·未提交读(Read Uncommitted):允许脏读,也就是可能读取到其他会话中未提交事务修改的数据 ·提交读(Read Committed):只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 (不重复读) ·可重复读(Repeated Read):可重复读。在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读 ·串行读(Serializable):完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞 MYSQL默认是RepeatedRead级别 MYSQL 有哪些存储引擎,各自优缺点。 MyISAM: 拥有较高的插入,查询速度,但不支持事务 InnoDB :5.5版本后Mysql的默认数据库,事务型数据库的首选引擎,支持ACID事务,支持行级锁定 BDB: 源自Berkeley DB,事务型数据库的另一种选择,支持COMMIT和ROLLBACK等其他事务特性 Memory :所有数据置于内存的存储引擎,拥有极高的插入,更新和查询效率。但是会占用和数据量成正比的内存空间。并且其内容会在Mysql重新启动时丢失 Merge :将一定数量的MyISAM表联合而成一个整体,在超大规模数据存储时很有用 Archive :非常适合存储大量的独立的,作为历史记录的数据。因为它们不经常被读取。Archive拥有高效的插入速度,但其对查询的支持相对较差 Federated: 将不同的Mysql服务器联合起来,逻辑上组成一个完整的数据库。非常适合分布式应用 Cluster/NDB :高冗余的存储引擎,用多台数据机器联合提供服务以提高整体性能和安全性。适合数据量大,安全和性能要求高的应用 CSV: 逻辑上由逗号分割数据的存储引擎。它会在数据库子目录里为每个数据表创建一个.CSV文件。这是一种普通文本文件,每个数据行占用一个文本行。CSV存储引擎不支持索引。 BlackHole :黑洞引擎,写入的任何数据都会消失,一般用于记录binlog做复制的中继 另外,Mysql的存储引擎接口定义良好。有兴趣的开发者通过阅读文档编写自己的存储引擎。http://baike.baidu.com/item/%E5%AD%98%E5%82%A8%E5%BC%95%E6%93%8E 高并发下,如何做到安全的修改同一行数据。 使用悲观锁 悲观锁本质是当前只有一个线程执行操作,结束了唤醒其他线程进行处理。 也可以缓存队列中锁定主键。 乐观锁和悲观锁是什么,INNODB 的行级锁有哪 2 种,解释其含义。 乐观锁是设定每次修改都不会冲突,只在提交的时候去检查,悲观锁设定每次修改都会冲突,持有排他锁。 行级锁分为共享锁和排他锁两种 共享锁又称读锁 排他锁又称写锁http://www.jianshu.com/p/f40ec03fd0e8 SQL 优化的一般步骤是什么,怎么看执行计划,如何理解其中各个字段的含义。 查看慢日志(show [session|gobal] status ),定位慢查询,查看慢查询执行计划 根据执行计划确认优化方案 Explain sql select_type:表示select类型。常见的取值有SIMPLE(简单表,即不使用连接或者子查询)、PRIMARY(主查询,即外层的查询)、UNION(union中的第二个或者后面的查询语句)、SUBQUERY(子查询中的第一个SELECT)等。 talbe:输出结果集的表。 type:表的连接类型。性能由高到底:system(表中仅有一行)、const(表中最多有一个匹配行)、eq_ref、ref、ref_null、index_merge、unique_subquery、index_subquery、range、idnex等 possible_keys:查询时,可能使用的索引 key:实际使用的索引 key_len:索引字段的长度 rows:扫描行的数量 Extra:执行情况的说明和描述http://blog.csdn.net/hsd2012/article/details/51106285 数据库会死锁吗,举一个死锁的例子,mysql 怎么解决死锁。 产生死锁的原因主要是: (1)系统资源不足。 (2) 进程运行推进的顺序不合适。 (3)资源分配不当等。 如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。 产生死锁的四个必要条件: (1) 互斥条件:一个资源每次只能被一个进程使用。 (2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。 (3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。 (4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。 这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。这里提供两个解决数据库死锁的方法: 1)重启数据库(谁用谁知道) 2)杀掉抢资源的进程: 先查哪些进程在抢资源:SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX; 杀掉它们:Kill trx_mysql_thread_id; MYsql 的索引原理,索引的类型有哪些,如何创建合理的索引,索引如何优化。 索引是通过复杂的算法,提高数据查询性能的手段。从磁盘io到内存io的转变 普通索引,主键,唯一,单列/多列索引建索引的几大原则 1.最左前缀匹配原则,非常重要的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。 2.=和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式 3.尽量选择区分度高的列作为索引,区分度的公式是count(distinct col)/count(*),表示字段不重复的比例,比例越大我们扫描的记录数越少,唯一键的区分度是1,而一些状态、性别字段可能在大数据面前区分度就是0,那可能有人会问,这个比例有什么经验值吗?使用场景不同,这个值也很难确定,一般需要join的字段我们都要求是0.1以上,即平均1条扫描10条记录 4.索引列不能参与计算,保持列“干净”,比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很简单,b+树中存的都是数据表中的字段值,但进行检索时,需要把所有元素都应用函数才能比较,显然成本太大。所以语句应该写成create_time = unix_timestamp(’2014-05-29’); 5.尽量的扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可 http://tech.meituan.com/mysql-index.htmlhttp://www.cnblogs.com/cq-home/p/3482101.html 聚集索引和非聚集索引的区别。 “聚簇”就是索引和记录紧密在一起。 非聚簇索引 索引文件和数据文件分开存放,索引文件的叶子页只保存了主键值,要定位记录还要去查找相应的数据块。 数据库中 BTREE 和 B+tree 区别。 B+是btree的变种,本质都是btree,btree+与B-Tree相比,B+Tree有以下不同点: 每个节点的指针上限为2d而不是2d+1。 内节点不存储data,只存储key;叶子节点不存储指针。 http://lcbk.net/9602.html **Btree 怎么分裂的,什么时候分裂,为什么是平衡的。 ** Key 超过1024才分裂B树为甚会分裂? 因为随着数据的增多,一个结点的key满了,为了保持B树的特性,就会产生分裂,就向红黑树和AVL树为了保持树的性质需要进行旋转一样! ACID 是什么。 A,atomic,原子性,要么都提交,要么都失败,不能一部分成功,一部分失败。 C,consistent,一致性,事物开始及结束后,数据的一致性约束没有被破坏 I,isolation,隔离性,并发事物间相互不影响,互不干扰。 D,durability,持久性,已经提交的事物对数据库所做的更新必须永久保存。即便发生崩溃,也不能被回滚或数据丢失。 Mysql 怎么优化 table scan 的。 避免在where子句中对字段进行is null判断 应尽量避免在where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。 避免在where 子句中使用or 来连接条件 in 和not in 也要慎用 Like查询(非左开头) 使用NUM=@num参数这种 where 子句中对字段进行表达式操作num/2=XX 在where子句中对字段进行函数操作 如何写 sql 能够有效的使用到复合索引。 由于复合索引的组合索引,类似多个木板拼接在一起,如果中间断了就无法用了,所以要能用到复合索引,首先开头(第一列)要用上,比如index(a,b) 这种,我们可以select table tname where a=XX 用到第一列索引 如果想用第二列 可以 and b=XX 或者and b like‘TTT%’ mysql 中 in 和 exists 区别。 mysql中的in语句是把外表和内表作hash 连接,而exists语句是对外表作loop循环,每次loop循环再对内表进行查询。一直大家都认为exists比in语句的效率要高,这种说法其实是不准确的。这个是要区分环境的。 如果查询的两个表大小相当,那么用in和exists差别不大。 如果两个表中一个较小,一个是大表,则子查询表大的用exists,子查询表小的用in: not in 和not exists如果查询语句使用了not in 那么内外表都进行全表扫描,没有用到索引;而not extsts 的子查询依然能用到表上的索引。所以无论那个表大,用not exists都比not in要快。 1.EXISTS只返回TRUE或FALSE,不会返回UNKNOWN。 2.IN当遇到包含NULL的情况,那么就会返回UNKNOWN。 数据库自增主键可能的问题。 在分库分表时可能会生成重复主键 利用自增比例达到唯一 自增1 2,3 等https://yq.aliyun.com/articles/38438 消息队列 用过哪些 MQ,和其他 mq 比较有什么优缺点,MQ 的连接是线程安全的吗,你们公司的MQ 服务架构怎样的。 根据实际情况说明 我们公司用activeMQ 因为业务比较简单 只有转码功能,而amq比较简单 如果是分布式的建议用kafkahttp://blog.csdn.net/sunxinhere/article/details/7968886 MQ 系统的数据如何保证不丢失。 基本都是对数据进行持久化,多盘存储 rabbitmq 如何实现集群高可用。 集群是保证服务可靠性的一种方式,同时可以通过水平扩展以提升消息吞吐能力。RabbitMQ是用分布式程序设计语言erlang开发的,所以天生就支持集群。接下来,将介绍RabbitMQ分布式消息处理方式、集群模式、节点类型,并动手搭建一个高可用集群环境,最后通过java程序来验证集群的高可用性。 三种分布式消息处理方式 RabbitMQ分布式的消息处理方式有以下三种: 1、Clustering:不支持跨网段,各节点需运行同版本的Erlang和RabbitMQ, 应用于同网段局域网。 2、Federation:允许单台服务器上的Exchange或Queue接收发布到另一台服务器上Exchange或Queue的消息, 应用于广域网,。 3、Shovel:与Federation类似,但工作在更低层次。 RabbitMQ对网络延迟很敏感,在LAN环境建议使用clustering方式;在WAN环境中,则使用Federation或Shovel。我们平时说的RabbitMQ集群,说的就是clustering方式,它是RabbitMQ内嵌的一种消息处理方式,而Federation或Shovel则是以plugin形式存在。https://my.oschina.net/jiaoyanli/blog/822011https://www.ibm.com/developerworks/cn/opensource/os-cn-RabbitMQ/ Redis,Memcached redis 的 list 结构相关的操作。 LPUSH LPUSHX RPUSH RPUSHX LPOP RPOP BLPOP BRPOP LLEN LRANGEhttps://redis.readthedocs.io/en/2.4/list.html Redis 的数据结构都有哪些。 字符串(strings):存储整数(比如计数器)和字符串(废话。。),有些公司也用来存储json/pb等序列化数据,并不推荐,浪费内存 哈希表(hashes):存储配置,对象(比如用户、商品),优点是可以存取部分key,对于经常变化的或者部分key要求atom操作的适合 列表(lists):可以用来存最新用户动态,时间轴,优点是有序,确定是元素可重复,不去重 集合(sets):无序,唯一,对于要求严格唯一性的可以使用 有序集合(sorted sets):集合的有序版,很好用,对于排名之类的复杂场景可以考虑https://redis.readthedocs.io/en/2.4/list.html Redis 的使用要注意什么,讲讲持久化方式,内存设置,集群的应用和优劣势,淘汰策略等。 持久化方式:RDB时间点快照 AOF记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集。 内存设置 maxmemory used_memory 虚拟内存: vm-enabled yes **3.0采用Cluster方式, ** Redis集群相对单机在功能上存在一些限制, 需要开发人员提前了解, 在使用时做好规避。 限制如下: 1) key批量操作支持有限。 如mset、 mget, 目前只支持具有相同slot值的 ke y执 行批量操作。 对于映射为不同slot值的key由于执行mget、 mget等操作可 能存在于多个节点上因此不被支持。 2) key事务操作支持有限。 同理只支持多key在同一节点上的事务操 作, 当多个key分布在不同的节点上时无法使用事务功能。 3) key作为数据分区的最小粒度, 因此不能将一个大的键值对象如 ha sh、 list等映射到不同的节点。 4) 不支持多数据库空间。 单机下的Redis可以支持16个数据库, 集群模 式下只能使用一个数据库空间, 即db0。 5) 复制结构只支持一层, 从节点只能复制主节点, 不支持嵌套树状复 制结构。 Redis Cluster是Redis的分布式解决方案, 在3.0版本正式推出, 有效地解 决了Redis分布式方面的需求。 当遇到单机内存、 并发、 流量等瓶颈时, 可 以采用Cluster架构方案达到负载均衡的目的。 之前, ** Redis分布式方案一般 有两种: ** ·客户端分区方案, 优点是分区逻辑可控, 缺点是需要自己处理数据路 由、 高可用、 故障转移等问题。 ·代理方案, 优点是简化客户端分布式逻辑和升级维护便利, 缺点是加 重架构部署复杂度和性能损耗。 现在官方为我们提供了专有的集群方案: Redis Cluster, 它非常优雅地 解决了Redis集群方面的问题, 因此理解应用好Redis Cluster将极大地解放我 们使用分布式Redis的工作量, 同时它也是学习分布式存储的绝佳案例。 LRU(近期最少使用算法)TTL(超时算法) 去除ttl最大的键值http://wiki.jikexueyuan.com/project/redis/data-elimination-mechanism.htmlhttp://www.infoq.com/cn/articles/tq-redis-memory-usage-optimization-storagehttp://www.redis.cn/topics/cluster-tutorial.html redis2 和 redis3 的区别,redis3 内部通讯机制。 集群方式的区别,3采用Cluster,2采用客户端分区方案和代理方案 通信过程说明: 1) 集群中的每个节点都会单独开辟一个TCP通道, 用于节点之间彼此 通信, 通信端口号在基础端口上加10000。 2) 每个节点在固定周期内通过特定规则选择几个节点发送ping消息。 3) 接收到ping消息的节点用pong消息作为响应。 当前 redis 集群有哪些玩法,各自优缺点,场景。 当缓存使用 持久化使用 Memcache 的原理,哪些数据适合放在缓存中。 基于libevent的事件处理 内置内存存储方式SLab Allocation机制 并不单一的数据删除机制 基于客户端的分布式系统 变化频繁,具有不稳定性的数据,不需要实时入库, (比如用户在线 状态、在线人数..) 门户网站的新闻等,觉得页面静态化仍不能满足要求,可以放入 到memcache中.(配合jquey的ajax请求) redis 和 memcached 的内存管理的区别。 Memcached默认使用Slab Allocation机制管理内存,其主要思想是按照预先规定的大小,将分配的内存分割成特定长度的块以存储相应长度的key-value数据记录,以完全解决内存碎片问题。 Redis的内存管理主要通过源码中zmalloc.h和zmalloc.c两个文件来实现的。 在Redis中,并不是所有的数据都一直存储在内存中的。这是和Memcached相比一个最大的区别。http://lib.csdn.net/article/redis/55323 Redis 的并发竞争问题如何解决,了解 Redis 事务的 CAS 操作吗。 Redis为单进程单线程模式,采用队列模式将并发访问变为串行访问。Redis本身没有锁的概念,Redis对于多个客户端连接并不存在竞争,但是在Jedis客户端对Redis进行并发访问时会发生连接超时、数据转换错误、阻塞、客户端关闭连接等问题,这些问题均是由于客户端连接混乱造成。对此有2种解决方法: 1.客户端角度,为保证每个客户端间正常有序与Redis进行通信,对连接进行池化,同时对客户端读写Redis操作采用内部锁synchronized。 2.服务器角度,利用setnx实现锁。 MULTI,EXEC,DISCARD,WATCH 四个命令是 Redis 事务的四个基础命令。其中: MULTI,告诉 Redis 服务器开启一个事务。注意,只是开启,而不是执行 EXEC,告诉 Redis 开始执行事务 DISCARD,告诉 Redis 取消事务 WATCH,监视某一个键值对,它的作用是在事务执行之前如果监视的键值被修改,事务会被取消。 可以利用watch实现cas乐观锁http://wiki.jikexueyuan.com/project/redis/transaction-mechanism.htmlhttp://www.jianshu.com/p/d777eb9f27df Redis 的选举算法和流程是怎样的 Raft采用心跳机制触发Leader选举。系统启动后,全部节点初始化为Follower,term为0.节点如果收到了RequestVote或者AppendEntries,就会保持自己的Follower身份。如果一段时间内没收到AppendEntries消息直到选举超时,说明在该节点的超时时间内还没发现Leader,Follower就会转换成Candidate,自己开始竞选Leader。一旦转化为Candidate,该节点立即开始下面几件事情: 1、增加自己的term。 2、启动一个新的定时器。 3、给自己投一票。 4、向所有其他节点发送RequestVote,并等待其他节点的回复。 如果在这过程中收到了其他节点发送的AppendEntries,就说明已经有Leader产生,自己就转换成Follower,选举结束。 如果在计时器超时前,节点收到多数节点的同意投票,就转换成Leader。同时向所有其他节点发送AppendEntries,告知自己成为了Leader。 每个节点在一个term内只能投一票,采取先到先得的策略,Candidate前面说到已经投给了自己,Follower会投给第一个收到RequestVote的节点。每个Follower有一个计时器,在计时器超时时仍然没有接受到来自Leader的心跳RPC, 则自己转换为Candidate, 开始请求投票,就是上面的的竞选Leader步骤。 如果多个Candidate发起投票,每个Candidate都没拿到多数的投票(Split Vote),那么就会等到计时器超时后重新成为Candidate,重复前面竞选Leader步骤。 Raft协议的定时器采取随机超时时间,这是选举Leader的关键。每个节点定时器的超时时间随机设置,随机选取配置时间的1倍到2倍之间。由于随机配置,所以各个Follower同时转成Candidate的时间一般不一样,在同一个term内,先转为Candidate的节点会先发起投票,从而获得多数票。多个节点同时转换为Candidate的可能性很小。即使几个Candidate同时发起投票,在该term内有几个节点获得一样高的票数,只是这个term无法选出Leader。由于各个节点定时器的超时时间随机生成,那么最先进入下一个term的节点,将更有机会成为Leader。连续多次发生在一个term内节点获得一样高票数在理论上几率很小,实际上可以认为完全不可能发生。一般1-2个term类,Leader就会被选出来。 Sentinel的选举流程 Sentinel集群正常运行的时候每个节点epoch相同,当需要故障转移的时候会在集群中选出Leader执行故障转移操作。Sentinel采用了Raft协议实现了Sentinel间选举Leader的算法,不过也不完全跟论文描述的步骤一致。Sentinel集群运行过程中故障转移完成,所有Sentinel又会恢复平等。Leader仅仅是故障转移操作出现的角色。 选举流程 1、某个Sentinel认定master客观下线的节点后,该Sentinel会先看看自己有没有投过票,如果自己已经投过票给其他Sentinel了,在2倍故障转移的超时时间自己就不会成为Leader。相当于它是一个Follower。 2、如果该Sentinel还没投过票,那么它就成为Candidate。 3、和Raft协议描述的一样,成为Candidate,Sentinel需要完成几件事情 1)更新故障转移状态为start 2)当前epoch加1,相当于进入一个新term,在Sentinel中epoch就是Raft协议中的term。 3)更新自己的超时时间为当前时间随机加上一段时间,随机时间为1s内的随机毫秒数。 4)向其他节点发送is-master-down-by-addr命令请求投票。命令会带上自己的epoch。 5)给自己投一票,在Sentinel中,投票的方式是把自己master结构体里的leader和leader_epoch改成投给的Sentinel和它的epoch。 4、其他Sentinel会收到Candidate的is-master-down-by-addr命令。如果Sentinel当前epoch和Candidate传给他的epoch一样,说明他已经把自己master结构体里的leader和leader_epoch改成其他Candidate,相当于把票投给了其他Candidate。投过票给别的Sentinel后,在当前epoch内自己就只能成为Follower。 5、Candidate会不断的统计自己的票数,直到他发现认同他成为Leader的票数超过一半而且超过它配置的quorum(quorum可以参考《redis sentinel设计与实现》)。Sentinel比Raft协议增加了quorum,这样一个Sentinel能否当选Leader还取决于它配置的quorum。 6、如果在一个选举时间内,Candidate没有获得超过一半且超过它配置的quorum的票数,自己的这次选举就失败了。 7、如果在一个epoch内,没有一个Candidate获得更多的票数。那么等待超过2倍故障转移的超时时间后,Candidate增加epoch重新投票。 8、如果某个Candidate获得超过一半且超过它配置的quorum的票数,那么它就成为了Leader。 9、与Raft协议不同,Leader并不会把自己成为Leader的消息发给其他Sentinel。其他Sentinel等待Leader从slave选出master后,检测到新的master正常工作后,就会去掉客观下线的标识,从而不需要进入故障转移流程。http://weizijun.cn/2015/04/30/Raft%E5%8D%8F%E8%AE%AE%E5%AE%9E%E6%88%98%E4%B9%8BRedis%20Sentinel%E7%9A%84%E9%80%89%E4%B8%BELeader%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/ redis 的持久化的机制,aof 和 rdb 的区别。 RDB 定时快照方式(snapshot): 定时备份,可能会丢失数据 AOF 基于语句追加方式 只追加写操作 AOF 持久化和 RDB 持久化的最主要区别在于,前者记录了数据的变更,而后者是保存了数据本身 redis 的集群怎么同步的数据的。 redis replication redis-migrate-tool等方式 搜索 elasticsearch 了解多少,说说你们公司 es 的集群架构,索引数据大小,分片有多少,以及一些调优手段。elasticsearch 的倒排索引是什么。 ElasticSearch(简称ES)是一个分布式、Restful的搜索及分析服务器,设计用于分布式计算;能够达到实时搜索,稳定,可靠,快速。和Apache Solr一样,它也是基于Lucence的索引服务器,而ElasticSearch对比Solr的优点在于: 轻量级:安装启动方便,下载文件之后一条命令就可以启动。 Schema free:可以向服务器提交任意结构的JSON对象,Solr中使用schema.xml指定了索引结构。 多索引文件支持:使用不同的index参数就能创建另一个索引文件,Solr中需要另行配置。 分布式:Solr Cloud的配置比较复杂 倒排索引是实现“单词-文档矩阵”的一种具体存储形式,通过倒排索引,可以根据单词快速获取包含这个单词的文档列表。倒排索引主要由两个部分组成:“单词词典”和“倒排文件”。 elasticsearch 索引数据多了怎么办,如何调优,部署。 使用bulk API 初次索引的时候,把 replica 设置为 0 增大 threadpool.index.queue_size 增大 indices.memory.index_buffer_size 增大 index.translog.flush_threshold_ops 增大 index.translog.sync_interval 增大 index.engine.robin.refresh_intervalhttp://www.jianshu.com/p/5eeeeb4375d4 lucence 内部结构是什么 索引(Index): 在Lucene中一个索引是放在一个文件夹中的。 如上图,同一文件夹中的所有的文件构成一个Lucene索引。段(Segment): 一个索引可以包含多个段,段与段之间是独立的,添加新文档可以生成新的段,不同的段可以合并。 如上图,具有相同前缀文件的属同一个段,图中共三个段 “_0” 和 “_1”和“_2”。 segments.gen和segments_X是段的元数据文件,也即它们保存了段的属性信息。文档(Document): 文档是我们建索引的基本单位,不同的文档是保存在不同的段中的,一个段可以包含多篇文档。 新添加的文档是单独保存在一个新生成的段中,随着段的合并,不同的文档合并到同一个段中。域(Field): 一篇文档包含不同类型的信息,可以分开索引,比如标题,时间,正文,作者等,都可以保存在不同的域里。 不同域的索引方式可以不同,在真正解析域的存储的时候,我们会详细解读。词(Term): 词是索引的最小单位,是经过词法分析和语言处理后的字符串。

优秀的个人博客,低调大师

java面试- 深入理解JVM(七)——Class文件结构

什么是JVM的“无关性”? Java具有平台无关性,也就是任何操作系统都能运行Java代码。之所以能实现这一点,是因为Java运行在虚拟机之上,不同的操作系统都拥有各自的Java虚拟机,因此Java能实现“一次编写,处处运行”。 而JVM不仅具有平台无关性,还具有语言无关性。平台无关性是指不同操作系统都有各自的JVM,而语言无关性是指Java虚拟机能运行除Java以外的代码! 这听起来非常惊人,但JVM对能运行的语言是有严格要求的。首先来了解下Java代码的运行过程。 Java源代码首先需要使用Javac编译器编译成class文件,然后启动JVM执行class文件,从而程序开始运行。也就是JVM只认识class文件,它并不管何种语言生成了class文件,只要class文件符合JVM的规范就能运行。因此目前已经有Scala、JRuby、Jython等语言能够在JVM上运行。它们有各自的语法规则,不过它们的编译器都能将各自的源码编译成符合JVM规范的class文件,从而能够借助JVM运行它们。 纵观Class文件结构 class文件是二进制文件,它的内容具有严格的规范,文件中没有任何空格,全是连续的0/1。class文件中的所有内容被分为两种类型:无符号数 和 表。- 无符号数它表示class文件中的值,这些值没有任何类型,但有不同的长度。根据这些值长度的不同分为:u1、u2、u4、u8,分别代表1字节的无符号数、2字节的无符号数、4字节的无符号数、8字节的无符号数。- 表class文件中所有数据(即无符号数)要么单独存在,要么由多个无符号数组成二维表。即class文件中的数据要么是单个值,要么是二维表。 class文件的组织结构 魔数 本文件的版本信息 常量池 访问标志 类索引 父类索引 接口索引集合 字段表集合 方法表集合 Class文件的构成1:魔数 class文件的头4个字节称为魔数,用来表示这个class文件的类型。 魔数的作用就相当于文件后缀名,只不过后缀名容易被修改,不安全,因此在class文件中标示文件类型比较合适。 class文件的魔数是用16进制表示的“CAFEBABE”,非常具有浪漫主义色彩,谁说程序员的情商都很低! Class文件的构成2:版本信息 紧接着魔数的4个字节是版本号。它表示本class中使用的是哪个版本的JDK。 在高版本的JVM上能够运行低版本的class文件,但在低版本的JVM上无法运行高版本的class文件,即使该class文件中没有用到任何高版本JDK的特性也无法运行! Class文件的构成3:常量池 1. 什么是常量池? 紧接着版本号之后的就是常量池。常量池中存放两种类型的常量: 字面值常量字面值常量即我们在程序中定义的字符串、被final修饰的值。 符号引用符号引用就是我们定义的各种名字: 类和接口的全限定名 字段的名字 和 描述符 方法的名字 和 描述符 2. 常量池的特点 常量池长度不固定常量池的大小是不固定的,因此常量池开头放置一个u2类型的无符号数,用来存储当前常量池的容量。JVM根据这个值就知道常量池的头尾来。注:这个值是从1开始的,若为5表示池中有4个常量。 常量池中的常量由而为表来表示常量池开头有个常量池容量计数器,接下来就全是一个个常量了,只不过常量都是由一张张二维表构成,除了记录常量的值以外,还记录当前常量的相关信息。 常量池是class文件的资源仓库 常量池是与本class中其它部分关联最多的部分 常量池是class文件中空间占用最大的部分之一 3. 常量池中常量的类型 刚才介绍了,常量池中的常量大体上分为:字面值常量 和 符号引用。在此基础上,根据常量的数据类型不同,又可以被细分为14种常量类型。这14种常量类型都有各自的二维表示结构。每种常量类型的头1个字节都是tag,用于表示当前常量属于14种类型中的哪一个。 以CONSTANT_Class_info常量为例,它的二维表示结构如下:CONSTANT_Class_info表: 类型 名称 数量 u1 tag 1 u2 name_index 1 tag表示当前常量的类型(当前常量为CONSTANT_Class_info,因此tag的值应为7,表示一个类或接口的全限定名);name_index表示这个类或接口全限定名的位置。它的值表示指向常量池的第几个常量。它会指向一个CONSTANT_Utf8_info类型的常量,它的二维表结构如下:CONSTANT_Utf8_info表: 类型 名称 数量 u1 tag 1 u2 length 1 u1 bytes length CONSTANT_Utf8_info表示字符串常量;tag表示当前常量的类型,这里应该是1;length表示这个字符串的长度;bytes为这个字符串的内容(采用缩略的UTF8编码) 问:为什么Java中定义的类、变量名字必须小于64K?类、接口、变量等名字都属于符号引用,它们都存储在常量池中。而不管哪种符号引用,它们的名字都由CONSTANT_Utf8_info类型的常量表示,这种类型的常量使用u2存储字符串的长度。由于2字节最多能表示65535个数,因此这些名字的最大长度最多只能是64K。 问:什么是UTF-8编码?什么是缩略UTF-8编码?前者每个字符使用3个字节表示,而后者把128个ASKII码用1字节表示,某些字符用2字节表示,某些字符用3字节表示。 Class文件的构成4:访问标志 在常量池之后是2字节的访问标志。访问标志是用来表示这个class文件是类还是接口、是否被public修饰、是否被abstract修饰、是否被final修饰等。由于这些标志都由是/否表示,因此可以用0/1表示。访问标志为2字节,可以表示16位标志,但JVM目前只定义了8种,未定义的直接写0. Class文件的构成5:类索引、父类索引、接口索引集合 类索引、父类索引、接口索引集合是用来表示当前class文件所表示类的名字、父类名字、接口们的名字。它们按照顺序依次排列,类索引和父类索引各自使用一个u2类型的无符号常量,这个常量指向CONSTANT_Class_info类型的常量,该常量的bytes字段记录了本类、父类的全限定名。由于一个类的接口可能有好多个,因此需要用一个集合来表示接口索引,它在类索引和父类索引之后。这个集合头两个字节表示接口索引集合的长度,接下来就是接口的名字索引。 Class文件的构成6:字段表的集合 1. 什么是字段表集合? 接下来是字段表的集合。字段表集合用于存储本类所涉及到的成员变量,包括实例变量和类变量,但不包括方法中的局部变量。每一个字段表只表示一个成员变量,本类中所有的成员变量构成了字段表集合。 2. 字段表结构的定义 类型 名称 数量 u2 access_flags 1 u2 name_index 1 u2 descriptor_index 1 u2 attributes_count 1 attribute_info attributes attributes_count access_flags字段的访问标志。在Java中,每个成员变量都有一系列的修饰符,和上述class文件的访问标志的作用一样,只不过成员变量的访问标志与类的访问标志稍有区别。 name_index本字段名字的索引。指向一个CONSTANT_Class_info类型的常量,这里面存储了本字段的名字等信息。 descriptor_index描述符。用于描述本字段在Java中的数据类型等信息(下面详细介绍) attributes_count属性表集合的长度。 attributes属性表集合。到descriptor_index为止是字段表的固定信息,光有上述信息可能无法完整地描述一个字段,因此用属性表集合来存放额外的信息,比如一个字段的值。(下面会详细介绍) 3. 什么是描述符? 成员变量(包括静态成员变量和实例变量) 和 方法都有各自的描述符。对于字段而言,描述符用于描述字段的数据类型;对于方法而言,描述符用于描述字段的数据类型、参数列表、返回值。 在描述符中,基本数据类型用大写字母表示,对象类型用“L对象类型的全限定名”表示,数组用“[数组类型的全限定名”表示。描述方法时,将参数根据上述规则放在()中,()右侧按照上述方法放置返回值。而且,参数之间无需任何符号。 4. 字段表集合的注意点 一个class文件的字段表集合中不能出现从父类/接口继承而来字段; 一个class文件的字段表集合中可能会出现程序猿没有定义的字段如编译器会自动地在内部类的class文件的字段表集合中添加外部类对象的成员变量,供内部类访问外部类。 Java中只要两个字段名字相同就无法通过编译。但在JVM规范中,允许两个字段的名字相同但描述符不同的情况,并且认为它们是两个不同的字段。 Class文件的构成7:方法表的集合 在class文件中,所有的方法以二维表的形式存储,每张表来表示一个函数,一个类中的所有方法构成方法表的集合。方法表的结构和字段表的结构一致,只不过访问标志和属性表集合的可选项有所不同。 类型 名称 数量 u2 access_flags 1 u2 name_index 1 u2 descriptor_index 1 u2 attributes_count 1 attribute_info attributes attributes_count 方法表的属性表集合中有一张Code属性表,用于存储当前方法经编译器编译过后的字节码指令。 方法表集合的注意点 如果本class没有重写父类的方法,那么本class文件的方法表集合中是不会出现父类/父接口的方法表; 本class的方法表集合可能出现程序猿没有定义的方法编译器在编译时会在class文件的方法表集合中加入类构造器和实例构造器。 重载一个方法需要有相同的简单名称和不同的特征签名。JVM的特征签名和Java的特征签名有所不同: Java特征签名:方法参数在常量池中的字段符号引用的集合 JVM特征签名:方法参数+返回值 Class文件的构成8:属性表的集合

优秀的个人博客,低调大师

java面试-深入理解JVM(一)——JVM内存模型

JVM内存模型 Java虚拟机(Java Virtual Machine=JVM)的内存空间分为五个部分,分别是:1. 程序计数器2. Java虚拟机栈3. 本地方法栈4. 堆5. 方法区。 下面对这五个区域展开深入的介绍。 1. 程序计数器 1.1. 什么是程序计数器? 程序计数器是一块较小的内存空间,可以把它看作当前线程正在执行的字节码的行号指示器。也就是说,程序计数器里面记录的是当前线程正在执行的那一条字节码指令的地址。注:但是,如果当前线程正在执行的是一个本地方法,那么此时程序计数器为空。 1.2. 程序计数器的作用 程序计数器有两个作用: 字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。 在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。 1.3. 程序计数器的特点 是一块较小的存储空间 线程私有。每条线程都有一个程序计数器。 是唯一一个不会出现OutOfMemoryError的内存区域。 生命周期随着线程的创建而创建,随着线程的结束而死亡。 2. Java虚拟机栈(JVM Stack) 2.1. 什么是Java虚拟机栈? Java虚拟机栈是描述Java方法运行过程的内存模型。Java虚拟机栈会为每一个即将运行的Java方法创建一块叫做“栈帧”的区域,这块区域用于存储该方法在运行过程中所需要的一些信息,这些信息包括: 局部变量表存放基本数据类型变量、引用类型的变量、returnAddress类型的变量。 操作数栈 动态链接 方法出口信息 等 当一个方法即将被运行时,Java虚拟机栈首先会在Java虚拟机栈中为该方法创建一块“栈帧”,栈帧中包含局部变量表、操作数栈、动态链接、方法出口信息等。当方法在运行过程中需要创建局部变量时,就将局部变量的值存入栈帧的局部变量表中。当这个方法执行完毕后,这个方法所对应的栈帧将会出栈,并释放内存空间。 注意:人们常说,Java的内存空间分为“栈”和“堆”,栈中存放局部变量,堆中存放对象。这句话不完全正确!这里的“堆”可以这么理解,但这里的“栈”只代表了Java虚拟机栈中的局部变量表部分。真正的Java虚拟机栈是由一个个栈帧组成,而每个栈帧中都拥有:局部变量表、操作数栈、动态链接、方法出口信息。 2.2. Java虚拟机栈的特点 局部变量表的创建是在方法被执行的时候,随着栈帧的创建而创建。而且,局部变量表的大小在编译时期就确定下来了,在创建的时候只需分配事先规定好的大小即可。此外,在方法运行的过程中局部变量表的大小是不会发生改变的。 Java虚拟机栈会出现两种异常:StackOverFlowError和OutOfMemoryError。a) StackOverFlowError:若Java虚拟机栈的内存大小不允许动态扩展,那么当线程请求栈的深度超过当前Java虚拟机栈的最大深度的时候,就抛出StackOverFlowError异常。b) OutOfMemoryError:若Java虚拟机栈的内存大小允许动态扩展,且当线程请求栈时内存用完了,无法再动态扩展了,此时抛出OutOfMemoryError异常。 Java虚拟机栈也是线程私有的,每个线程都有各自的Java虚拟机栈,而且随着线程的创建而创建,随着线程的死亡而死亡。 注:StackOverFlowError和OutOfMemoryError的异同?StackOverFlowError表示当前线程申请的栈超过了事先定好的栈的最大深度,但内存空间可能还有很多。而OutOfMemoryError是指当线程申请栈时发现栈已经满了,而且内存也全都用光了。 3. 本地方法栈 3.1. 什么是本地方法栈? 本地方法栈和Java虚拟机栈实现的功能类似,只不过本地方法区是本地方法运行的内存模型。 本地方法被执行的时候,在本地方法栈也会创建一个栈帧,用于存放该本地方法的局部变量表、操作数栈、动态链接、出口信息。 方法执行完毕后相应的栈帧也会出栈并释放内存空间。 也会抛出StackOverFlowError和OutOfMemoryError异常。 4. 堆 4.1. 什么是堆? 堆是用来存放对象的内存空间。几乎所有的对象都存储在堆中。 4.2. 堆的特点 线程共享整个Java虚拟机只有一个堆,所有的线程都访问同一个堆。而程序计数器、Java虚拟机栈、本地方法栈都是一个线程对应一个的。 在虚拟机启动时创建 垃圾回收的主要场所。 可以进一步细分为:新生代、老年代。新生代又可被分为:Eden、From Survior、To Survior。不同的区域存放具有不同生命周期的对象。这样可以根据不同的区域使用不同的垃圾回收算法,从而更具有针对性,从而更高效。 堆的大小既可以固定也可以扩展,但主流的虚拟机堆的大小是可扩展的,因此当线程请求分配内存,但堆已满,且内存已满无法再扩展时,就抛出OutOfMemoryError。 5. 方法区 5.1. 什么是方法区? Java虚拟机规范中定义方法区是堆的一个逻辑部分。方法区中存放已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等。 5.2. 方法区的特点 线程共享方法区是堆的一个逻辑部分,因此和堆一样,都是线程共享的。整个虚拟机中只有一个方法区。 永久代方法区中的信息一般需要长期存在,而且它又是堆的逻辑分区,因此用堆的划分方法,我们把方法区称为老年代。 内存回收效率低方法区中的信息一般需要长期存在,回收一遍内存之后可能只有少量信息无效。对方法区的内存回收的主要目标是:对常量池的回收 和 对类型的卸载。 Java虚拟机规范对方法区的要求比较宽松。和堆一样,允许固定大小,也允许可扩展的大小,还允许不实现垃圾回收。 5.3. 什么是运行时常量池? 方法区中存放三种数据:类信息、常量、静态变量、即时编译器编译后的代码。其中常量存储在运行时常量池中。 我们一般在一个类中通过public static final来声明一个常量。这个类被编译后便生成Class文件,这个类的所有信息都存储在这个class文件中。 当这个类被Java虚拟机加载后,class文件中的常量就存放在方法区的运行时常量池中。而且在运行期间,可以向常量池中添加新的常量。如:String类的intern()方法就能在运行期间向常量池中添加字符串常量。 当运行时常量池中的某些常量没有被对象引用,同时也没有被变量引用,那么就需要垃圾收集器回收。 6. 直接内存 直接内存是除Java虚拟机之外的内存,但也有可能被Java使用。 在NIO中引入了一种基于通道和缓冲的IO方式。它可以通过调用本地方法直接分配Java虚拟机之外的内存,然后通过一个存储在Java堆中的DirectByteBuffer对象直接操作该内存,而无需先将外面内存中的数据复制到堆中再操作,从而提升了数据操作的效率。 直接内存的大小不受Java虚拟机控制,但既然是内存,当内存不足时就会抛出OOM异常。 综上所述 Java虚拟机的内存模型中一共有两个“栈”,分别是:Java虚拟机栈和本地方法栈。两个“栈”的功能类似,都是方法运行过程的内存模型。并且两个“栈”内部构造相同,都是线程私有。只不过Java虚拟机栈描述的是Java方法运行过程的内存模型,而本地方法栈是描述Java本地方法运行过程的内存模型。 Java虚拟机的内存模型中一共有两个“堆”,一个是原本的堆,一个是方法区。方法区本质上是属于堆的一个逻辑部分。堆中存放对象,方法区中存放类信息、常量、静态变量、即时编译器编译的代码。 堆是Java虚拟机中最大的一块内存区域,也是垃圾收集器主要的工作区域。 程序计数器、Java虚拟机栈、本地方法栈是线程私有的,即每个线程都拥有各自的程序计数器、Java虚拟机栈、本地方法区。并且他们的生命周期和所属的线程一样。而堆、方法区是线程共享的,在Java虚拟机中只有一个堆、一个方法栈。并在JVM启动的时候就创建,JVM停止才销毁。

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。