admin管理员组

文章数量:1794759

各大公司Java后端高级开发面试题总结

各大公司Java后端高级开发面试题总结

ThreadLocal(线程变量副本)


Java内存模型:


“你能不能谈谈,java GC是在什么时候,对什么东西,做了什么事情?”


Synchronized 与Lock都是可重入锁,同一个线程再次进入同步代码的时候.可以使用自己已经获取到的锁。

  • 某个线程在等待一个锁的控制权的这段时间需要中断

  • 需要分开处理一些wait-notify,ReentrantLock里面的Condition应用,能够控制notify哪个线程,锁可以绑定多个条件。

  • 具有公平锁功能,每个到来的线程都将排队等候。

  • 友情链接: Synchronized关键字、Lock,并解释它们之间的区别


    StringBuffer是线程安全的,每次操作字符串,String会生成一个新的对象,而StringBuffer不会;StringBuilder是非线程安全的


    fail-fast:机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。


    happens-before:如果两个操作之间具有happens-before 关系,那么前一个操作的结果就会对后面一个操作可见。


    Volatile和Synchronized四个不同点:

    1.保证此变量对所有线程的可见性,指一条线程修改了这个变量的值,新值对于其他线程来说是可见的,但并不是多线程安全的。

    Volatile如何保证内存可见性:

    1.当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存。

    同步:就是一个任务的完成需要依赖另外一个任务,只有等待被依赖的任务完成后,依赖任务才能完成。


    CAS(Compare And Swap) 无锁算法: CAS是乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。


    线程池的作用: 在程序启动的时候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程


    类加载器工作机制:


    一致性哈希:


    Redis数据结构: String—字符串(key-value 类型)


    java自动装箱拆箱深入剖析


    索引:B+,B-,全文索引

  • 经常出现在group by,order by和distinc关键字后面的字段

  • 经常与其他表进行连接的表,在连接字段上应该建立索引

  • 经常出现在Where子句中的字段

  • 经常出现用作查询选择的字段

  • 友情链接:MySQL:InnoDB存储引擎的B+树索引算法


    Spring IOC (控制反转,依赖注入)


    代理的共有优点:业务类只需要关注业务逻辑本身,保证了业务类的重用性。

    JDK和CGLIB生成动态代理类的区别:


    SpringMVC运行原理

  • 客户端请求提交到DispatcherServlet

  • 由DispatcherServlet控制器查询HandlerMapping,找到并分发到指定的Controller中。

  • Controller调用业务逻辑处理后,返回ModelAndView

  • DispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModelAndView指定的视图

  • 视图负责将结果显示到客户端

  • 友情链接:Spring:基于注解的Spring MVC(上)


    一个Http请求

    设计存储海量数据的存储系统:设计一个叫“中间层”的一个逻辑层,在这个层,将数据库的海量数据抓出来,做成缓存,运行在服务器的内存中,同理,当有新的数据到来,也先做成缓存,再想办法,持久化到数据库中,这是一个简单的思路。主要的步骤是负载均衡,将不同用户的请求分发到不同的处理节点上,然后先存入缓存,定时向主数据库更新数据。读写的过程采用类似乐观锁的机制,可以一直读(在写数据的时候也可以),但是每次读的时候会有个版本的标记,如果本次读的版本低于缓存的版本,会重新读数据,这样的情况并不多,可以忍受。

    友情链接: HTTP与HTTPS的区别


    Session与Cookie:Cookie可以让服务端跟踪每个客户端的访问,但是每次客户端的访问都必须传回这些Cookie,如果Cookie很多,则无形的增加了客户端与服务端的数据传输量,


    分布式Session框架

  • 配置服务器,Zookeeper集群管理服务器可以统一管理所有服务器的配置文件

  • 共享这些Session存储在一个分布式缓存中,可以随时写入和读取,而且性能要很好,如Memcache,Tair。

  • 封装一个类继承自HttpSession,将Session存入到这个类中然后再存入分布式缓存中

  • 由于Cookie不能跨域访问,要实现Session同步,要同步SessionID写到不同域名下。


  • 适配器模式:将一个接口适配到另一个接口,Java I/O中InputStreamReader将Reader类适配到InputStream,从而实现了字节流到字符流的准换。


    Spring事务配置方法:

    Spring通过aop/tx Schema 命名空间和@Transaction注解技术来进行声明式事物配置。


    Mybatis


    Servlet和Filter的区别:

    Filter有如下几个用处:

    实际上Filter和Servlet极其相似,区别只是Filter不能直接对用户生成响应。实际上Filter里doFilter()方法里的代码就是从多个Servlet的service()方法里抽取的通用代码,通过使用Filter可以实现更好的复用。

    Filter和Servlet的生命周期:


    HashMap与HashTable的区别。

    HashMap的实现机制:

  • 维护一个每个元素是一个链表的数组,而且链表中的每个节点是一个Entry[]键值对的数据结构。

  • 实现了数组+链表的特性,查找快,插入删除也快。

  • 对于每个key,他对应的数组索引下标是 int i = hash(key.hashcode)&(len-1);

  • 每个新加入的节点放在链表首,然后该新加入的节点指向原链表首

  • HashMap和TreeMap区别

    HashMap冲突


    HashMap,ConcurrentHashMap与LinkedHashMap的区别

  • ConcurrentHashMap是使用了锁分段技术技术来保证线程安全的,锁分段技术:首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问

  • ConcurrentHashMap 是在每个段(segment)中线程安全的

  • LinkedHashMap维护一个双链表,可以将里面的数据按写入的顺序读出

  • ConcurrentHashMap应用场景

    ConcurrentHashMap的应用场景是高并发,但是并不能保证线程安全,而同步的HashMap和HashTable的是锁住整个容器,而加锁之后ConcurrentHashMap不需要锁住整个容器,只需要锁住对应的segment就好了,所以可以保证高并发同步访问,提升了效率。

    ConcurrentHashMap能够保证每一次调用都是原子操作,但是并不保证多次调用之间也是原子操作。


    Vector和ArrayList的区别


    ExecutorService service = Executors…. ExecutorService service = new ThreadPoolExecutor() ExecutorService service = new ScheduledThreadPoolExecutor();

    ThreadPoolExecutor源码分析

    线程池本身的状态:

    等待任务队列和工作集:

    线程池的主要状态锁:

    线程池的存活时间和大小:

    1.2 ThreadPoolExecutor 的内部工作原理

  • 如果当前池大小 poolSize 小于 corePoolSize ,则创建新线程执行任务。

  • 如果当前池大小 poolSize 大于 corePoolSize ,且等待队列未满,则进入等待队列

  • 如果当前池大小 poolSize 大于 corePoolSize 且小于 maximumPoolSize ,且等待队列已满,则创建新线程执行任务。

  • 如果当前池大小 poolSize 大于 corePoolSize 且大于 maximumPoolSize ,且等待队列已满,则调用拒绝策略来处理该任务。

  • 线程池里的每个线程执行完任务后不会立刻退出,而是会去检查下等待队列里是否还有线程任务需要执行,如果在 keepAliveTime 里等不到新的任务了,那么线程就会退出。

  • Executor包结构

    CopyOnWriteArrayList : 写时加锁,当添加一个元素的时候,将原来的容器进行copy,复制出一个新的容器,然后在新的容器里面写,写完之后再将原容器的引用指向新的容器,而读的时候是读旧容器的数据,所以可以进行并发的读,但这是一种弱一致性的策略。


    Linux常用命令:cd,cp,mv,rm,ps(进程),tar,cat(查看内容),chmod,vim,find,ls


    死锁的必要条件

  • 互斥 至少有一个资源处于非共享状态

  • 占有并等待

  • 非抢占

  • 循环等待

  • 解决死锁,第一个是死锁预防,就是不让上面的四个条件同时成立。二是,合理分配资源。


    进程间的通信方式

  • 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。

  • 有名管道 (named pipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。

  • 信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。

  • 消队列( message queue ) : 消队列是由消的链表,存放在内核中并由消队列标识符标识。消队列克服了信号传递信少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。

  • 信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。

  • 共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。

  • 套接字( socket ) : 套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。


  • 进程与线程的区别和联系


    数据库事务是指作为单个逻辑工作单元执行的一系列操作。

    友情链接:数据库事务的四大特性以及事务的隔离级别


    MySQL数据库优化总结


    Hibernate的一级缓存是由Session提供的,因此它只存在于Session的生命周期中,当程序调用save(),update(),saveOrUpdate()等方法 及调用查询接口list,filter,iterate时,如Session缓存中还不存在相应的对象,Hibernate会把该对象加入到一级缓存中,当Session关闭的时候缓存也会消失。

    Hibernate的一级缓存是Session所内置的,不能被卸载,也不能进行任何配置一级缓存采用的是key-value的Map方式来实现的,在缓存实体对象时,对象的主关键字ID是Map的key,实体对象就是对应的值。

    Hibernate二级缓存:把获得的所有数据对象根据ID放入到第二级缓存中。Hibernate二级缓存策略,是针对于ID查询的缓存策略,删除、更新、增加数据的时候,同时更新缓存。

    进程和线程的区别:

    进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1–n个线程。

    线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。

    线程和进程一样分为五个阶段:创建、就绪、运行、阻塞、终止。

    多进程是指操作系统能同时运行多个任务(程序)。

    多线程是指在同一程序中有多个顺序流在执行。

    在java中要想实现多线程,有三种手段,一种是继续Thread类,另外一种是实现Runable接口,还有就是实现Callable接口。


    Switch能否用string做参数?

    a.在 Java 7 之前, switch 只能支持byte,short,char,int 或者其对应的封装类以及 Enum 类型。在Java 7中,String 支持被加上了。


    Object有哪些公用方法?

    a.方法equals测试的是两个对象是否相等

    b.方法clone进行对象拷贝

    c.方法getClass返回和当前对象相关的Class对象

    d.方法notify,notifyall,wait都是用来对给定对象进行线程同步的


    Java的四种引用,强弱软虚,以及用到的场景

    a.利用软引用和弱引用解决OOM问题:用一个HashMap来保存图片的路径和相应图片对象关联的软引用之间的映射关系,在内存不足时,JVM会自动回收这些缓存图片对象所占用的空间,从而有效地避免了OOM的问题。

    b.通过软可及对象重获方法实现Java对象的高速缓存:比如我们创建了一Employee的类,如果每次需要查询一个雇员的信。哪怕是几秒中之前刚刚查询过的,都要重新构建一个实例,这是需要消耗很多时间的。我们可以通过软引用和 HashMap 的结合,先是保存引用方面:以软引用的方式对一个Employee对象的实例进行引用并保存该引用到HashMap 上,key 为此雇员的 id,value为这个对象的软引用,另一方面是取出引用,缓存中是否有该Employee实例的软引用,如果有,从软引用中取得。如果没有软引用,或者从软引用中得到的实例是null,重新构建一个实例,并保存对这个新建实例的软引用。

    c.强引用:如果一个对象具有强引用,它就不会被垃圾回收器回收。即使当前内存空间不足,JVM也不会回收它,而是抛出 OutOfMemoryError 错误,使程序异常终止。如果想中断强引用和某个对象之间的关联,可以显式地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象。

    d.软引用:在使用软引用时,如果内存的空间足够,软引用就能继续被使用,而不会被垃圾回收器回收,只有在内存不足时,软引用才会被垃圾回收器回收。

    e.弱引用:具有弱引用的对象拥有的生命周期更短暂。因为当 JVM 进行垃圾回收,一旦发现弱引用对象,无论当前内存空间是否充足,都会将弱引用回收。不过由于垃圾回收器是一个优先级较低的线程,所以并不一定能迅速发现弱引用对象。

    f.虚引用:顾名思义,就是形同虚设,如果一个对象仅持有虚引用,那么它相当于没有引用,在任何时候都可能被垃圾回收器回收。


    Hashcode的作用,与 equal 有什么区别?

    a.同样用于鉴定2个对象是否相等的,java集合中有 list 和 set 两类,其中 set不允许元素重复实现,那个这个不允许重复实现的方法,如果用 equal 去比较的话,如果存在1000个元素,你 new 一个新的元素出来,需要去调用1000次 equal 去逐个和他们比较是否是同一个对象,这样会大大降低效率。hashcode实际上是返回对象的存储地址,如果这个位置上没有元素,就把元素直接存储在上面,如果这个位置上已经存在元素,这个时候才去调用equal方法与新元素进行比较,相同的话就不存了,散列到其他地址上。


    Override和Overload的含义以及区别


    抽象类和接口的区别

    a.一个类只能继承单个类,但是可以实现多个接口

    b.抽象类中可以有构造方法,接口中不能有构造方法

    c.抽象类中的所有方法并不一定要是抽象的,你可以选择在抽象类中实现一些基本的方法。而接口要求所有的方法都必须是抽象的

    d.抽象类中可以包含静态方法,接口中不可以

    e.抽象类中可以有普通成员变量,接口中不可以

    解析XML的几种方式的原理与特点:DOM、SAX、PULL

    a.DOM:消耗内存:先把xml文档都读到内存中,然后再用DOM API来访问树形结构,并获取数据。这个写起来很简单,但是很消耗内存。要是数据过大,手机不够牛逼,可能手机直接死机

    b.SAX:解析效率高,占用内存少,基于事件驱动的:更加简单地说就是对文档进行顺序扫描,当扫描到文档(document)开始与结束、元素(element)开始与结束、文档(document)结束等地方时通知事件处理函数,由事件处理函数做相应动作,然后继续同样的扫描,直至文档结束。

    c.PULL:与 SAX 类似,也是基于事件驱动,我们可以调用它的next()方法,来获取下一个解析事件(就是开始文档,结束文档,开始标签,结束标签),当处于某个元素时可以调用XmlPullParser的getAttributte()方法来获取属性的值,也可调用它的nextText()获取本节点的值。


    wait()和sleep()的区别

    sleep来自Thread类,和wait来自Object类

    调用sleep()方法的过程中,线程不会释放对象锁。而 调用 wait 方法线程会释放对象锁

    sleep睡眠后不出让系统资源,wait让出系统资源其他线程可以占用CPU

    sleep(milliseconds)需要指定一个睡眠时间,时间一到会自动唤醒


    JAVA 中堆和栈的区别,说下java 的内存机制

    a.基本数据类型比变量和对象的引用都是在栈分配的

    b.堆内存用来存放由new创建的对象和数组

    c.类变量(static修饰的变量),程序在一加载的时候就在堆中为类变量分配内存,堆中的内存地址存放在栈中

    d.实例变量:当你使用java关键字new的时候,系统在堆中开辟并不一定是连续的空间分配给变量,是根据零散的堆内存地址,通过哈希算法换算为一长串数字以表征这个变量在堆中的”物理位置”,实例变量的生命周期–当实例变量的引用丢失后,将被GC(垃圾回收器)列入可回收“名单”中,但并不是马上就释放堆中内存

    e.局部变量: 由声明在某方法,或某代码段里(比如for循环),执行到它的时候在栈中开辟内存,当局部变量一但脱离作用域,内存立即释放


    JAVA多态的实现原理

    a.抽象的来讲,多态的意思就是同一消可以根据发送对象的不同而采用多种不同的行为方式。(发送消就是函数调用)

    b.实现的原理是动态绑定,程序调用的方法在运行期才动态绑定,追溯源码可以发现,JVM 通过参数的自动转型来找到合适的办法。

    我有一个微信公众号,经常会分享一些Java技术相关的干货;如果你喜欢我的分享,可以用微信搜索“Java团长”或者“javatuanzhang”关注。

    出处:wwwblogs/java1024/p/7685400.html

    本文标签: 各大后端面试题高级公司