java面试题_java面试题2020 - CSDN
精华内容
参与话题
  • java面试题笔试常见选择题大全含答案

    万次阅读 多人点赞 2019-05-26 00:53:58
    java面试题笔试常见选择题大全含答案 1、9道常见的java笔试选择题 2、java多线程面试题选择题大全含答案 3、java异常处理面试题常见选择题含答案 4、java笔试常见的选择题(坑你没商量) 5、java笔试题大全之IO流...
    展开全文
  • 2年开发经验总结的java面试题(有完整答案)

    万次阅读 多人点赞 2020-04-28 11:38:36
    一、Java基础 部分 1、Java基本数据类型 有八种:四种整数类型(byte、short、int、long), 两种浮点数类型(double、float) 一种字符类型char,一种布尔类型Boolean 记忆:8位:Byte(字节型) 16位:short(短...

    一、Java基础 部分

    1、Java基本数据类型 

    有八种: 四种整数类型(byte、short、int、long),

                 两种浮点数类型(double、float)

                 一种字符类型char,一种布尔类型Boolean

    记忆:8位:Byte(字节型) 16位:short(短整型)、char(字符型)

               32位:int(整型)、float(单精度型/浮点型)

               64位:long(长整型)、double(双精度型)   最后一个:boolean(布尔类型)
    2、基本数据类型和封装类的区别 

    原始类型是类,引用类型是对象

    原始类型大小比较用"==" , 引用类型大小比较用"equals"

    引用类型可以被序列化,原始类型不行。

    在集合类中只能使用引用类型,不能使用原始类型

    基本数据类型不用new,封装类需要new

    基本数据参数传递是以值传递,封装类型是以地址传递的
    3、String、StringBuffer、StringBuilder区别 

    String是字符串常量,StringBuffer、StringBuilder是字符串变量,

    String创建的字符内容不可变(String底层char数组是final的),StringBuffer、StringBuilder的字符内容是可加长的

    StringBuffer是线程安全的,StringBuilder线程不安全的,但是速度快(因为它不会为线程安全消耗性能)

    补充:String为什么不可变

    虽然String、StringBuffer和StringBuilder都是final类,它们生成的对象都是不可变的,而且它们内部也都是靠char数组实现的,但是不同之处在于,String类中定义的char数组是final的,而StringBuffer和StringBuilder都是继承自AbstractStringBuilder类,它们的内部实现都是靠这个父类完成的,而这个父类中定义的char数组只是一个普通是私有变量,可以用append追加。因为AbstractStringBuilder实现了Appendable接口。

    4、运行时异常和非运行时异常区别 

    运行时异常是运行时报错:比如ClassCastException(类转换异常)、IndexOutOfBoundsException(数组越界)、NullPointerException(空指针)、ArrayStoreException(数据存储异常,操作数组时类型不一致)、IO操作的BufferOverflowException异常

    非运行时异常是还未运行可见的错误,可以try、catch捕获异常
    5、简述一下面向对象的特征,并举例说明你对面向对象的理解 

    面向对象的特征归结为封装继承多态,把现实世界的事物的属性、行为特征抽象出来放到一个容器里(类),比如人类,人的走、听、吃、说等动作可以归结为类里的方法,但又是人类的共同点,人有身高、体重归结为类里的属性

    封装:就是设计者把不愿意透露给使用者的那部分代码就是封装过的,通过修饰词private(权限最小)、public(权限最大)
            还用protected、default(属性前默认为该类型),这些才能起到限制类对象权限的作用.
        继承:子类继承父类的过程,继承者可以拥有父类全部方法属性,
            好处提高代码复用性,子类只需要写特有的功能或者字段可以把公共的代码 抽出到父类里面
        多态:通过父类统一子类方法属性,然后通过调用,可以任意使用子类方法,优化代码量,原理是子类对父类方法进行重写
            左边某个变量编译期是一个类型,右边运行期是另一个类型父类 变量名 = new 子类();条件是一个建立在继承关系中

    6、正则表达式的用法 

    定义要规范的字符串->制定规则->调用正则方法

    示例:String str = "dqwda16165"; String 正则表达式="[a-z]*[0-9]+"; system.out.println(str.matches(正则表达式)判断是否匹配)

    7、Java 语言如何进行异常处理,关键字:throws、throw、try、catch、finally分别代表什么意义?finally代码是在return之后还是之前执行? 

    throws抛出所有可能异常  throw是抛出具体异常类型  try是将会发生异常的语句括起来,异常处理 catch是有异常就执行其它代码

    finally无论如何都会执行,如果在try或catch有return,return执行完会等待finally结束才返回;

    8、abstract class和interface有什么区别?接口可以继承接口吗?接口可以继承抽象类吗,为什么?

    抽象类和接口区别:抽象类里抽象方法必须被子类实现,抽象类可以继承多个抽象类,普通类只能单继承抽象类,不能有主方法,可以有普通方法,抽象方法默认被public abstract修饰

    接口类里只能写抽象方法,属性默认被public static final修饰,多个接口可以被同一类实现,
    9、构造器(constructor)是否可被重写(override)? 

    构造器(constructor)不能被继承,所有不能重写,但能重载(overloading)
    10、是否可以继承String类? 

    public final class String extends Object,里边有final关键字,所以不能被继承。
    11、Java 中的final关键字有哪些用法? 

    修饰的变量必须初始化或不能修改,修饰类不能被继承,修饰方法不能被重写
    12、try{}里有一个return语句,那么紧跟在这个try后的finally{}里的代码会不会被执行,什么时候被执行,在return前还是后? 

    会执行 会在return执行完之后还没返回结果之前执行,return会把返回结果放到函数栈等待finally执行完之后才真正的返回;
    13、阐述final、finally、finalize的区别。

     final用于修饰类(不能继承)、变量(不能修改,只能赋值一次)、方法(不能重写)

    finally是用于try{}catch执行过程中有没有异常捕获都要执行的finally块,关闭资源等...

    finalize是方法名,对象遗言,用于在垃圾收集器回收清理对象之前要执行的方法,在object类定义的,所有类都继承了它
    14、如何通过反射创建对象? 

    通过Class对象的newInstance()方法来创建Class对象对应类的实例

    使用Class对象获取指定的Constructor对象,调用Constructor对象的newInstance()方法来创建Class对象对应类的实例。
    15、Java 8的新特性 

    一、Java 8引入了函数式接口的概念。Lambda允许把函数作为一个方法的参数,或者把代码看成数据。

    二、接口的默认方法与静态方法,在接口中定义默认方法,使用default关键字,并提供默认的实现。所有实现这个接口的类都会接受默认方法的实现,除非子类提供的自己的实现,在接口中定义静态方法,使用static关键字,也可以提供实现

    三、方法引用,结合Lambda表达式联合使用

    1.构造器引用。语法是Class::new 

    2.静态方法引用。语法是Class::static_method

    3.特定类的任意对象方法引用。它的语法是Class::method

    4.特定对象的方法引用,它的语法是instance::method

    四、Java 8引入重复注解,相同的注解在同一地方可以声明多次。重复注解机制本身需要用@Repeatable注解。Java 8在编译器层做了优化,相同注解会以集合的方式保存,因此底层的原理并没有变化

    五、扩展注解的支持,java 8扩展了注解的上下文,几乎可以为任何东西添加注解,包括局部变量、泛型类、父类与接口的实现,连方法的异常也能添加注解

    六、引入Optional类,防止空指针异常,Optional类实际上是个容器:它可以保存类型T的值,或者保存null。使用Optional类我们就不用显式进行空指针检查了

    七、引入Stream API ,函数式编程风格,让代码变得连串支持连续、并行聚集操作,简单明了

    八、JavaScript引擎Nashorn,Nashorn允许在JVM上开发运行JavaScript应用,允许Java与JavaScript相互调用。

    九、Base64,Base64类提供了对URL、MIME友好的编码器与解码器

    十、Date/Time API (JSR 310),提供了新的java.time包,可以用来替代 java.util.Date和java.util.Calendar,一般会用到Clock、LocaleDate、LocalTime、LocaleDateTime、ZonedDateTime、Duration这些类,对于时间日期的改进还是非常不错的;

    除了这十大新特性之外,还有另外的一些新特性:

    • 更好的类型推测机制:Java 8在类型推测方面有了很大的提高,这就使代码更整洁,不需要太多的强制类型转换了。

    • 编译器优化:Java 8将方法的参数名加入了字节码中,这样在运行时通过反射就能获取到参数名,只需要在编译时使用-parameters参数。

    • 并行(parallel)数组:支持对数组进行并行处理,主要是parallelSort()方法,它可以在多核机器上极大提高数组排序的速度。

    • 并发(Concurrency):在新增Stream机制与Lambda的基础之上,加入了一些新方法来支持聚集操作。

    • Nashorn引擎jjs:基于Nashorn引擎的命令行工具。它接受一些JavaScript源代码为参数,并且执行这些源代码。

    • 类依赖分析器jdeps:可以显示Java类的包级别或类级别的依赖。

    • JVM的PermGen空间被移除:取代它的是Metaspace(JEP 122)。

    16、Java数组和链表的两种结构的操作效率 

    数组效率高,数组底层是一个连续的内存空间,根据基地址和偏移量计算地址的;

    链表的数据是通过地址指向下一个数据地址找到的;
    17、Java的引用类型有哪几种 

    强引用、弱引用、软引用、虚引用
    二、多线程、IO、集合 部分
    1、ArrayList、Vector、LinkedList的存储性能和特性 

    ArrayList是以数组形式存储对象,因为它是存放在连续位置上,插入和删除麻烦,但查询效率高,连续的数组有序的可以根据索引查找;

    LinkedList将对象存储在独立的空间,每个空间保留了下一个链接的索引,查询效率低,但修改、删除效率高

    Vector使用了Synchronized方法(线程安全的),性能低于ArrayList

    补充:arraylist和vector的区别? 
    同步性:Vector是线程安全的,也就是说是同步的,而ArrayList是线程不安全的,不是同步的 
    数据增长:当需要增长时,Vector默认增长为原来一培,而ArrayList却是原来的一半
    2、List、Set、Map是否继承自Collection接口?

     List,Set是,Map不是
    3、List、Map、Set三个接口存取元素时,各有什么特点? 

    List允许数据重复,有序的,调用get(index i)来明确说明取第几个。

    Set不允许重复数据,内部有排序,只能以Iterator接口取得所有的元素,再逐一遍历各个元素

    Map是通过键值对存储数据,键唯一的,相同数据会覆盖,用get(Object key)方法根据key获得相应的value
    4、请说出与线程同步以及线程调度相关的方法。 

    wait():使一个线程处于等待(阻塞)状态,并且释放所持有的对象的锁

    sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要处理InterruptedException异常

    notify():唤醒一个处于等待状态的线程,当然在调用此方法的时候,唤醒等待状态的线程不确定

    notityAll():唤醒所有处于等待状态的线程,该方法并不是将对象的锁给所有线程,而是让它们竞争,只有获得锁的线程才能进入就绪状态;
    5、编写多线程程序有几种实现方式? 

    java5 以前第一种是继承Thread类(单继承不推荐)、第二种实现Runnable接口,重写run,java5以后可以实现Callable接口,重写call函数
    6、简述synchronized 和java.util.concurrent.locks.Lock的异同? 

    相同点:Lock有synchronized所有功能

    不同点:Lock比synchronized性能更好,线程语义更精准,synchronized是自动释放锁,Lock必须要在finally手动释放
    7、hash碰撞以及hash算法、如何解决哈希冲突 

    解决hash冲突的方法: 
    开放定址法:一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入。没有空的位置就会进行扩容。

    链地址法: 
    将所有关键字为同义词的记录存储在一个单链表中,一旦发生冲突,在当前位置给单链表增加结点就行。 
    缺点:查找时需要遍历单链表的性能损耗。

    8、ArrayList和HashSet的区别,HashMap和Hashtable的区别? 

    ArrayList是实现List接口,HashSet是实现Set接口

    ArrayList是数组存储。HashSet存储对象,具有HashMap的特性。

    ArrayList是有序可重复,HashSet是无序不可重复判断重复的标准是 equals方法 /hashCode方法

    HashSet和HashMap都是线程不安全的

    HashMap实现Map接口,HashSet是实现Set接口

    HashMap是键值对存储,键不能重复,值可以重复,而且查询速度比HashSet快,通过键查询值;

    11题关于第二个比较

    9、HashMap的存储原理,需要了解HashMap的源码。 

    HashMap底层是通过hash表数据结构实现的,该结构有数组的查询容易,又有链表的插入删除容易的特性;
    10、ArrayList和LinkedList的各自实现和区别 

    都是List接口的实现,ArrayList底层是动态数组存储方式,LinkedList是双向链表存储方式

    ArrayList查询效率高,添加删除效率低

    LinkedList查询效率低,添加删除效率高
    11、HashMap和HashTable区别 

    Hashtable继承自Dictionary类,而HashMap是Java1.2引进的Map interface的一个实现

    HashMap允许将null作为一个entry的key或者value,而Hashtable不允许

    HashMap是非synchronized,而Hashtable是synchronized

    两者通过hash值散列到hash表的算法不一样:HashTbale是古老的除留余数法,直接使用hashcode

    12、Hashtable,HashMap,ConcurrentHashMap 底层实现原理与线程安全问题 

    Hashtable线程安全的,

    • 底层数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低,ConcurrentHashMap做了相关优化
    • 初始size为11,扩容:newsize = olesize*2+1
    • 计算index的方法:index = (hash & 0x7FFFFFFF) % tab.length

    HashMap线程不安全的,

    • 底层数组+链表实现,可以存储null键和null值,线程不安全
    • 初始size为16,扩容:newsize = oldsize*2,size一定为2的n次幂
    • 扩容针对整个Map,每次扩容时,原来数组中的元素依次重新计算存放位置,并重新插入
    • 插入元素后才判断该不该扩容,有可能无效扩容(插入后如果扩容,如果没有再次插入,就会产生无效扩容)
    • 当Map中元素总数超过Entry数组的75%,触发扩容操作,为了减少链表长度,元素分配更均匀
    • 计算index方法:index = hash & (tab.length – 1)

    ConcurrentHashMap 线程安全的,

    • 底层采用分段的数组+链表实现,线程安全
    • 通过把整个Map分为N个Segment,可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。(读操作不加锁,由于HashEntry的value变量是 volatile的,也能保证读取到最新的值。)
    • Hashtable的synchronized是针对整张Hash表的,即每次锁住整张表让线程独占,ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术
    • 有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁
    • 扩容:段内扩容(段内元素超过该段对应Entry数组长度的75%触发扩容,不会对整个Map进行扩容),插入前检测需不需要扩容,有效避免无效扩容

    13、Hash冲突怎么办?哪些解决散列冲突的方法? 

    开放定址法:一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入。没有空的位置就会进行扩容。

    链地址法: 
    将所有关键字为同义词的记录存储在一个单链表中,一旦发生冲突,在当前位置给单链表增加结点就行。 
    缺点:查找时需要遍历单链表的性能损耗。

    14、讲讲IO里面的常见类,字节流、字符流、接口、实现类、方法阻塞。 

    文件字节输入输出流 FileInputStream/FileOutputStream,

    文件字符流 FileReader/FileWriter

    包装流PrintStream/PrintWriter/Scanner

    字符串输入输出流StringReader/StringWriter

    转换流InputStreamReader/OutputStreamReader

    缓存流BufferedReader/BufferedWriter , BufferedInputStream/BufferedOutputStream

    Flushable接口、Appendable接口、Readable接口

       同步阻塞IO:在此种方式下,用户进程在发起一个IO操作以后,必须等待IO操作的完成,只有当真正完成了IO操作以后,用户进程才能运行。

        异步阻塞NIO:此种方式下是指应用发起一个IO操作以后,不等待内核IO操作的完成,等内核完成IO操作以后会通知应用程序,这其实就是同步和异步最关键的区别,同步必须等待或者主动的去询问IO是否完成

    15、讲讲NIO。 

    14题有答案
    16、递归读取文件夹下的文件,代码怎么实现 

    不好描述,设计一个方法传入文件路径,判断是否为空,不为空new File(testFileDir).listFiles();,然后再判断空,最后遍历是文本文件还是文件目录;
    17、常用的线程池模式以及不同线程池的使用场景 

    newCachedThreadPool 执行很多短期异步的小程序或者负载较轻的服务器

    newFixedThreadPool 执行长期的任务,性能好很多

    newSingleThreadExecutor 一个任务一个任务执行的场景

    NewScheduledThreadPool 周期性执行任务的场景

    线程池任务执行流程:

    1. 当线程池小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程。
    2. 当线程池达到corePoolSize时,新提交任务将被放入workQueue中,等待线程池中任务调度执行
    3. 当workQueue已满,且maximumPoolSize>corePoolSize时,新提交任务会创建新线程执行任务
    4. 当提交任务数超过maximumPoolSize时,新提交任务由RejectedExecutionHandler处理
    5. 当线程池中超过corePoolSize线程,空闲时间达到keepAliveTime时,关闭空闲线程
    6. 当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize线程空闲时间达到keepAliveTime也将关闭

    18、newFixedThreadPool此种线程池如果线程数达到最大值后会怎么办,底层原理。 

    设置固定尺寸的线程池、可变尺寸连接池

    创建线程池方法:

    固定大小的线程池,ExecutorService pool = Executors.newFixedThreadPool(5)

    单任务线程池,ExecutorService pool = Executors.newSingleThreadExecutor()

    可变尺寸的线程池,ExecutorService pool = Executors.newCachedThreadPool()

    延迟连接池,ExecutorService pool = Executors.newScheduledThreadPool(2)

    如果当前线程数小于指定的最大数量则创建新的线程执行任务,否则加入到缓冲队列workQueue

    最终是把需要执行的线程放到一个工作线程workers HashSet里面。这里的work与Thread是分离的,这样做的好处是,如果我们的业务代码,需要对于线程池中的线

    程,赋予优先级、线程名称、线程执行策略等其他控制时,可以实现自己的ThreadFactory进行扩展,无需继承或改写ThreadPoolExecutor
    19、了解可重入锁的含义,以及ReentrantLock 和synchronized的区别 

    从名字上理解,ReenTrantLock的字面意思就是再进入的锁,其实synchronized关键字所使用的锁也是可重入的,两者关于这个的区别不大。两者都是同一个线程没进入一次,锁的计数器都自增1,所以要等到锁的计数器下降为0时才能释放锁。

    除了synchronized的功能,多了三个高级功能。 
    等待可中断,公平锁,绑定多个Condition。 
    1. 等待可中断:在持有锁的线程长时间不释放锁的时候,等待的线程可以选择放弃等待,tryLock(long timeout, TimeUnit unit) 
    2. 公平锁:按照申请锁的顺序来一次获得锁称为公平锁,synchronized的是非公平锁,ReentrantLock可以通过构造函数实现公平锁。new RenentrantLock(boolean fair) 
    3. 绑定多个Condition:通过多次newCondition可以获得多个Condition对象,可以简单的实现比较负责的线程同步的功能,通过await(),signal();
    20、atomicinteger和volatile等线程安全操作的关键字的理解和使用 

    volatile关键字

      volatile是一个特殊的修饰符,只有成员变量才能使用它,与Synchronized及ReentrantLock等提供的互斥相比,Synchronized保证了Synchronized同步块中变量的可见性,而volatile则是保证了所修饰变量的可见性。可见性指的是在一个线程中修改变量的值以后,在其他线程中能够看到这个值(在Java并发程序缺少同步类的情况下,多线程对成员变量的操作对其它线程是透明的(不可见))。因为volatile只是保证了同一个变量在多线程中的可见性,所以它更多是用于修饰作为开关状态的变量。

    原子操作Atomic

      Volatile变量可以确保先行关系,保证下一个读取操作会在前一个写操作之后发生(即写操作会发生在后续的读操作之前),但它并不能保证原子性。例如用volatile修饰count变量,那么count++ 操作就不是原子性的。

    21、进程和线程的区别 

    进程是系统资源分配的最小单位,线程是程序执行的最小单位,一般启动一个进程就会分配一个空间地址,建立数据表来维护代码段、堆栈段和数据段;进程程序比较健壮,一个进程死掉不会影响到其它独立的进程,而线程死掉就会影响到整个进程;

    线程是在同一进程下共享全局变量和静态变量,进程是以IPC进行的;
    22、同步和异步,阻塞和非阻塞 

    同步与异步
      同步与异步是针对应用程序与内核的交互而言的。同步过程中进程触发IO操作并等待或者轮询的去查看IO操作是否完成。异步过程中进程触发IO操作以后,直接返回,做自己的事情,IO交给内核来处理,完成后内核通知进程IO完成。

    阻塞与非阻塞
      应用进程请求I/O操作时,如果数据未准备好,如果请求立即返回就是非阻塞,不立即返回就是阻塞。简单说就是做一件事如果不能立即获得返回,需要等待,就是阻塞,否则就可以理解为非阻塞

    三、设计模式 
    1、简述一下你了解的设计模式。 

    单利模式用于不会频繁创建对象的场景,只能创建一个对象,节约内存,加快对象访问速度;

    工厂模式普通来说就是根据用户需求创建对象,对象方法是继承父类过来的;适配器模式就是多写一个实现类来继承,通过一个适配器类帮需要添加监听器的对象实现了监听器里所有方法;这个对象只需要实现它需要的方法。

    模板模式相当于模版,并没有实现,需要具体的使用才能实现(按照一定规律才产生),把几个对象相同的动作抽取到一个接口里,在接口定义动作执行顺序;对象执行动作时实现该接口的方法;最后创建环境测试对象的执行顺序调用动作方法;

    代理模式,代理一般是指为其他对象提供代理以控制对这个对象的访问,某些情形下,不适合直接引用目标对象或者不适合在其他对象中引用,则可以使用代理模式,以增强对主业务逻辑。

    装饰者模式,动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。

    享元模式是结构型设计模式的一种,是池技术的重要实现方式,它可以减少应用程序创建的对象,降低程序内存的占用,提高程序的性能,用于大量出现相似的对象,缓冲池;

    观察者模式就是发布订阅模式,发布者发布信息,订阅者获取信息,订阅了就能收到信息,没订阅就收不到信息;
    2、写出单利模式,懒汉和饿汉 
    四、JVM 
    1、描述一下JVM加载class文件的原理机制? 

    装载:查找和导入class文件;

    检查:载入的class文件数据的正确性;

    准备:为类的静态变量分配存储空间;

    解析:将符号引用转换成直接引用(这一步是可选的)

    初始化:初始化静态变量,静态代码块,在程序调用类的静态成员的时候开始执行,所以静态方法main()才会成为一般程序的入口方法。类的构造器也会引发该动

    2、Java 中会存在内存泄漏吗,请简单描述。 

    内存泄露就是指一个不再被程序使用的对象或变量一直在内存中占据着,java中内存泄露的发生场景,通俗地说,就是程序员可能创建了一个对象,以后一直不再使用这个对象,这个对象却一直被引用,即这个对象无用但是却无法被垃圾回收器回收的,这就是java中的内存泄露,如果一个外部类的实例对象的方法返回了一个内部类的实例对象,这个内部类对象被长期引用了,即使那个外部类实例对象不再被使用,但由于内部类持久外部类的实例对象,这个外部类对象将不会被垃圾回收,这也会造成内存泄露。
    3、GC是什么?为什么要有GC?

    GC是垃圾收集的意思,用于防止内存泄露,有效的利用内存。垃圾回收器通常是作为一个单独的低优先级的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收 ;
    4、JVM的内存模型(重要、GC算法、新生代、老年代、永久代等需要详细了解) 

    新生代。新建的对象都是用新生代分配内存,Eden空间不足的时候,会把存活的对象转移到Survivor中,新生代大小可以由-Xmn来控制,也可以用-XX:SurvivorRatio来控制Eden和Survivor的比例

    旧生代。用于存放新生代中经过多次垃圾回收仍然存活的对象

    持久代(Permanent Space)实现方法区,主要存放所有已加载的类信息,方法信息,常量池等等。可通过-XX:PermSize和-XX:MaxPermSize来指定持久带初始化值和最大值。Permanent Space并不等同于方法区,只不过是Hotspot JVM用Permanent Space来实现方法区而已,有些虚拟机没有Permanent Space而用其他机制来实现方法区。

    标记-整理(Mark-Compact)
      此算法结合了“标记-清除”和“复制”两个算法的优点。也是分两阶段,第一阶段从根节点开始标记所有被引用对象,第二阶段遍历整个堆,把清除未标记对象并且把存活对象“压缩”到堆的其中一块,按顺序排放。此算法避免了“标记-清除”的碎片问题,同时也避免了“复制”算法的空间问题。

    5、GC的工作原理 

    GC通过每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收,GC是后台的守护进程,对于Java程序员来说,分配对象使用new关键字;释放对象时,只要将对象所有引用赋值为null,让程序不能够再访问到这个对象,我们称该对象为"不可达的".GC将负责回收所有"不可达"对象的内存空间。 

    对于GC来说,当程序员创建对象时,GC就开始监控这个对象的地址、大小以及使用情况。通常,GC采用有向图的方式记录和管理堆(heap)中的所有对象。通过这种方式确定哪些对象是"可达的",哪些对象是"不可达的".当GC确定一些对象为"不可达"时,GC就有责任回收这些内存空间。但是,为了保证GC能够在不同平台实现的问题,Java规范对GC的很多行为都没有进行严格的规定。例如,对于采用什么类型的回收算法、什么时候进行回收等重要问题都没有明确的规定。因此,不同的JVM的实现者往往有不同的实现算法。这也给Java程序员的开发带来行多不确定性。
    五、数据库 
    1、事务的ACID是指什么? 

    原子性(Atomicity):操作过程不可分割,要么都成功,要么都失败

    一致性(Consistency):事物操作之后,操作前后数据不变;比如转账减少的跟增加的值不变

    隔离性(Isolation):多个事物之间的操作是分隔的,互不干扰,如果有多个事务去操作同一个数据的时候,就会事务并发问题(抢购 秒杀)

    持久性(Durability):成功的完成一个事物处理后,最终commit把数据将永久保存在数据库;

    2、悲观锁和乐观锁的区别 

    悲观锁 就是很悲观,每次去拿数据的时候都认为别人会修改,每次获取数据前都要被加锁,

    乐观锁 就是很乐观,每次去拿数据的时候都认为别人不会修改,不会加锁,但是每次更新时都要判断是否被修改过,可以使用版本号判断;
    3、Left join、right join、inner join区别 

    left join(左联接)        返回包括左表中的所有字段记录、只返回右表中和左表交集的记录,不匹配的部分显示null 
    right join(右联接)      返回包括右表中的所有记录和左表中联结字段相等的记录,不匹配的部分显示null
    inner join(等值连接) 只返回两个表中联结字段相等的行
    4、SQL优化 

    DDL优化

    变多次索引维护为一次索引维护:插入数据禁用索引,插入后再开启;

    变多次唯一校验为一次唯一校验:关闭唯一校验,批量插入数据,插入后开启

    变多次事务提交为一次事务提交:把多条插入语句合并为一条

    在SQL中避免where或order by后经常出现的字段上建索引,出现<>、is null、in、not in、避免在 where 子句中使用 or 来连接条件、like前置匹配都会变成全表扫描,索引失效;

    5、redis缓存数据库,需要了解,什么是内存数据库,支持的数据类型 

    把经常使用的数据存放在内存中,全局共享,减少和数据库之间的交互频率,提升数据访问速度,主要用于应用程序全局共享缓存,常见的内存数据库有Redis、memcached、FastDB,支持的常用数据类型可以是键值对数据结构的value支持各种数据类型
    6、单个索引、联合索引、主键索引 

    单个索引就是在一个列上面创建索引

    联合索引:索引可以覆盖多个数据列,如像INDEX(columnA, columnB)索引,这就是联合索引。

    主键索引:设定主键而创建的索引,把某个列设为主键的时候,数据库就会給改列创建索引(主键非空且唯一)
    7、索引的数据结构 

    B-树、B+树、R-树、散列

    B-树结构支持插入、控制操作以及通过管理一系列树根状结构的彼此联通的节点中来做选择。B-树结构中有两种节点类型:索引节点和叶子节点。叶子节点是存储数据的,而索引节点是用来告诉用户存储在叶子节点中的数据的顺序,并帮助用户找到数据。

    B+树是B-树结构的增强版,尽管B+树支持B-树的所有特性,他们之间最显著的不同点在于B+树中底层数据是按照提及的索引列进行排序的。B+树还通过在叶子节点之间附加引用来优化扫描的性能。

    散列表数据结构是一个简单的概念,他将一种算法应用到给定值中以在底层数据存储系统中返回一个唯一的指针或位置。散列表的优点是始终以线性时间复杂度找到需要读取的行的位置,而不想B-树那样需要跨越多层节点来确定位置。

    R-树数据结构支持基于数据类型对集合数据进行管理。目前只有MyIsam使用R-树支持空间索引。使用空间索引也有很多限制,比如只支持唯一的NOT NULL列等。空间索引并不常用。
    8、数据库的锁,行锁、表锁、悲观锁、乐观锁 

    表锁偏向MyISAM存储引擎,开销小,加锁快;无死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低;

    偏向InnoDB存储引擎,开销大,加锁慢;会出现死锁;锁定粒度小,发生锁冲突的概率最低,并发度最高。

    InnoDB与MyISAM的最大不同有两点:一是支持事务;二是彩了行级锁

    #悲观锁:进行业务操作前先加锁,即一锁二查三更新。

    #乐观锁先进行业务操作,不到万不得已不去拿锁。

    六、框架 
    1、web Service 常用注解 客户端如何生成,还是手写 

    @WebService(serviceName="PojoService", portName="PojoPort", name="PojoPortType", targetNamespace="http//:Pojo")
      serviceName 对应 <service name="PojoService"> 
      portName 对应 <service>下的 <port name="PojoPort">          
          name 对应 <portType name="PojoPortType">

         targetNamespace 对应 targetNamespace="http//:Pojo"

    定义schemaLocation的显示
    @WebMethod(operationName="queryPojo",exclude=true)
           operationName 接口的方法名、exclude 用于阻止将某一继承方法公开为web服务,默认为false

    @WebResult(name="returnWord") 接口的返回值

    @WebParam(name="cityName")接口的参数

    2、mybatis处理大数据 

    分表分为水平分表(hash分表、时间、区间分表)、垂直分表(不常用字段单独表),比如区间分表,有跨表查询情况使用关键字 union union all
    3、AOP IOC优点缺点 

    AOP缺点:性能略低,仅适用于方法调用,必须在Spring容器

    AOP优点:从Ioc容器中直接获得一个对象然后直接使用,无需事先创建,让逻辑业务分解,解耦代码,改变了OOP(Object Oriented Programming)面向对象编程的不足

    IOC缺点:生成一个对象的步骤变复杂了(忽略),缺少IDE重构的支持,如果修改了类名,还需到XML文件中手动修改,这似乎是所有XML方式的缺憾所在

    IOC优点:实现组件之间的解耦,提高程序的灵活性和可维护性
    4、spring事务传播属性和隔离级别 

    NEVER        绝对不能有事物,不然报错,有事物的方法调用也不行;
    REQUIRED 普通方法调用,单开事物,有事物方法调用,就用有事物方法的事物
    REQUIRES_NEW 无论有没有事物的方法调用 我都坚持执行自己的事物
    SUPPORTS 有事物的方法调用就用你的,没有就没事物

    Dirty Reads 脏读:客户看到的不是数据库真实数据,解决 事物提交前,不允许其他事物访问修改过的值

    Phantom Reads 幻像读:一个事务读取到另一个事务里已插入的数据, 解决 其他事物处理完数据前,不允许添加新数据

    Non-Repeatable Reads 不可重复读 :后续读取数据读取到其它事务已提交的更新数据,导致前后读取数据不一致,解决 读取数据在修改之后;

    5、Web Service 客户端和服务端实现技术 
    待定...
    6、Spring Mvc返回json技术 

    第一种 每个json视图controller配置一个Jsoniew

    第二种 使用JSON工具将对象序列化成json,常用工具Jackson,fastjson,gson

    第三种 利用spring mvc3的注解@ResponseBody

    7、Hibernate悲观锁和乐观锁 

    Hibernate悲观锁:在数据有加载的时候就给其进行加锁,直到该锁被释放掉,其他用户才可以进行修改,优点:数据的一致性保持得很好,缺点:不适合多个用户并发访问。当一个锁住的资源不被释放掉的时候,这个资源永远不会被其他用户进行修改,容易造成无限期的等待。

    Hibernate乐观锁:就是在对数据进行修改的时候,对数据才去版本或者时间戳等方式来比较,数据是否一致性来实现加锁。优点比较好。
    8、Hibernate三种状态 

    临时状态:new的对象还未持久化,还没处于Session中

    持久状态:已经持久化,加入到session缓存冲,处于此状态的对象叫持久对象;

    游离状态:持久化对象脱离了Session的对象。如Session缓存被清空的对象。特点:已经持久化,但不在Session缓存中。处于此状态的对象叫游离对象;
    9、hibernate和ibatis的区别 

    ibatis:开源项目上手简单,开发灵活,开发工作量大,大多自己写sql,很多配置文件

    Hibernate:开源的对象关系映射框架,开发效率高,但不能干扰sql,做优化程度较低

    10、讲讲mybatis连接池 

    常见的mybatis连接池有原生、c3p0、dbcp三类,通过工厂模式创建DataSource接口,它的实现有unpooledDataSource(不带连接池的数据源),PooledDataSource(带连接池的数据源),它们都可以通过对应的工厂类对象获取;

    拿PooledDataSource来说的话首先:需要一个连接数据库的对象,在执行SQL语句的时候获取java.sql.Connection连接对象

    其次:PooledDataSource数据源将Connection连接池对象包裹成PooledConnection对象放到了PoolState类型的容器中维护。 MyBatis将连接池中的连接池dui分为两种状态: 空闲状态(idle)和活动状态(active),PooledConnection对象分别被存储到PoolState容器内的idleConnections和activeConnections两个List集合中:

    空闲(idle)状态就把PooledConnection对象被放置到idleConnections集合中,表示当前闲置的没有被使用的PooledConnection集合,调用PooledDataSource的getConnection()方法时,会优先从此集合中取PooledConnection对象。当用完一个java.sql.Connection对象时,MyBatis会将其包裹成PooledConnection对象放到此集合中。

    活动(active)状态下把PooledConnection对象被放置到名为activeConnections的ArrayList中,表示当前正在被使用的PooledConnection集合,调用PooledDataSource的getConnection()方法时,会优先从idleConnections集合中取PooledConnection对象,如果没有,则看此集合是否已满,如果未满,PooledDataSource会创建出一个PooledConnection,添加到此集合中,并返回;

    11、SpringMVC的工作原理 

     用户发送请求,被前端控制器DispatcherServlet捕获拦截;

    DispatcherServlet调用HandlerMapping处理器映射管理对象获得Handler处理器;

    DispatcherServlet根据Handler去获取适合的适配器HandlerAdpter,HttpMessageConveter将请求信息转换成指定的响应对象;

    有了适配器,把请求参数填充到Handler,spring就开始执行Handler(Controller)进行数据转换、数据验证、数据格式化操作

    Handler执行完之后,向DispatcherServlet返回一个ModelAndView对象;

    根据返回的ModelAndView选择一个合适的ViewResolver视图解析器,找到ModelAndView指定的视图;

    ViewResolver结合Model、View渲染显示页面; 

    12、Spring的几种注入方式 

    注解注入、setter注入、构造器注入
    13、Spring如何实现事务管理 

    编程式事务管理:将事务管理代码嵌入到业务方法中来控制事务的提交和回滚,在编程式事务中,必须在每个业务操作中包含额外的事务管理代码

    声明式事务管理:使用spring aop拦截器实现
    14、Spring IOC和AOP的原理 

    IOC主要是帮我们创建对象和管理bean的容器,它控制反转就是把创建对象的权力交给ioc容器(spring容器),启动spring的时候把xml和其它配置文件加载信息到ioc容器,ioc再建立注册信息表来管理,再通过注册表实力化成bean,把bean放到spring容器bean缓冲池(hashMap实现),然后使用bean直接从缓存池取;记住:spring的配置文件用于描述bean关系的,利用反射功能建立bean依赖关系;

    Spring AOP底层是动态代理,动态代理分为jdk代理和cglib代理,jdk代理要求代理的类必须有父类接口,它主要通过Proxy和InvocationHandler接口,实现InvocationHandler接口并实现它的invoke方法,该方法传入参数有接口对象和接口方法,然后通过反射创建代理对象(需要传入两个参数一个是当前调用类的实例,一个是实现InvocationHandler的实例并传入接口)
    七、算法和数据结构 
    1、写出快速排序和冒泡排序算法 

    class MaoPao{
        /*
        int[] x={1,2,3,4,5,6};
        用冒泡排序排列出来
        */
        public static void main(String[] args){
                int[] pp={1,2,3,4,5,6};//准备数组
                        pai(pp);
                String x=java.util.Arrays.toString(pp);
                    System.out.println(x);
        }
        public static void pai(int[] arr){
                        int temp=0;
                    for(int i=0;i<arr.length;i++){
                        for(int j=0;j<arr.length-1;j++){
                            if(arr[j]<arr[j+1]){
                                temp=arr[j+1];
                                arr[j+1]=arr[j];
                                arr[j]=temp;
                            }
                        }
                }
          }
    }
    快速排序
    /**
     * 查找出中轴(默认是最低位low)的在numbers数组排序后所在位置
     * 
     * @param numbers 带查找数组
     * @param low 开始位置
     * @param high 结束位置
     * @return 中轴所在位置
     */
    public static int getMiddle(int[] numbers, int low,int high)
    {
     int temp = numbers[low]; //数组的第一个作为中轴
     while(low < high)
     {
     while(low < high && numbers[high] > temp)
     {
      high--;
     }
     numbers[low] = numbers[high];//比中轴小的记录移到低端
     while(low < high && numbers[low] < temp)
     {
      low++;
     }
     numbers[high] = numbers[low] ; //比中轴大的记录移到高端
     }
     numbers[low] = temp ; //中轴记录到尾
     return low ; // 返回中轴的位置
    }


    八、Linux基础 
    1、常用命令 

    解压文件 tar -zxvf 文件名.tar.gz

    rm -rf 文件名或文件名/*  强制暴力删除

    tail -n 3 -f 1.txt  //动态显示文件后3行内容(查看最新日志(实时更新))

    mv 文件1 文件2 移动文件命令

    ls -l //以详细信息方式列出文件信息

    ls 目录名  //查看该目录的文件信息

    whoami    //查看当前操作用户

    who am i  //查看当前登录用户(有可能是有多个的)的信息

    su - root //切换到root用户和su - 一样

    mkdir 目录名  //创建一个目录

    mkdir -p 目录1/目录2/目录3  //递归创建目录

    cp -rf dir1/* dir2 //直接复制内容(非常重要)

    echo hello > 1.txt     //以覆盖写的方式将hello字符添加到文件1.txt

    echo world >> 1.txt    //以追加的方式将world字符添加到文件1.txt

    cat 2.txt > 1.txt  //将2.txt文件的内容覆盖到1.txt

    cat 2.txt >> 1.txt      //将2.txt文件的内容追加到1.txt

    -----------------------------------------------------------

    ubuntu远程访问Linux的终端常用命令

    ssh localhost 判断是否安装远程服务安全协议命令

    sudo apt-get install openssh-server 安装ssh的服务器端命令

    sudo apt-get update 更新软件源命令

    sudo  /etc/init.d/ssh restart 启动ssh-server命令

    sudo passwd root 设置root密码命令

    su root   命令行切换到root命令

    sudo gedit 文件路径 修改文件命令
    2、Linux文件权限 

    https://www.cnblogs.com/0xcafedaddy/p/7132860.html
    3、端口占用 

    netstat -ano,列出所有端口的情况

    netstat -aon | findstr 端口号  占用查看

    taskkill /pid 被占用端口号 /F  解除端口占用
    九、项目经验面试真题 
    1、浏览器访问www.taobao.com,经历了怎样的过程。 

    待定...
    2、高并发情况下,我们系统是如何支撑大量的请求的 

    一、使用消息队列来存放请求;

    二、可以做多机集群,利用负载均衡原理分配每个数据库的职责;

    三、使用Redis缓存,减少对数据库的请求访问,能使用静态页面的地方尽量使用,减少容器的解析(尽量将动态内容生成静态html来显示);
    3、集群如何同步会话状态 

    一般集群都是主从数据库原则,在主方会配置一个授权账号生成的二进制文件,传入的数据都保存到二进制文件上,从方会用根据授权账号信息读取二进制文件进行写操作写到它自己的文件下,
    4、负载均衡的原理 

    会向外暴露虚拟的端口号和ip,在配置文件里会设置一个共享账号来管理集群,并且根据ip分配职责,当有请求的时候会判断什么业务操作,根据业务不同可以分发不同的数据库访问路径,做到读写分离,负载均衡器一般还有备用均衡器防止单点故障;
    5、如果有一个特别大的访问量,到数据库上,怎么做优化(DB设计,DBIO,SQL优化,Java优化) 
    设计缓存,使用memcached、redis,读写分离,数据库优化(优化表结构、索引、查询语句等),使用集群,升级硬件, 
    6、手写斐波那契数列、递归查找文件 
    7、Mybatis的# $的区别 

    #生成sql是双引号拼接的数据,$是直接显示数据

    #可以防止注入,$不能,但在order by中就要使用$
    8、prototype作用域的范围 
    9、Spring的动态代理 

    动态代理模式jdk代理要求代理的类必须有父类接口,它主要通过Proxy和InvocationHandler接口,实现InvocationHandler接口并实现它的invoke方法,该方法传入参数有接口对象和接口方法(通过反射调用方法),然后使用spring的Proxy类创建代理对象时传入两个参数一个是当前调用类的实例,一个是实现InvocationHandler的实例并传入接口
    10、手写生产者消费者模式 

    比如dubbo的提供者和消费者关系
    11、分布式锁 
    12、死锁的原因以及如何避免 

    原因 当多个线程争夺资源造成的,比如买包子,你坚决买完包子再付钱,而老板坚决付完钱再卖,双方都不退让,造成死锁;

    加锁顺序 确保所有的线程都是按照相同的顺序获得锁

    死锁检测(每当一个线程获得了锁,会在线程和锁相关的数据结构中(map、graph等等)将其记下。除此之外,每当有线程请求锁,也需要记录在这个数据结构中)   

    加锁时限(在尝试获取锁的时候加一个超时时间,这就是在尝试获取锁的过程中若超过了这个时限该线程则放弃对该锁请求)
    13、内存溢出的常见原因   java.lang.OutOfMemoryError: ......java heap space.....

    一 堆栈溢出数据得不到释放,访问量比较大比较久,垃圾回收器认为都是可用的数据,不去回收,从而导致内存溢出,溢出之前关键字报错java.lang.OutOfMemoryError:GC over head limit exceeded

    二 PermGen的溢出,可能是第三方包、代码、常量多或者通过动态代码加载等方法,导致常量池的膨胀,常用的手段是:增加-XX:PermSize和-XX:MaxPermSize的大小。

    三 可能是地址空间不够而导致,java.lang.OutOfMemoryError: request {} byte for {}out of swap

    四 无法为线程分配一块内存区域,这个要么是内存本身就不够,要么heap的空间设置得太大了,导致了剩余的内存已不够,线程本身要占用内存 java.lang.OutOfMemoryError: unable to create new native thread

    五 -Xss太小 java.lang.StackOverflowError
    14、秒杀系统的设计

    简单模拟的秒杀场景源码:https://pan.baidu.com/s/1-khb_lB1gtAPcA7Rsam_Wg

    大概思路刚开始的时候是通过页面ajax请求访问到后台调用创建订单方法,先根据id查询出总库存数,销售初始值是0,如果总库存减去销售初始值0小于等于0的不满足就对库存+1,然后更新数据库返回一个result,判断result大于0就有库存调用insert方法,但有个安全问题就是当高并发的时候有可能拿到的是同一个数字去同时调用update方法更新数据库,然后就有些没有得到,为了解决这个问题当时他把悲观锁改变成乐观锁,就是通过版本号判断,当满足还有库存的情况下多个线程访问到同一地方,当第一个线程先调用update方法对version加1库存字段+1,当第二个线程进来时发现版本号改变了就找不到了,这样就保证了每个线程调用不一样的,但乐观锁不能解决高并发带来的问题,最后利用了redis的lpop的特点,当对一个集合存入多个值可以通过lpop把集合里的数据挨个儿弹出,lpop可以用来做抢购码,对redis的api基本操作方法做了封装,直接调用就行了,做那块主要写了两个方法,一个得到抢购码的方法,通过redis工具调用lpop方法弹出一个抢购码返回出去,并且通过前台传入的产品id结合用户存入到lset集合里作为日志,因为我们要查看哪个用户抢到了,还有一个方法就是用于生成抢购码的,它有两个参数一个是要生成多少抢购码随机数count、第二个参数是用户id,创建一个存储抢购码的listcode容器,通过循环count和UUID生成抢购码调用add添加到listcode集合里,在循环外面通过redis工具调用lsetList方法把listcode作为value,把用户id作为key。
    15、100万条记录实现导出 

    https://blog.csdn.net/happyljw/article/details/52809244
    16、字符串的比较、反转 

    使用== 如果地址一样,则返回true,否则false
    使用equals 如果内容一样,则返回true,否则false
    使用compareTo 从开头字母比较,比较各个字符的 Unicode 值,比较结果如果是负数说明第一个数小于第二个,如果是整数说明大于第二个,如果返回的是0说明比较值相等;

    通过StringBuiler的reverse()的方法,最快的方式

    通过String类的charAt()的方法来获取字符串中的每一个字符,然后将其拼接为一个新的字符串
    17、CountDownLatch的应用场景

    CountDownLatch是一个辅助类,能够使一个线程等待其他线程完成各自的工作后再执行,比如跑步比赛,第一名必须等待其它选手到达才统计排名

    CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务

    18、使用Redis遇到的问题,缓存穿透,瞬间并发,缓存雪崩,如何解决的?

    缓存穿透就是多个用户同时去redis请求数据,没有查询到,就要去数据库查询,数据库没有就不做缓存,导致每次请求都要去数据库访问;

    解决:缓存空对象. 将 null 变成一个值

    缓存雪崩就是redis里的数据有效时间同时失效,然后去查询数据库,所有的查询都落在数据库上,造成雪崩

    解决:加锁排队. 限流、缓存永远不过期、做二级缓存,或者双缓存策略

    19、实现SpringMvc拦截器的哪些方式

    有两种写法,一种是实现接口,另外一种是继承适配器类,然后在SpringMvc的配置文件中配置拦截器mvc:interceptors和mvc:interceptor即可

    20、如何解决跨域问题?

    一、动态创建script,script标签不受同源策略的限制

    二、后端转发请求

    三、JSONP的回调函数和数据。回调函数是当响应到来时要放在当前页面被调用的函数。数据就是传入回调函数中的json数据,也就是回调函数的参数了

    21、Redis如何解决掉电数据丢失问题

    rdb设置自动保存数据时间,只要有1个key改变 就保存数据文件

    aop启动redis服务就开始记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集,默认关闭该模式;默认开启的appendonly yes   yes 开启,no 关闭

    22、简单讲一下java的跨平台原理

    Java通过不同的系统、不同版本、不同位数的java虚拟机(jvm),来屏蔽不同的系统指令集差异而对外体统统一的接口(java API),对于我们普通的java开发者而言,只需要按照接口开发即可。如果我系统需要部署到不同的环境时,只需在系统上面按照对应版本的虚拟机即可

    23、简单介绍一下activiti?

    24、简单讲一下struts2的执行流程?

    浏览器发送请求经过一系列的过滤器到达核心过滤器(StrutsPrepareAndExecuteFilter),核心过滤器ActionMapper判断当前请求是否要给某个action处理,如果不处理,走原来流程,如果要处理,则把请求交给Actionproxy处理,Actionproxy会通过ConfigurationManager这个对象去访问struts2.xml配置文件找到要哪个action类来处理,找到后通过创建ActionInvocation实例来调用action的方法,

    展开全文
  • 2020JAVA面试题附答案(持续更新版)

    万次阅读 多人点赞 2020-04-21 23:52:57
    JAVA基础 JAVA中的几种基本类型,各占用多少字节? 下图单位是bit,非字节 1B=8bit String能被继承吗?为什么? 不可以,因为String类有final修饰符,而final修饰的类是不能被继承的,实现细节不允许改变。平常我们...

    前言


    前言:
    少年易老学难成,一寸光阴不可轻。未觉池塘春草梦,阶前梧叶已秋声 。—朱熹《劝学诗》
    勤奋才是改变你命运的唯一捷径。
    整理不易,各位看官点赞再看更舒适,养成好习惯(●´∀`●)


    1.JAVA基础


    1.JAVA中的几种基本类型,各占用多少字节?
    这里写图片描述
    下图单位是bit,非字节 1B=8bit
    在这里插入图片描述
    在这里插入图片描述
    2.String能被继承吗?为什么?
    不可以,因为String类有final修饰符,而final修饰的类是不能被继承的,实现细节不允许改变。平常我们定义的String str=”abc”(直接赋一个字面量);其实和String str=new String(“abc”)(通过构造器构造)还是有差异的。
    在这里插入图片描述

    String str=“abc”和String str=new String(“abc”); 产生几个对象?
        1.前者1或0,后者2或1,先看字符串常量池,如果字符串常量池中没有,都在常量池中创建一个,如果有,前者直接引用,后者在堆内存中还需创建一个“abc”实例对象。
    	2.对于基础类型的变量和常量:变量和引用存储在栈中,常量存储在常量池中。
    	3.为了提升jvm(JAVA虚拟机)性能和减少内存开销,避免字符的重复创建 项目中还是不要使用new String去创建字符串,最好使用String直接赋值。
    

    参考链接
    3.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);
    }
    

    4.ArrayList 和 LinkedList 有什么区别。
    ArrayList和LinkedList都实现了List接口,有以下的不同点:
    1、ArrayList是基于索引的数据接口,它的底层是数组。它可以以O(1)时间复杂度对元素进行随机访问。与此对应,LinkedList是以元素列表的形式存储它的数据,每一个元素都和它的前一个和后一个元素链接在一起,在这种情况下,查找某个元素的时间复杂度是O(n)。
    2、相对于ArrayList,LinkedList的插入,添加,删除操作速度更快,因为当元素被添加到集合任意位置的时候,不需要像数组那样重新计算大小或者是更新索引。
    3、LinkedList比ArrayList更占内存,因为LinkedList为每一个节点存储了两个引用,一个指向前一个元素,一个指向下一个元素。
    5.讲讲类的实例化顺序,比如父类静态数据,构造函数,字段,子类静态数据,构造函数,字段,当 new 的时候, 他们的执行顺序。
    此题考察的是类加载器实例化时进行的操作步骤(加载–>连接->初始化)。
    父类静态代变量、
    父类静态代码块、
    子类静态变量、
    子类静态代码块、
    父类非静态变量(父类实例成员变量)、
    父类构造函数、
    子类非静态变量(子类实例成员变量)、
    子类构造函数。
    测试demo
    参阅博客《深入理解类加载》
    6.用过哪些 Map 类,都有什么区别,HashMap 是线程安全的吗,并发下使用的 Map 是什么,他们内部原理分别是什么,比如存储方式, hashcode,扩容, 默认容量等。
    hashMap是线程不安全的,HashMap是数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的,采用哈希表来存储的,
    参考链接
    JAVA8 的 ConcurrentHashMap 为什么放弃了分段锁,有什么问题吗,如果你来设计,你如何设计。
    参考链接
    7.有没有有顺序的 Map 实现类, 如果有, 他们是怎么保证有序的。
    TreeMap和LinkedHashMap是有序的(TreeMap默认升序,LinkedHashMap则记录了插入顺序)。
    参考链接
    8.抽象类和接口的区别,类可以继承多个类么,接口可以继承多个接口么,类可以实现多个接口么。
    1、抽象类和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象。
    2、抽象类要被子类继承,接口要被类实现。
    3、接口只能做方法申明,抽象类中可以做方法申明,也可以做方法实现
    4、接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。
    5、抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,一个实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类。
    6、抽象方法只能申明,不能实现。abstract void abc();不能写成abstract void abc(){}。
    7、抽象类里可以没有抽象方法
    8、如果一个类里有抽象方法,那么这个类只能是抽象类
    9、抽象方法要被实现,所以不能是静态的,也不能是私有的。
    10、接口可继承接口,并可多继承接口,但类只能单根继承。
    9.继承和聚合的区别在哪。
    继承指的是一个类(称为子类、子接口)继承另外的一个类(称为父类、父接口)的功能,并可以增加它自己的新功能的能力,继承是类与类或者接口与接口之间最常见的关系;在Java中此类关系通过关键字extends明确标识,在设计时一般没有争议性;
    这里写图片描述
    聚合是关联关系的一种特例,他体现的是整体与部分、拥有的关系,即has-a的关系,此时整体与部分之间是可分离的,他们可以具有各自的生命周期,部分可以属于多个整体对象,也可以为多个整体对象共享;比如计算机与CPU、公司与员工的关系等;表现在代码层面,和关联关系是一致的,只能从语义级别来区分;
    这里写图片描述
    参考链接
    10.讲讲你理解的 nio和 bio 的区别是啥,谈谈 reactor 模型。
    IO(BIO)是面向流的,NIO是面向缓冲区的
    BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。
    NIO:New IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。
    AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制。
    参考链接1
    参考链接2
    11.反射的原理,反射创建类实例的三种方式是什么
    参考链接1
    参考链接2
    12.反射中,Class.forName 和 ClassLoader 区别。
    参考链接
    13.描述动态代理的几种实现方式,分别说出相应的优缺点。
    Jdk cglib jdk底层是利用反射机制,需要基于接口方式,这是由于

    Proxy.newProxyInstance(target.getClass().getClassLoader(),
    target.getClass().getInterfaces(), this);
    

    Cglib则是基于asm框架,实现了无反射机制进行代理,利用空间来换取了时间,代理效率高于jdk
    参考链接
    动态代理与 cglib 实现的区别
    同上(基于invocationHandler和methodInterceptor)
    14.为什么 CGlib 方式可以对接口实现代理。
    同上
    15.final 的用途
    类、变量、方法
    final 修饰的类叫最终类,该类不能被继承。
    final 修饰的方法不能被重写。
    final 修饰的变量叫常量,常量必须初始化,初始化之后值就不能被修改。
    参考链接
    16.写出三种单例模式实现。
    懒汉式单例,饿汉式单例,双重检查等
    参考链接
    17.如何在父类中为子类自动完成所有的 hashcode 和 equals 实现?这么做有何优劣。
    同时复写hashcode和equals方法,优势可以添加自定义逻辑,且不必调用超类的实现。
    参考链接
    18.请结合 OO 设计理念,谈谈访问修饰符 public、private、protected、default 在应用设计中的作用。
    访问修饰符,主要标示修饰块的作用域,方便隔离防护

    类中的数据成员和成员函数据具有的访问权限包括:publicprivate、protect、default(包访问权限)
    作用域		当前类	同一package	子孙类	其他package 
    public   	√    	√         	√       √ 
    protected   √      	√           √       × 
    default     √       √           ×       × 
    private     √       ×           ×       × 
    
    public           所有类可见
    protected      	 本包和所有子类都可见(本包中的子类非子类均可访问,不同包中的子类可以访问,不是子类不能访问)
    default          本包可见(即默认的形式)(本包中的子类非子类均可访问,不同包中的类及子类均不能访问)
    priavte          本类可见
    

    public: Java语言中访问限制最宽的修饰符,一般称之为“公共的”。被其修饰的类、属性以及方法不仅可以跨类访问,而且允许跨包(package)访问。
    private: Java语言中对访问权限限制的最窄的修饰符,一般称之为“私有的”。被其修饰的类、属性以及方法只能被该类的对象访问,其子类不能访问,更不能允许跨包访问。
    protect: 介于public 和 private 之间的一种访问修饰符,一般称之为“保护形”。被其修饰的类、属性以及方法只能被类本身的方法及子类访问,即使子类在不同的包中也可以访问。
    default:即不加任何访问修饰符,通常称为"默认访问模式"。该模式下,只允许在同一个包中进行访问。
    19.深拷贝和浅拷贝区别。
    参考链接
    20.数组和链表数据结构描述,各自的时间复杂度
    参考链接
    21.error 和 exception 的区别,CheckedException,RuntimeException 的区别
    参考链接
    22.请列出 5 个运行时异常。
    同上
    23.在自己的代码中,如果创建一个 java.lang.String 对象,这个对象是否可以被类加载器加载?为什么
    类加载无须等到“首次使用该类”时加载,jvm允许预加载某些类。。。。
    参考链接
    24.说一说你对 java.lang.Object 对象中 hashCode 和 equals 方法的理解。在什么场景下需要重新实现这两个方法。
    参考上边试题(17)
    25.在 jdk1.5 中,引入了泛型,泛型的存在是用来解决什么问题。
    泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数,泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,以提高代码的重用率
    参考链接
    26.这样的 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相等。
    参考链接
    27.有没有可能 2 个不相等的对象有相同的 hashcode。

    实例:

    String str1 = "通话";
    String str2 = "重地";
    System.out.println(String.format("str1:%d | str2:%d",  str1.hashCode(),str2.hashCode()));
    System.out.println(str1.equals(str2));
    
    执行结果:str1:1179395 | str2:1179395
    false
    

    28.Java 中的 HashSet 内部是如何工作的。
    底层是基于hashmap实现的
    参考链接
    什么是序列化,怎么序列化,为什么序列化,反序列化会遇到什么问题,如何解决。
    参考链接
    29. JDK 和 JRE 有什么区别?
    JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境。
    JRE:Java Runtime Environment 的简称,java 运行环境,为 java 的运行提供了所需环境。
    具体来说 JDK 其实包含了 JRE,同时还包含了编译 java 源码的编译器 javac,还包含了很多 java 程序调试和分析的工具。简单来说:如果你需要运行 java 程序,只需安装 JRE 就可以了,如果你需要编写 java 程序,需要安装 JDK。
    30. == 和 equals 的区别是什么?
    == 解读:
    对于基本类型和引用类型 == 的作用效果是不同的,如下所示:
    基本类型:比较的是值是否相同;
    引用类型:比较的是引用是否相同;
    实例:

            String x = "string";
            String y = "string";
            String z = new String("string");
            System.out.println(x==y); // true,引用相同
            System.out.println(x==z); // false,==:string比较引用,开辟了新的堆内存空间,所以false
            System.out.println(x.equals(y)); // true,equals:string:比较值,相同
            System.out.println(x.equals(z)); // true,equals:string比较值,相同
    

    equals 解读:
    equals 本质上就是 ==,只不过 String 和 Integer 等重写了 equals 方法,把它变成了值比较。看下面的代码就明白了。
    首先来看默认情况下 equals 比较一个(有相同值的对象),代码如下:

    public class Cat {
        private  String name;
    	public Cat(String name){
            this.name = name;
        }
    	public String getName() {
            return name;
        }
    	public void setName(String name) {
            this.name = name;
        }
    	public static void main(String[] args) {
    		Cat c1 = new Cat("cat1");//c1是Cat的实例化对象,c2同理
            Cat c2 = new Cat("cat2");
           	String s1 = new String("隔壁老王");
            String s2 = new String("隔壁老王");
    		System.out.println(c1.equals(c2));//false,equals在比较的类对象的时候比较的是引用
    		System.out.println(s1.equals(s2)); //true,而在比较string的时候,因为重写了equals方法,和基本数据类型一样,比较的是值,所以为true
    
    }
    

    总结 :== 对于基本类型来说是值比较(不难理解,八种基本数据类型是可以有确定值的),对于引用类型来说是比较的是引用(数组、类、接口没有确定值);而 equals 默认情况下是引用比较,只是很多类重新了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。
    31.java 中的 Math.round(-1.5) 等于多少?
    等于 -1,因为在数轴上取值时,中间值(0.5)向右取整,所以正 0.5 是往上取整,负 0.5 是直接舍弃。同理,Math.round(1.5) = 2
    32.写一个字符串反转函数。

    // StringBuffer reverse
    StringBuffer stringBuffer = new StringBuffer();
    stringBuffer.append("abcdefg");
    System.out.println(stringBuffer.reverse()); // gfedcba
    // StringBuilder reverse
    StringBuilder stringBuilder = new StringBuilder();
    stringBuilder.append("abcdefg");
    System.out.println(stringBuilder.reverse()); // gfedcba
    

    33.String 类的常用方法都有那些?
    indexOf():返回指定字符的索引。
    charAt():返回指定索引处的字符。
    replace():字符串替换。
    trim():去除字符串两端空白。
    split():分割字符串,返回一个分割后的字符串数组。
    getBytes():返回字符串的 byte 类型数组。
    length():返回字符串长度。
    toLowerCase():将字符串转成小写字母。
    toUpperCase():将字符串转成大写字符。
    substring():截取字符串。
    equals():字符串比较。
    34.抽象类必须要有抽象方法吗?
    不需要,抽象类不一定非要有抽象方法。
    示例代码:

    public abstract class noAbstractMethod{
            public static void main(String[] args) {
                sayHi();
            }
            public static void sayHi() {
                System.out.println("hi~");
            }
    }
            结果:hi~
    

    35.java 中 IO 流分为几种?
    按功能来分:输入流(input)、输出流(output)。

    按类型来分:字节流和字符流。

    字节流和字符流的区别是:字节流按 8 位传输以字节为单位输入输出数据,字符流按 16 位传输以字符为单位输入输出数据。
    36.Files的常用方法都有哪些?
    Files.exists():检测文件路径是否存在。
    Files.createFile():创建文件。
    Files.createDirectory():创建文件夹。
    Files.delete():删除一个文件或目录。
    Files.copy():复制文件。
    Files.move():移动文件。
    Files.size():查看文件个数。
    Files.read():读取文件。
    Files.write():写入文件。
    37.List、Set、Map 之间的区别是什么?
    在这里插入图片描述
    38.如何实现数组和 List 之间的转换?
    List转换成为数组:调用ArrayList的toArray方法。
    数组转换成为List:调用Arrays的asList方法。
    39. ArrayList 和 Vector 的区别是什么?
    Vector是同步的,而ArrayList不是。然而,如果你寻求在迭代的时候对列表进行改变,你应该使用CopyOnWriteArrayList。
    ArrayList比Vector快,它是异步,不会过载。
    ArrayList更加通用,因为我们可以使用Collections工具类轻易地获取同步列表和只读列表。
    40.Array 和 ArrayList 有何区别?
    Array可以容纳基本类型和对象,而ArrayList只能容纳对象。
    Array是指定大小的,而ArrayList初始大小是固定的。
    Array没有提供ArrayList那么多功能,比如addAll、removeAll和iterator等。
    41.在 Queue 中 poll()和 remove()有什么区别?
    poll() 和 remove() 都是从队列中取出一个元素,但是 poll() 在获取元素失败的时候会返回空,但是 remove() 失败的时候会抛出异常。
    42. 哪些集合类是线程安全的?
    vector:就比arraylist多了个同步化机制(线程安全),因为效率较低,现在已经不太建议使用。在web应用中,特别是前台页面,往往效率(页面响应速度)是优先考虑的。
    statck:堆栈类,先进后出。
    hashtable:就比hashmap多了个线程安全。
    enumeration:枚举,相当于迭代器。
    43.迭代器 Iterator 是什么?
    迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。
    44.Iterator 怎么使用?有什么特点?
    Java中的Iterator功能比较简单,并且只能单向移动:

    (1) 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。注意:iterator()方法是java.lang.Iterable接口,公共基类Collection提供iterator()方法。

    (2) 使用next()获得序列中的下一个元素。

    (3) 使用hasNext()检查序列中是否还有元素。

    (4) 使用remove()将迭代器新返回的元素删除。

    Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素。
    45. Iterator 和 ListIterator 有什么区别?
    Iterator可用来遍历Set和List集合,但是ListIterator只能用来遍历List,见名知意,Set并不能使用ListIterator
    Iterator对集合只能是前向遍历,ListIterator既可以前向也可以后向。
    ListIterator实现了Iterator接口,并包含其他的功能,比如:增加元素,替换元素,获取前一个和后一个元素的索引,等等。
    46.synchronized 和 volatile 的区别是什么?
    volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
    volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的。
    volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性。
    volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
    volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化。
    47.给定一个文本,获取某字符串出现的次数

        public static void count(){
    
            File file = new File("C:\\Users\\Administrator\\Desktop\\行政区划配置表.txt");
            InputStream is = null;
            try {
                is = new FileInputStream(file);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            byte[] b = new byte[1024];
            int a = 0;
            try {
                a = is.read(b);
            } catch (IOException e) {
                e.printStackTrace();
            }
            String[] str = new String(b, 0, a).split("");
            int count = 0;
            for(int i = 0;i<str.length;i++){
                //设置查询统计的字符串为a
                if("a".equals(str[i])){
                    count++;
                }
            }
            System.out.println(count);
        }
    

    2.JVM 知识


    1.什么情况下会发生栈内存溢出。
    如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常。 如果虚拟机在动态扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。
    参考链接
    2.JVM 的内存结构,Eden 和 Survivor 比例。
    这里写图片描述
    eden 和 survior 是按8比1分配的
    参考链接
    3.jvm 中一次完整的 GC 流程是怎样的,对象如何晋升到老年代,说说你知道的几种主要的jvm 参数。
    对象诞生即新生代->eden,在进行minor gc过程中,如果依旧存活,移动到from,变成Survivor,进行标记代数,如此检查一定次数后,晋升为老年代,
    参考链接1
    参考链接2
    参考链接3
    4.你知道哪几种垃圾收集器,各自的优缺点,重点讲下 cms,包括原理,流程,优缺点
    Serial、parNew、ParallelScavenge、SerialOld、ParallelOld、CMS、G1
    参考链接
    5.垃圾回收算法的实现原理。
    参考链接
    6.当出现了内存溢出,你怎么排错。
    首先分析是什么类型的内存溢出,对应的调整参数或者优化代码。
    参考链接
    7.JVM 内存模型的相关知识了解多少,比如重排序,内存屏障,happen-before,主内存,工作内存等。
    内存屏障:为了保障执行顺序和可见性的一条cpu指令
    重排序:为了提高性能,编译器和处理器会对执行进行重拍
    happen-before:操作间执行的顺序关系。有些操作先发生。
    主内存:共享变量存储的区域即是主内存
    工作内存:每个线程copy的本地内存,存储了该线程以读/写共享变量的副本
    参考链接1
    参考链接2
    参考链接3
    8.简单说说你了解的类加载器。
    类加载器的分类(bootstrap,ext,app,curstom),类加载的流程(load-link-init)
    参考链接
    9.讲讲 JAVA 的反射机制。
    Java程序在运行状态可以动态的获取类的所有属性和方法,并实例化该类,调用方法的功能
    参考链接
    10.你们线上应用的 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
    11.g1 和 cms 区别,吞吐量优先和响应优先的垃圾收集器选择。
    Cms是以获取最短回收停顿时间为目标的收集器。基于标记-清除算法实现。比较占用cpu资源,切易造成碎片。
    G1是面向服务端的垃圾收集器,是jdk9默认的收集器,基于标记-整理算法实现。可利用多核、多cpu,保留分代,实现可预测停顿,可控。
    参考链接
    请解释如下 jvm 参数的含义:
    -server -Xms512m -Xmx512m -Xss1024K
    -XX:PermSize=256m -XX:MaxPermSize=512m -XX:MaxTenuringThreshold=20
    XX:CMSInitiatingOccupancyFraction=80 -XX:+UseCMSInitiatingOccupancyOnly。
    Server模式启动
    最小堆内存512m
    最大512m
    每个线程栈空间1m
    永久代256m
    最大永久代512m
    最大转为老年代检查次数20
    Cms回收开启时机:内存占用80%
    命令JVM不基于运行时收集的数据来启动CMS垃圾收集周期
    12.32位系统jvm堆内存如下哪一个设置是最大且有效的( B )
    A. -Xmx1000m
    B. -Xmx1500m
    C. -Xmx8G
    D. 无限
    JVM最大内存: 首先JVM内存限制于实际的最大物理内存,假设物理内存无限大的话,JVM内存的最大值跟操作系统有很大的关系。简单的说就32位处理器虽然可控内存空间有4GB,但是具体的操作系统会给一个限制,这个限制一般是2GB-3GB(一般来说Windows系统下为1.5G-2G,Linux系统下为2G-3G),而64bit以上的处理器就不会有限制了。


    3.开源框架知识


    1.简单讲讲 tomcat 结构,以及其类加载器流程。
    Server- --多个service
    Container级别的:–>engine–》host–>context
    Listenter
    Connector
    Logging、Naming、Session、JMX等等
    这里写图片描述
    通过WebappClassLoader 加载class
    参考链接1
    参考链接2
    参考链接3
    参考链接4
    2.tomcat 如何调优,涉及哪些参数。
    硬件上选择,操作系统选择,版本选择,jdk选择,配置jvm参数,配置connector的线程数量,开启gzip压缩,trimSpaces,集群等
    a) 内存优化:主要是对Tomcat启动参数进行优化,我们可以在Tomcat启动脚本中修改它的最大内存数等等。

    b) 线程数优化:Tomcat的并发连接参数,主要在Tomcat配置文件中server.xml中配置,比如修改最小空闲连接线程数,用于提高系统处理性能等等。

    c) 优化缓存:打开压缩功能,修改参数,比如压缩的输出内容大小默认为2KB,可以适当的修改。
    参考链接
    3.讲讲 Spring 加载流程。
    通过listener入口,核心是在AbstractApplicationContext的refresh方法,在此处进行装载bean工厂,bean,创建bean实例,拦截器,后置处理器等。
    参考链接
    4.讲讲 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。
    参考链接
    5.Spring 如何管理事务的。
    编程式和声明式
    同上
    6.Spring 怎么配置事务(具体说出一些关键的 xml 元素)。
    配置事务的方法有两种:
    1)、基于XML的事务配置。

    <?xml version="1.0" encoding="UTF-8"?>
    <!-- from the file 'context.xml' -->  
    <beans xmlns="http://www.springframework.org/schema/beans"  
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
         xmlns:aop="http://www.springframework.org/schema/aop"  
         xmlns:tx="http://www.springframework.org/schema/tx"  
         xsi:schemaLocation="  
         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
         http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd  
         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">  
          
      <!-- 数据元信息 -->  
      <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">  
        <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>  
        <property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/>  
        <property name="username" value="root"/>  
        <property name="password" value="root"/>  
      </bean>  
      
      <!-- 管理事务的类,指定我们用谁来管理我们的事务-->  
      <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
        <property name="dataSource" ref="dataSource"/>  
      </bean>   
      
      <!-- 首先我们要把服务对象声明成一个bean  例如HelloService -->  
      <bean id="helloService" class="com.yintong.service.HelloService"/>  
      
      <!-- 然后是声明一个事物建议tx:advice,spring为我们提供了事物的封装,这个就是封装在了<tx:advice/>-->
      <!-- <tx:advice/>有一个transaction-manager属性,我们可以用它来指定我们的事物由谁来管理。
          默认:事务传播设置是 REQUIRED,隔离级别是DEFAULT -->
      <tx:advice id="txAdvice" transaction-manager="txManager">  
          <!-- 配置这个事务建议的属性 -->  
          <tx:attributes>  
            <!-- 指定所有get开头的方法执行在只读事务上下文中 -->  
            <tx:method name="get*" read-only="true"/>  
            <!-- 其余方法执行在默认的读写上下文中 -->  
            <tx:method name="*"/>  
          </tx:attributes>  
      </tx:advice>  
        
      <!-- 我们定义一个切面,它匹配FooService接口定义的所有操作 -->  
      <aop:config>  
         <!-- <aop:pointcut/>元素定义AspectJ的切面表示法,这里是表示com.yintong.service.helloService包下的任意方法。 -->
         <aop:pointcut id="helloServiceOperation" expression="execution(* com.yintong.service.helloService.*(..))"/>  
         <!-- 然后我们用一个通知器:<aop:advisor/>把这个切面和tx:advice绑定在一起,表示当这个切面:fooServiceOperation执行时tx:advice定义的通知逻辑将被执行 -->
         <aop:advisor advice-ref="txAdvice" pointcut-ref="helloServiceOperation"/>  
      </aop:config>  
     
    </beans>  
    

    2)、基于注解方式的事务配置。
    @Transactional:直接在Java源代码中声明事务的做法让事务声明和将受其影响的代码距离更近了,而且一般来说不会有不恰当的耦合的风险,因为,使用事务性的代码几乎总是被部署在事务环境中。

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"  
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
         xmlns:aop="http://www.springframework.org/schema/aop"  
         xmlns:tx="http://www.springframework.org/schema/tx"  
         xsi:schemaLocation="  
         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
         http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd  
         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">  
        
      <bean id="helloService" class="com.yintong.service.HelloService"/>  
      <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
         <property name="dataSource" ref="dataSource"/>  
      </bean>
      <!-- 配置注解事务 -->  
      <tx:annotation-driven transaction-manager="txManager"/>  
    </beans>
    

    参考链接
    7.说说你对 Spring 的理解,非单例注入的原理?它的生命周期?循环注入的原理, aop 的实现原理,说说 aop 中的几个术语,它们是怎么相互工作的。
    AOP与IOC的概念(即spring的核心)

    a) IOC:Spring是开源框架,使用框架可以使我们减少工作量,提高工作效率并且它是分层结构,即相对应的层处理对应的业务逻辑,减少代码的耦合度。而spring的核心是IOC控制反转和AOP面向切面编程。IOC控制反转主要强调的是程序之间的关系是由容器控制的,容器控制对象,控制了对外部资源的获取。而反转即为,在传统的编程中都是由我们创建对象获取依赖对象,而在IOC中是容器帮我们创建对象并注入依赖对象,正是容器帮我们查找和注入对象,对象是被获取,所以叫反转。

    b) AOP:面向切面编程,主要是管理系统层的业务,比如日志,权限,事物等。AOP是将封装好的对象剖开,找出其中对多个对象产生影响的公共行为,并将其封装为一个可重用的模块,这个模块被命名为切面(aspect),切面将那些与业务逻辑无关,却被业务模块共同调用的逻辑提取并封装起来,减少了系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。

    核心组件:bean,context,core,单例注入是通过单例beanFactory进行创建,生命周期是在创建的时候通过接口实现开启,循环注入是通过后置处理器,aop其实就是通过反射进行动态代理,pointcut,advice等。
    Aop相关:
    参考链接
    8.Springmvc 中 DispatcherServlet 初始化过程。
    入口是web.xml中配置的ds,ds继承了HttpServletBean,FrameworkServlet,通过其中的init方法进行初始化装载bean和实例,initServletBean是实际完成上下文工作和bean初始化的方法。
    参考链接
    9.springMVC的执行流程
    springMVC是由dispatchservlet为核心的分层控制框架。首先客户端发出一个请求web服务器解析请求url并去匹配dispatchservlet的映射url,如果匹配上就将这个请求放入到dispatchservlet,dispatchservlet根据mapping映射配置去寻找相对应的handel,然后把处理权交给找到的handel,handel封装了处理业务逻辑的代码,当handel处理完后会返回一个逻辑视图modelandview给dispatchservlet,此时的modelandview是一个逻辑视图不是一个正式视图,所以dispatchservlet会通过viewresource视图资源去解析modelandview,然后将解析后的参数放到view中返回到客户端并展现。
    10.事物的理解

    a) 事物具有原子性,一致性,持久性,隔离性
    b) 原子性:是指在一个事物中,要么全部执行成功,要么全部失败回滚。
    c) 一致性:事物执行之前和执行之后都处于一致性状态
    d) 持久性:事物多数据的操作是永久性
    e) 隔离性:当一个事物正在对数据进行操作时,另一个事物不可以对数据进行操作,也就是多个并发事物之间相互隔离。
    

    4.操作系统


    1.Linux 系统下你关注过哪些内核参数,说说你知道的。
    这里写图片描述
    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
    参考链接
    2.Linux 下 IO 模型有几种,各自的含义是什么。
    阻塞式io,非阻塞io,io复用模型,信号驱动io模型,异步io模型。
    参考链接1
    参考链接2
    3.epoll 和 poll 有什么区别。
    select的本质是采用32个整数的32位,即32* 32= 1024来标识,fd值为1-1024。当fd的值超过1024限制时,就必须修改FD_SETSIZE的大小。这个时候就可以标识32* max值范围的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较多还是一个串行的操作
    参考链接
    4.平时用到哪些 Linux 命令。
    Ls,find,tar,tail,cp,rm,vi,grep,ps,pkill等等
    参考链接
    5.用一行命令查看文件的最后五行。
    Tail -n 5 filename
    6.用一行命令输出正在运行的 java 进程。
    ps -ef|grep Java
    7.介绍下你理解的操作系统中线程切换过程。
    控制权的转换,根据优先级切换上下文(用户,寄存器,系统)
    参考链接
    8.进程和线程的区别。
    Linux 实现并没有区分这两个概念(进程和线程)
    进程:程序的一次执行
    线程:CPU的基本调度单位
    一个进程可以包含多个线程。
    参考链接

    5.多线程

    1.多线程的几种实现方式,什么是线程安全。
    实现runable接口,继承thread类。
    参考链接
    2.volatile 的原理,作用,能代替锁么。
    Volatile利用内存栅栏机制来保持变量的一致性。不能代替锁,其只具备数据可见性一致性,不具备原子性。
    参考链接
    3.画一个线程的生命周期状态图。
    新建,可运行,运行中,睡眠,阻塞,等待,死亡。
    这里写图片描述
    参考链接
    4.sleep 和 wait 的区别。
    Sleep是休眠线程,wait是等待,sleep是thread的静态方法,wait则是object的方法。
    Sleep依旧持有锁,并在指定时间自动唤醒。wait则释放锁。
    参考链接
    5.Lock 与 Synchronized 的区别。
    首先两者都保持了并发场景下的原子性和可见性,区别则是synchronized的释放锁机制是交由其自身控制,且互斥性在某些场景下不符合逻辑,无法进行干预,不可人为中断等。
    而lock常用的则有ReentrantLock和readwritelock两者,添加了类似锁投票、定时锁等候和可中断锁等候的一些特性。此外,它还提供了在激烈争用情况下更佳的性能。
    参考链接
    6.synchronized 的原理是什么,解释以下名词:重排序,自旋锁,偏向锁,轻量级锁,可重入锁,公平锁,非公平锁,乐观锁,悲观锁。
    Synchronized底层是通过监视器的enter和exit实现
    参考链接1
    参考链接2
    7.用过哪些原子类,他们的原理是什么。
    AtomicInteger; AtomicLong; AtomicReference; AtomicBoolean;基于CAS原语实现 ,比较并交换、加载链接/条件存储,最坏的情况下是旋转锁
    参考链接1
    参考链接2
    8.用过线程池吗,newCache 和 newFixed 有什么区别,他们的原理简单概括下,构造函数的各个参数的含义是什么,比如 coreSize,maxsize 等。
    newSingleThreadExecutor返回以个包含单线程的Executor,将多个任务交给此Exector时,这个线程处理完一个任务后接着处理下一个任务,若该线程出现异常,将会有一个新的线程来替代。
    newFixedThreadPool返回一个包含指定数目线程的线程池,如果任务数量多于线程数目,那么没有没有执行的任务必须等待,直到有任务完成为止。
    newCachedThreadPool根据用户的任务数创建相应的线程来处理,该线程池不会对线程数目加以限制,完全依赖于JVM能创建线程的数量,可能引起内存不足。
    底层是基于ThreadPoolExecutor实现,借助reentrantlock保证并发。
    coreSize核心线程数,maxsize最大线程数。
    参考链接
    9.线程池的关闭方式有几种,各自的区别是什么。
    Shutdown shutdownNow tryTerminate 清空工作队列,终止线程池中各个线程,销毁线程池
    参考链接
    10.假如有一个第三方接口,有很多个线程去调用获取数据,现在规定每秒钟最多有 10 个线程同时调用它,如何做到。
    ScheduledThreadPoolExecutor 设置定时,进行调度。

    public ScheduledThreadPoolExecutor(int corePoolSize,
    ThreadFactory threadFactory) {
    	super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
    	new DelayedWorkQueue(), threadFactory);
    }
    

    参考链接
    11.spring 的 controller 是单例还是多例,怎么保证并发的安全。
    单例
    通过单例工厂 DefaultSingletonBeanRegistry实现单例
    通过AsyncTaskExecutor保持安全
    12.用三个线程按顺序循环打印 abc 三个字母,比如 abcabcabc。

    public class ABC_Synch {
        public static class ThreadPrinter implements Runnable {
            private String name;
            private Object prev;
            private Object self;
            private ThreadPrinter(String name, Object prev, Object self) {
                this.name = name;
                this.prev = prev;
                this.self = self;
            }
            @Override
            public void run() {
                int count = 10;
                while (count > 0) {// 多线程并发,不能用if,必须使用whil循环
                    synchronized (prev) { // 先获取 prev 锁
                        synchronized (self) {// 再获取 self 锁
                            System.out.print(name);//打印
                            count--;
    
                            self.notifyAll();// 唤醒其他线程竞争self锁,注意此时self锁并未立即释放。
                        }
                        //此时执行完self的同步块,这时self锁才释放。
                        try {
                            prev.wait(); // 立即释放 prev锁,当前线程休眠,等待唤醒
                            /**
                             * JVM会在wait()对象锁的线程中随机选取一线程,赋予其对象锁,唤醒线程,继续执行。
                             */
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        public static void main(String[] args) throws Exception {
            Object a = new Object();
            Object b = new Object();
            Object c = new Object();
            ThreadPrinter pa = new ThreadPrinter("A", c, a);
            ThreadPrinter pb = new ThreadPrinter("B", a, b);
            ThreadPrinter pc = new ThreadPrinter("C", b, c);
    
            new Thread(pa).start();
            Thread.sleep(10);//保证初始ABC的启动顺序
            new Thread(pb).start();
            Thread.sleep(10);
            new Thread(pc).start();
            Thread.sleep(10);
        }
    }
    
    

    参考链接
    13.ThreadLocal 用过么,用途是什么,原理是什么,用的时候要注意什么。
    Threadlocal底层是通过threadlocalMap进行存储键值 每个ThreadLocal类创建一个Map,然后用线程的ID作为Map的key,实例对象作为Map的value,这样就能达到各个线程的值隔离的效果。
    ThreadLocal的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或者组件之间一些公共变量的传递的复杂度。
    谁设置谁负责移除
    参考链接1
    参考链接2
    14.如果让你实现一个并发安全的链表,你会怎么做。
    Collections.synchronizedList() ConcurrentLinkedQueue
    参考链接
    15.有哪些无锁数据结构,他们实现的原理是什么。
    LockFree,CAS
    基于jdk提供的原子类原语实现,例如AtomicReference
    参考链接
    16.讲讲 java 同步机制的 wait 和 notify。
    首先这两个方法只能在同步代码块中调用,wait会释放掉对象锁,等待notify唤醒。
    参考链接
    17.多线程如果线程挂住了怎么办。
    根据具体情况(sleep,wait,join等),酌情选择notifyAll,notify进行线程唤醒。
    参考链接
    18.countdowlatch 和 cyclicbarrier 的内部原理和用法,以及相互之间的差别。
    CountDownLatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它运行一个或者多个线程一直处于等待状态。
    CyclicBarrier要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行。
    CyclicBarrier初始化的时候,设置一个屏障数。线程调用await()方法的时候,这个线程就会被阻塞,当调用await()的线程数量到达屏障数的时候,主线程就会取消所有被阻塞线程的状态。
    前者是递减,不可循环,后者是递加,可循环用
    countdowlatch 基于abq cb基于ReentrantLock Condition
    参考链接1
    参考链接2
    19.使用 synchronized 修饰静态方法和非静态方法有什么区别。
    对象锁和类锁
    参考链接
    20.简述 ConcurrentLinkedQueue LinkedBlockingQueue 的用处和不同之处。
    LinkedBlockingQueue 是一个基于单向链表的、范围任意的(其实是有界的)、FIFO 阻塞队列。
    ConcurrentLinkedQueue是一个基于链接节点的无界线程安全队列,它采用先进先出的规则对节点进行排序,当我们添加一个元素的时候,它会添加到队列的尾部,当我们获取一个元素时,它会返回队列头部的元素。它采用了“wait-free”算法来实现,该算法在Michael & Scott算法上进行了一些修改, Michael & Scott算法的详细信息可以参见参考资料一。
    参考链接1
    参考链接2
    参考链接3
    ##导致线程死锁的原因?怎么解除线程死锁。
    死锁问题是多线程特有的问题,它可以被认为是线程间切换消耗系统性能的一种极端情况。在死锁时,线程间相互等待资源,而又不释放自身的资源,导致无穷无尽的等待,其结果是系统任务永远无法执行完成。死锁问题是在多线程开发中应该坚决避免和杜绝的问题。
    一般来说,要出现死锁问题需要满足以下条件:

    互斥条件:一个资源每次只能被一个线程使用。
    请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
    不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺。
    循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
    只要破坏死锁 4 个必要条件之一中的任何一个,死锁问题就能被解决。
    

    参考链接
    21.非常多个线程(可能是不同机器),相互之间需要等待协调,才能完成某种工作,问怎么设计这种协调方案。
    此问题的本质是保持顺序执行。可以使用executors
    #TCP 与 HTTP
    22.http1.0 和 http1.1 有什么区别。
    HTTP 1.0主要有以下几点变化:
    请求和相应可以由于多行首部字段构成
    响应对象前面添加了一个响应状态行
    响应对象不局限于超文本
    服务器与客户端之间的连接在每次请求之后都会关闭
    实现了Expires等传输内容的缓存控制
    内容编码Accept-Encoding、字符集Accept-Charset等协商内容的支持
    这时候开始有了请求及返回首部的概念,开始传输不限于文本(其他二进制内容)
    HTTP 1.1加入了很多重要的性能优化:持久连接、分块编码传输、字节范围请求、增强的缓存机制、传输编码及请求管道。
    参考链接
    23.TCP 三次握手和四次挥手的流程,为什么断开连接要 4 次,如果握手只有两次,会出现什么。

    第一次握手(SYN=1, seq=x):
    客户端发送一个 TCP 的 SYN 标志位置1的包,指明客户端打算连接的服务器的端口,以及初始序号 X,保存在包头的序列号(Sequence Number)字段里。
    发送完毕后,客户端进入 <code>SYN_SEND</code> 状态。
    
    第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1):
    服务器发回确认包(ACK)应答。即 SYN 标志位和 ACK 标志位均为1。服务器端选择自己 ISN 序列号,放到 Seq 域里,同时将确认序号(Acknowledgement Number)设置为客户的 ISN 加1,即X+1。
    发送完毕后,服务器端进入 <code>SYN_RCVD</code> 状态。
    
    第三次握手(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 状态。
    两次后会重传直到超时。如果多了会有大量半链接阻塞队列。
    参考链接1
    参考链接2
    24.TIME_WAIT 和 CLOSE_WAIT 的区别。
    TIME_WAIT状态就是用来重发可能丢失的ACK报文。
    TIME_WAIT 表示主动关闭,CLOSE_WAIT 表示被动关闭。
    25.说说你知道的几种 HTTP 响应码,比如 200, 302, 404。

    1xx:信息,请求收到,继续处理
    2xx:成功,行为被成功地接受、理解和采纳
    3xx:重定向,为了完成请求,必须进一步执行的动作
    4xx:客户端错误,请求包含语法错误或者请求无法实现
    5xx:服务器错误,服务器不能实现一种明显无效的请求
    200 ok 一切正常
    302 Moved Temporatily 文件临时移出
    404 not found
    

    参考链接
    26.当你用浏览器打开一个链接的时候,计算机做了哪些工作步骤。
    Dns解析–>端口分析–>tcp请求–>服务器处理请求–>服务器响应–>浏览器解析—>链接关闭
    27.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;
    

    参考链接
    28.如何避免浏览器缓存。
    无法被浏览器缓存的请求:
    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的请求无法被缓存
    参考链接
    29.简述 Http 请求 get 和 post 的区别以及数据包格式。
    这里写图片描述
    这里写图片描述
    参考链接1
    参考链接2
    30.简述 HTTP 请求的报文格式。
    参考上面
    31.HTTPS 的加密方式是什么,讲讲整个加密解密流程。
    加密方式是tls/ssl,底层是通过对称算法,非对称,hash算法实现
    客户端发起HTTPS请求 --》2. 服务端的配置 --》
    3. 传送证书 —》4. 客户端解析证书 5. 传送加密信息 6. 服务段解密信息 7. 传输加密后的信息 8. 客户端解密信息
    参考链接
    #架构设计与分布式
    32.常见的缓存策略有哪些,你们项目中用到了什么缓存系统,如何设计的。
    Cdn缓存,redis缓存,ehcache缓存等
    Cdn 图片资源 js等, redis一主一从 echcache缓存数据
    33.用 java 自己实现一个 LRU。

    final int cacheSize = 100;
    Map&lt;String, String&gt; map = new LinkedHashMap&lt;String, String&gt;((int) Math.ceil(cacheSize / 0.75f) + 1, 0.75f, true) {
    	@Override
    	protected boolean removeEldestEntry(Map.Entry&lt;String, String&gt; eldest) {
    		return size() &gt; cacheSize;
    	}
    };
    

    参考链接
    34.分布式集群下如何做到唯一序列号。
    Redis生成,mongodb的objectId,zk生成
    参考链接
    35.设计一个秒杀系统,30 分钟没付款就自动关闭交易。
    分流 – 限流–异步–公平性(只能参加一次)–用户体验(第几位,多少分钟,一抢完)
    容错处理
    Redis 队列 mysql
    30分钟关闭 可以借助redis的发布订阅机制 在失效时进行后续操作,其他mq也可以
    参考链接
    36.如何使用 redis 和 zookeeper 实现分布式锁?有什么区别优缺点,分别适用什么场景。
    首先分布式锁实现常见的有数据库锁(表记录),缓存锁,基于zk(临时有序节点可以实现的)的三种
    Redis适用于对性能要求特别高的场景。redis可以每秒执行10w次,内网延迟不超过1ms
    缺点是数据存放于内存,宕机后锁丢失。
    锁无法释放?使用Zookeeper可以有效的解决锁无法释放的问题,因为在创建锁的时候,客户端会在ZK中创建一个临时节点,一旦客户端获取到锁之后突然挂掉(Session连接断开),那么这个临时节点就会自动删除掉。其他客户端就可以再次获得锁。
    非阻塞锁?使用Zookeeper可以实现阻塞的锁,客户端可以通过在ZK中创建顺序节点,并且在节点上绑定监听器,一旦节点有变化,Zookeeper会通知客户端,客户端可以检查自己创建的节点是不是当前所有节点中序号最小的,如果是,那么自己就获取到锁,便可以执行业务逻辑了。
    不可重入?使用Zookeeper也可以有效的解决不可重入的问题,客户端在创建节点的时候,把当前客户端的主机信息和线程信息直接写入到节点中,下次想要获取锁的时候和当前最小的节点中的数据比对一下就可以了。如果和自己的信息一样,那么自己直接获取到锁,如果不一样就再创建一个临时的顺序节点,参与排队。
    单点问题?使用Zookeeper可以有效的解决单点问题,ZK是集群部署的,只要集群中有半数以上的机器存活,就可以对外提供服务。
    参考链接
    37.如果有人恶意创建非法连接,怎么解决。
    可以使用filter过滤处理
    38.分布式事务的原理,优缺点,如何使用分布式事务。
    Two Phase commit协议
    优点是可以管理多机事务,拥有无线扩展性 确定是易用性难,承担延时风险
    JTA,atomiks等
    参考链接
    39.什么是一致性 hash。
    一致性hash是一种分布式hash实现算法。满足平衡性 单调性 分散性 和负载。
    参考链接
    40.什么是 restful,讲讲你理解的 restful。
    REST 指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是 RESTful。
    参考链接
    41.如何设计建立和保持 100w 的长连接。
    服务器内核调优(tcp,文件数),客户端调优,框架选择(netty)
    42.如何防止缓存雪崩。
    缓存雪崩可能是因为数据未加载到缓存中,或者缓存同一时间大面积的失效,从而导致所有请求都去查数据库,导致数据库CPU和内存负载过高,甚至宕机。
    解决思路:
    1,采用加锁计数,或者使用合理的队列数量来避免缓存失效时对数据库造成太大的压力。这种办法虽然能缓解数据库的压力,但是同时又降低了系统的吞吐量。
    2,分析用户行为,尽量让失效时间点均匀分布。避免缓存雪崩的出现。
    3,如果是因为某台缓存服务器宕机,可以考虑做主备,比如:redis主备,但是双缓存涉及到更新事务的问题,update可能读到脏数据,需要好好解决。
    参考链接
    43.解释什么是 MESI 协议(缓存一致性)。
    MESI是四种缓存段状态的首字母缩写,任何多核系统中的缓存段都处于这四种状态之一。我将以相反的顺序逐个讲解,因为这个顺序更合理:
    失效(Invalid)缓存段,要么已经不在缓存中,要么它的内容已经过时。为了达到缓存的目的,这种状态的段将会被忽略。一旦缓存段被标记为失效,那效果就等同于它从来没被加载到缓存中。
    共享(Shared)缓存段,它是和主内存内容保持一致的一份拷贝,在这种状态下的缓存段只能被读取,不能被写入。多组缓存可以同时拥有针对同一内存地址的共享缓存段,这就是名称的由来。
    独占(Exclusive)缓存段,和S状态一样,也是和主内存内容保持一致的一份拷贝。区别在于,如果一个处理器持有了某个E状态的缓存段,那其他处理器就不能同时持有它,所以叫“独占”。这意味着,如果其他处理器原本也持有同一缓存段,那么它会马上变成“失效”状态。
    已修改(Modified)缓存段,属于脏段,它们已经被所属的处理器修改了。如果一个段处于已修改状态,那么它在其他处理器缓存中的拷贝马上会变成失效状态,这个规律和E状态一样。此外,已修改缓存段如果被丢弃或标记为失效,那么先要把它的内容回写到内存中——这和回写模式下常规的脏段处理方式一样。
    44.说说你知道的几种 HASH 算法,简单的也可以。
    哈希(Hash)算法,即散列函数。 它是一种单向密码体制,即它是一个从明文到密文的不可逆的映射,只有加密过程,没有解密过程。 同时,哈希函数可以将任意长度的输入经过变化以后得到固定长度的输出
    MD4 MD5 SHA
    参考链接
    45.什么是 paxos 算法。
    Paxos算法是莱斯利·兰伯特(Leslie Lamport,就是 LaTeX 中的"La",此人现在在微软研究院)于1990年提出的一种基于消息传递的一致性算法。
    参考链接
    ##什么是 zab 协议。
    ZAB 是 Zookeeper 原子广播协议的简称
    整个ZAB协议主要包括消息广播和崩溃恢复两个过程,进一步可以分为三个阶段,分别是:
    发现 Discovery
    同步 Synchronization
    广播 Broadcast
    组成ZAB协议的每一个分布式进程,都会循环执行这三个阶段,将这样一个循环称为一个主进程周期。
    参考链接
    ##一个在线文档系统,文档可以被编辑,如何防止多人同时对同一份文档进行编辑更新。
    点击编辑的时候,利用redis进行加锁setNX完了之后 expire 一下
    也可以用版本号进行控制
    46.线上系统突然变得异常缓慢,你如何查找问题。
    逐级排查(网络,磁盘,内存,cpu),数据库,日志,中间件等也可通过监控工具排查。
    47.说说你平时用到的设计模式。
    单例, 代理,模板,策略,命令
    a) 单例模式:单例模式核心只需要new一个实例对象的模式,比如数据库连接,在线人数等,一些网站上看到的在线人数统计就是通过单例模式实现的,把一个计时器存放在数据库或者内存中,当有人登陆的时候取出来加一再放回去,有人退出登陆的时候取出来减一再放回去,但是当有两个人同时登陆的时候,会同时取出计数器,同时加一,同时放回去,这样的话数据就会错误,所以需要一个全局变量的对象给全部人使用,只需要new出一个实例对象,这就是单例模式的应用,并且单例模式节省资源,因为它控制了实例对象的个数,并有利于gc回收。

    b) 策略模式:就是将几个类中公共的方法提取到一个新的类中,从而使扩展更容易,保证代码的可移植性,可维护性强。比如有个需求是写鸭子对象,鸭子有叫,飞,外形这三种方法,如果每个鸭子类都写这三个方法会出现代码的冗余,这时候我们可以把鸭子中的叫,飞,外形这三个方法提取出来,放到鸭父类中,让每个鸭子都继承这个鸭父类,重写这三个方法,这样封装的代码可移植性强,当用户提出新的需求比如鸭子会游泳,那么对于我们oo程序员来讲就非常简单了我们只需要在鸭父类中加一个游泳的方法,让会游泳的鸭子重写游泳方法就可以了。

    c) 工厂模式:简单的工厂模式主要是统一提供实例对象的引用,通过工厂模式接口获取实例对象的引用。比如一个登陆功能,后端有三个类,controller类,interface类,实现接口的实现类。当客户端发出一个请求,当请求传到controller类中时,controller获取接口的引用对象,而实现接口的实现类中封装好了登陆的业务逻辑代码。当你需要加一个注册需求的时候只需要在接口类中加一个注册方法,实现类中实现方法,controller获取接口的引用对象即可,不需要改动原来的代码,这种做法是的可拓展性强。
    参考链接
    48.Dubbo 的原理,数据怎么流转的,怎么实现集群,负载均衡,服务注册和发现。重试转发,快速失败的策略是怎样的。
    Dubbo[]是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。
    ##Cluster 实现集群
    在集群负载均衡时,Dubbo提供了多种均衡策略,缺省为random随机调用。
    Random LoadBalance:随机,按权重比率设置随机概率。
    RoundRobin LoadBalance:轮循,按公约后的权重比率设置轮循比率。
    LeastActive LoadBalance:最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。
    ConsistentHash LoadBalance:一致性Hash,相同参数的请求总是发到同一提供者。当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。
    快速失败,只发起一次调用,失败立即报错。
    参考链接
    49.一次 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)服务消费方得到最终结果。
    50.异步模式的用途和意义。
    异步模式使用与服务器多核,并发严重的场景
    可提高服务吞吐量大,不容易受到冲击,可以采用并发策略,提高响应时间
    缓存数据过期后的更新如何设计。
    失效:应用程序先从cache取数据,没有得到,则从数据库中取数据,成功后,放到缓存中。
    命中:应用程序从cache中取数据,取到后返回。
    更新:先把数据存到数据库中,成功后,再让缓存失效。
    51.编程中自己都怎么考虑一些设计原则的,比如开闭原则,以及在工作中的应用。
    开闭原则(Open Close Principle)
    一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。
    里氏代换原则(Liskov Substitution Principle)
    子类型必须能够替换掉它们的父类型。
    依赖倒转原则(Dependence Inversion Principle)
    高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。即针对接口编程,不要针对实现编程
    接口隔离原则(Interface Segregation Principle)
    建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少
    组合/聚合复用原则
    说要尽量的使用合成和聚合,而不是继承关系达到复用的目的
    迪米特法则(Law Of Demeter)
    迪米特法则其根本思想,是强调了类之间的松耦合,类之间的耦合越弱,越有利于复用,一个处在弱耦合的类被修改,不会对有关系的类造成影响,也就是说,信息的隐藏促进了软件的复用。
    单一职责原则(Single Responsibility Principle)
    一个类只负责一项职责,应该仅有一个引起它变化的原因
    参考链接
    52.设计一个社交网站中的“私信”功能,要求高并发、可扩展等等。 画一下架构图。
    MVC 模式,即常见的 MVC 框架。
    SSM SSH SSI等
    53.曾经参与设计的服务器架构。
    54.应用服务器怎么监控性能,各种方式的区别。
    55.如何设计一套高并发支付方案,架构如何设计。
    56.如何实现负载均衡,有哪些算法可以实现。
    57.Zookeeper 的用途,选举的原理是什么。
    58.Mybatis 的底层实现原理。
    59.请思考一个方案,设计一个可以控制缓存总体大小的自动适应的本地缓存。
    ##请思考一个方案,实现分布式环境下的 countDownLatch。
    60.后台系统怎么防止请求重复提交。
    可以通过token值进行防止重复提交,存放到redis中,在表单初始化的时候隐藏在表单中,添加的时候在移除。判断这个状态即可防止重复提交。
    如何看待缓存的使用(本地缓存,集中式缓存),简述本地缓存和集中式缓存和优缺点。本地缓存在并发使用时的注意事项。
    61.描述一个服务从发布到被消费的详细过程。
    ##讲讲你理解的服务治理。
    62.如何做到接口的幂等性。
    #算法
    63.10 亿个数字里里面找最小的 10 个。
    ##有 1 亿个数字,其中有 2 个是重复的,快速找到它,时间和空间要最优。
    64.2 亿个随机生成的无序整数,找出中间大小的值。
    65.给一个不知道长度的(可能很大)输入字符串,设计一种方案,将重复的字符排重。
    66.遍历二叉树。
    67.有 3n+1 个数字,其中 3n 个中是重复的,只有 1 个是不重复的,怎么找出来。
    ##常用的排序算法,快排,归并、冒泡。 快排的最优时间复杂度,最差复杂度。冒泡排序的优化方案。
    ##二分查找的时间复杂度,优势。
    ##一个已经构建好的 TreeSet,怎么完成倒排序。

    	//冒泡
        public static void mp(int a[]) {
    
            int swap = 0;
            for (int i = 0; i < a.length; i++) {
                for (int j = i; j < a.length; j++) {
                    if (a[j] > a[i]) {
                        swap = a[i];
                        a[i] = a[j];
                        a[j] = swap;
                    }
                }
            }
            System.out.println(Arrays.toString(a));
            }
    
        /**
         * 不使用递归的二分查找
         *title:commonBinarySearch
         *@param arr
         *@param key
         *@return 关键字位置
         */
        public static int commonBinarySearch(int[] arr,int key){
            int low = 0;
            int high = arr.length - 1;
            int middle = 0;//定义middle
    
            if(key < arr[low] || key > arr[high] || low > high){
                return -1;
            }
            while(low <= high){
                middle = (low + high) / 2;
                if(arr[middle] > key){
                    //比关键字大则关键字在左区域
                    high = middle - 1;
                }else if(arr[middle] < key){
                    //比关键字小则关键字在右区域
                    low = middle + 1;
                }else{
                    return middle;
                }
            }
            return -1;//最后仍然没有找到,则返回-1
        }
        
    	/**
    	 * 使用递归的二分查找
    	 *title:recursionBinarySearch
    	 *@param arr 有序数组
    	 *@param key 待查找关键字
    	 *@return 找到的位置
    	 */
    	public static int recursionBinarySearch(int[] arr,int key,int low,int high){
    		
    		if(key < arr[low] || key > arr[high] || low > high){
    			return -1;				
    		}
    		int middle = (low + high) / 2;//初始中间位置
    		if(arr[middle] > key){
    			//比关键字大则关键字在左区域
    			return recursionBinarySearch(arr, key, low, middle - 1);
    		}else if(arr[middle] < key){
    			//比关键字小则关键字在右区域
    			return recursionBinarySearch(arr, key, middle + 1, high);
    		}else {
    			return middle;
    		}	
    	}
    

    68.什么是 B+树,B-树,列出实际的使用场景。
    69.并行和并发有什么区别?
    并发当有多个线程在操作时,如果系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,再将时间 段分配给各个线程执行,在一个时间段的线程代码运行时,其它线程处于挂起状。.这种方式我们称之为并发(Concurrent)。
    并行:当系统有一个以上CPU时,则线程的操作有可能非并发。当一个CPU执行一个线程时,另一个CPU可以执行另一个线程,两个线程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。
    参考链接
    70.线程和进程的区别?
    简而言之,进程是程序运行和资源分配的基本单位,一个程序至少有一个进程,一个进程至少有一个线程。进程在执行过程中拥有独立的内存单元,而多个线程共享内存资源,减少切换次数,从而效率更高。线程是进程的一个实体,是cpu调度和分派的基本单位,是比程序更小的能独立运行的基本单位。同一进程中的多个线程之间可以并发执行。
    71.守护线程是什么?
    守护线程(即daemon thread),是个服务线程,准确地来说就是服务其他的线程。
    72. 创建线程有哪几种方式?
    ①. 继承Thread类创建线程类

    定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。
    创建Thread子类的实例,即创建了线程对象。
    调用线程对象的start()方法来启动该线程。
    ②. 通过Runnable接口创建线程类

    定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
    创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。
    调用线程对象的start()方法来启动该线程。
    ③. 通过Callable和Future创建线程

    创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。
    创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
    使用FutureTask对象作为Thread对象的target创建并启动新线程。
    调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。
    73. 说一下 runnable 和 callable 有什么区别?
    Runnable接口中的run()方法的返回值是void,它做的事情只是纯粹地去执行run()方法中的代码而已;
    Callable接口中的call()方法是有返回值的,是一个泛型,和Future、FutureTask配合可以用来获取异步执行的结果。
    74.线程有哪些状态?
    线程通常都有五种状态,创建、就绪、运行、阻塞和死亡。

    创建状态。在生成线程对象,并没有调用该对象的start方法,这是线程处于创建状态。
    就绪状态。当调用了线程对象的start方法之后,该线程就进入了就绪状态,但是此时线程调度程序还没有把该线程设置为当前线程,此时处于就绪状态。在线程运行之后,从等待或者睡眠中回来之后,也会处于就绪状态。
    运行状态。线程调度程序将处于就绪状态的线程设置为当前线程,此时线程就进入了运行状态,开始运行run函数当中的代码。
    阻塞状态。线程正在运行的时候,被暂停,通常是为了等待某个时间的发生(比如说某项资源就绪)之后再继续运行。sleep,suspend,wait等方法都可以导致线程阻塞。
    死亡状态。如果一个线程的run方法执行结束或者调用stop方法后,该线程就会死亡。对于已经死亡的线程,无法再使用start方法令其进入就绪   
    75.sleep() 和 wait() 有什么区别?
    sleep():方法是线程类(Thread)的静态方法,让调用线程进入睡眠状态,让出执行机会给其他线程,等到休眠时间结束后,线程进入就绪状态和其他线程一起竞争cpu的执行时间。因为sleep() 是static静态的方法,他不能改变对象的机锁,当一个synchronized块中调用了sleep() 方法,线程虽然进入休眠,但是对象的机锁没有被释放,其他线程依然无法访问这个对象。

    wait():wait()是Object的方法,当一个线程执行到wait方法时,它就进入到一个和该对象相关的等待池,同时释放对象的机锁,使得其他线程能够访问,可以通过notify,notifyAll方法来唤醒等待的线程。
    76.notify()和 notifyAll()有什么区别?
    如果线程调用了对象的 wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁。
    当有线程调用了对象的 notifyAll()方法(唤醒所有 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。也就是说,调用了notify后只要一个线程会由等待池进入锁池,而notifyAll会将该对象等待池内的所有线程移动到锁池中,等待锁竞争。
    优先级高的线程竞争到对象锁的概率大,假若某线程没有竞争到该对象锁,它还会留在锁池中,唯有线程再次调用 wait()方法,它才会重新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了 synchronized 代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。
    77.线程的 run()和 start()有什么区别?
    每个线程都是通过某个特定Thread对象所对应的方法run()来完成其操作的,方法run()称为线程体。通过调用Thread类的start()方法来启动一个线程。

    start()方法来启动一个线程,真正实现了多线程运行。这时无需等待run方法体代码执行完毕,可以直接继续执行下面的代码; 这时此线程是处于就绪状态, 并没有运行。 然后通过此Thread类调用方法run()来完成其运行状态, 这里方法run()称为线程体,它包含了要执行的这个线程的内容, Run方法运行结束, 此线程终止。然后CPU再调度其它线程。

    run()方法是在本线程里的,只是线程里的一个函数,而不是多线程的。 如果直接调用run(),其实就相当于是调用了一个普通函数而已,直接待用run()方法必须等待run()方法执行完毕才能执行下面的代码,所以执行路径还是只有一条,根本就没有线程的特征,所以在多线程执行时要使用start()方法而不是run()方法。
    78.创建线程池有哪几种方式?
    ①. newFixedThreadPool(int nThreads)

    创建一个固定长度的线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程规模将不再变化,当线程发生未预期的错误而结束时,线程池会补充一个新的线程。

    ②. newCachedThreadPool()

    创建一个可缓存的线程池,如果线程池的规模超过了处理需求,将自动回收空闲线程,而当需求增加时,则可以自动添加新线程,线程池的规模不存在任何限制。

    ③. newSingleThreadExecutor()

    这是一个单线程的Executor,它创建单个工作线程来执行任务,如果这个线程异常结束,会创建一个新的来替代它;它的特点是能确保依照任务在队列中的顺序来串行执行。

    ④. newScheduledThreadPool(int corePoolSize)

    创建了一个固定长度的线程池,而且以延迟或定时的方式来执行任务,类似于Timer。
    参考链接
    79.线程池都有哪些状态?
    线程池有5种状态:Running、ShutDown、Stop、Tidying、Terminated。

    线程池各个状态切换框架图:
    在这里插入图片描述
    80.线程池中 submit()和 execute()方法有什么区别?
    接收的参数不一样
    submit有返回值,而execute没有
    submit方便Exception处理
    81. 在 java 程序中怎么保证多线程的运行安全?

    线程安全在三个方面体现:

    原子性:提供互斥访问,同一时刻只能有一个线程对数据进行操作,(atomic,synchronized);
    可见性:一个线程对主内存的修改可以及时地被其他线程看到,(synchronized,volatile);
    有序性:一个线程观察其他线程中的指令执行顺序,由于指令重排序,该观察结果一般杂乱无序,(happens-before原则)。
    82.多线程锁的升级原理是什么?

    在Java中,锁共有4种状态,级别从低到高依次为:无状态锁,偏向锁,轻量级锁和重量级锁状态,这几个状态会随着竞争情况逐渐升级。锁可以升级但不能降级。

    锁升级的图示过程:
    在这里插入图片描述
    83.什么是死锁?
    死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。是操作系统层面的一个错误,是进程死锁的简称,最早在 1965 年由 Dijkstra 在研究银行家算法时提出的,它是计算机操作系统乃至整个并发程序设计领域最难处理的问题之一。
    84.ThreadLocal 是什么?有哪些使用场景?
    线程局部变量是局限于线程内部的变量,属于线程自身所有,不在多个线程间共享。Java提供ThreadLocal类来支持线程局部变量,是一种实现线程安全的方式。但是在管理环境下(如 web 服务器)使用线程局部变量的时候要特别小心,在这种情况下,工作线程的生命周期比任何应用变量的生命周期都要长。任何线程局部变量一旦在工作完成后没有释放,Java 应用就存在内存泄露的风险。
    85.synchronized 和 Lock 有什么区别?
    首先synchronized是java内置关键字,在jvm层面,Lock是个java类;
    synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁;
    synchronized会自动释放锁(a 线程执行完同步代码会释放锁 ;b 线程执行过程中发生异常会释放锁),Lock需在finally中手工释放锁(unlock()方法释放锁),否则容易造成线程死锁;
    用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了;
    synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可判断、可公平(两者皆可);
    Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。
    86.对ajax的理解
    Ajax为异步请求,即局部刷新技术,在传统的页面中,用户需要点击按钮或者事件触发请求,到刷新页面,而异步技术为不需要点击即可触发事件,这样使得用户体验感增强,比如商城购物车的异步加载,当你点击商品时无需请求后台而直接动态修改参数。


    6.数据库知识


    1.数据库隔离级别有哪些,各自的含义是什么,MYSQL 默认的隔离级别是是什么。

    1.未提交读(Read Uncommitted):允许脏读,也就是可能读取到其他会话中未提交事务修改的数据
    2.提交读(Read Committed):只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 (不重复读)
    3.可重复读(Repeated Read):可重复读。在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读
    4.串行读(Serializable):完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞
    
    MYSQL默认是RepeatedRead级别
    

    2.MYSQL 有哪些存储引擎,各自优缺点。

    1.MyISAM: 拥有较高的插入,查询速度,但不支持事务
    2.InnoDB :5.5版本后Mysql的默认数据库,事务型数据库的首选引擎,支持ACID事务,支持行级锁定
    3.BDB: 源自Berkeley DB,事务型数据库的另一种选择,支持COMMIT和ROLLBACK等其他事务特性
    4.Memory :所有数据置于内存的存储引擎,拥有极高的插入,更新和查询效率。但是会占用和数据量成正比的内存空间。并且其内容会在Mysql重新启动时丢失
    5.Merge :将一定数量的MyISAM表联合而成一个整体,在超大规模数据存储时很有用
    6.Archive :非常适合存储大量的独立的,作为历史记录的数据。因为它们不经常被读取。Archive拥有高效的插入速度,但其对查询的支持相对较差
    7.Federated: 将不同的Mysql服务器联合起来,逻辑上组成一个完整的数据库。非常适合分布式应用
    8.Cluster/NDB :高冗余的存储引擎,用多台数据机器联合提供服务以提高整体性能和安全性。适合数据量大,安全和性能要求高的应用
    9.CSV: 逻辑上由逗号分割数据的存储引擎。它会在数据库子目录里为每个数据表创建一个.CSV文件。这是一种普通文本文件,每个数据行占用一个文本行。CSV存储引擎不支持索引。
    10.BlackHole :黑洞引擎,写入的任何数据都会消失,一般用于记录binlog做复制的中继
    
    另外,Mysql的存储引擎接口定义良好。有兴趣的开发者通过阅读文档编写自己的存储引擎。
    

    参考链接
    3.高并发下,如何做到安全的修改同一行数据。
    使用悲观锁 悲观锁本质是当前只有一个线程执行操作,结束了唤醒其他线程进行处理。
    也可以缓存队列中锁定主键。
    4.乐观锁和悲观锁是什么,INNODB 的行级锁有哪 2 种,解释其含义。
    乐观锁是设定每次修改都不会冲突,只在提交的时候去检查,悲观锁设定每次修改都会冲突,持有排他锁。
    行级锁分为共享锁和排他锁两种 共享锁又称读锁 排他锁又称写锁
    参考链接
    5.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:执行情况的说明和描述
    Oracle优化

    1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
    
    2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:
    
    select id from t where num is null
    可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:
    select id from t where num=0
    3.应尽量避免在 where 子句中使用!=<>操作符,否则将引擎放弃使用索引而进行全表扫描。
    4.应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:
    select id from t where num=10 or num=20
    可以这样查询:
    select id from t where num=10
    union all
    select id from t where num=20
    5.in 和 not in 也要慎用,否则会导致全表扫描,如:
    select id from t where num in(1,2,3)
    对于连续的数值,能用 between 就不要用 in 了:
    select id from t where num between 1 and 3
    6.下面的查询也将导致全表扫描:
    select id from t where name like ‘%abc%’
    若要提高效率,可以考虑全文检索。
    7.如果在 where 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描:
    select id from t where num=@num
    可以改为强制查询使用索引:
    select id from t with(index(索引名)) where num=@num
    8.应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:
    select id from t where num/2=100
    应改为:
    select id from t where num=100*2
    9.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:
    select id from t where substring(name,1,3)=‘abc’ // oracle总有的是substr函数。
    select id from t where datediff(day,createdate,2005-11-30)=0 //查过了确实没有datediff函数。
    应改为:
    select id from t where name like ‘abc%’
    select id from t where createdate>=2005-11-30’ and createdate<2005-12-1//
    oracle 中时间应该把char 转换成 date 如: createdate >= to_date(2005-11-30,‘yyyy-mm-dd’)
    10.不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。
    
    11.在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。
    12.不要写一些没有意义的查询,如需要生成一个空表结构:
    select col1,col2 into #t from t where 1=0
    这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样:
    create table #t()
    13.很多时候用 exists 代替 in 是一个好的选择:
    select num from a where num in(select num from b)
    用下面的语句替换:
    select num from a where exists(select 1 from b where num=a.num)
    14.并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。
    15.索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。
    16.应尽可能的避免更新 clustered 索引数据列,因为 clustered 索引数据列的顺序就是表记录的物理存储顺序,一旦该列值改变将导致整个表记录的顺序的调整,会耗费相当大的资源。若应用系统需要频繁更新 clustered 索引数据列,那么需要考虑是否应将该索引建为 clustered 索引。
    17.尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。
    18.尽可能的使用 varchar/nvarchar 代替 char/nchar ,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。
    19.任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段。
    20.尽量使用表变量来代替临时表。如果表变量包含大量数据,请注意索引非常有限(只有主键索引)。
    21.避免频繁创建和删除临时表,以减少系统表资源的消耗。
    22.临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用表中的某个数据集时。但是,对于一次性事件,最好使用导出表。
    23.在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果数据量不大,为了缓和系统表的资源,应先create table,然后insert。
    24.如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定。
    25.尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。
    26.使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方案来解决问题,基于集的方法通常更有效。
    27.与临时表一样,游标并不是不可使用。对小型数据集使用 FAST_FORWARD 游标通常要优于其他逐行处理方法,尤其是在必须引用几个表才能获得所需的数据时。在结果集中包括“合计”的例程通常要比使用游标执行的速度快。如果开发时间允许,基于游标的方法和基于集的方法都可以尝试一下,看哪一种方法的效果更好。
    28.在所有的存储过程和触发器的开始处设置 SET NOCOUNT ON ,在结束时设置 SET NOCOUNT OFF 。无需在执行存储过程和触发器的每个语句后向客户端发送 DONE_IN_PROC 消息。
    29.尽量避免大事务操作,提高系统并发能力。
    30.尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。
    

    参考链接1
    参考链接2
    6.数据库会死锁吗,举一个死锁的例子,mysql 怎么解决死锁。
    产生死锁的原因主要是:
    (1)系统资源不足。
    (2) 进程运行推进的顺序不合适。
    (3)资源分配不当等。
    如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。
    产生死锁的四个必要条件:
    (1) 互斥条件:一个资源每次只能被一个进程使用。
    (2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
    (3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
    (4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
    这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。
    这里提供两个解决数据库死锁的方法:
    1)重启数据库(谁用谁知道)
    2)杀掉抢资源的进程:
    先查哪些进程在抢资源:SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;
    杀掉它们:Kill trx_mysql_thread_id;
    7.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)的索引,那么只需要修改原来的索引即可
    参考链接1
    参考链接2
    ##聚集索引和非聚集索引的区别。
    “聚簇”就是索引和记录紧密在一起。
    非聚簇索引 索引文件和数据文件分开存放,索引文件的叶子页只保存了主键值,要定位记录还要去查找相应的数据块。
    8.数据库中 BTREE 和 B+tree 区别。
    B+是btree的变种,本质都是btree,btree+与B-Tree相比,B+Tree有以下不同点:
    每个节点的指针上限为2d而不是2d+1。
    内节点不存储data,只存储key;叶子节点不存储指针。
    参考链接
    Btree 怎么分裂的,什么时候分裂,为什么是平衡的。
    Key 超过1024才分裂B树为甚会分裂? 因为随着数据的增多,一个结点的key满了,为了保持B树的特性,就会产生分裂,就向红黑树和AVL树为了保持树的性质需要进行旋转一样!
    9.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子句中对字段进行函数操作
    10.如何写 sql 能够有效的使用到复合索引。
    由于复合索引的组合索引,类似多个木板拼接在一起,如果中间断了就无法用了,所以要能用到复合索引,首先开头(第一列)要用上,比如index(a,b) 这种,我们可以select table tname where a=XX 用到第一列索引 如果想用第二列 可以 and b=XX 或者and b like‘TTT%’
    11.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。
    12.数据库自增主键可能的问题。
    在分库分表时可能会生成重复主键 利用自增比例达到唯一 自增1 2,3 等
    参考链接
    #消息队列
    ##用过哪些 MQ,和其他 mq 比较有什么优缺点,MQ 的连接是线程安全的吗,你们公司的MQ 服务架构怎样的。
    根据实际情况说明
    我们公司用activeMQ 因为业务比较简单 只有转码功能,而amq比较简单
    如果是分布式的建议用kafka
    参考链接
    13.MQ 系统的数据如何保证不丢失。
    基本都是对数据进行持久化,多盘存储
    14.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形式存在。
    参考链接1
    参考链接2
    #Redis,Memcached
    15.redis 的 list 结构相关的操作。
    LPUSH LPUSHX RPUSH RPUSHX LPOP RPOP BLPOP BRPOP LLEN LRANGE
    参考链接
    16.Redis 的数据结构都有哪些。
    字符串(strings):存储整数(比如计数器)和字符串(废话。。),有些公司也用来存储json/pb等序列化数据,并不推荐,浪费内存
    哈希表(hashes):存储配置,对象(比如用户、商品),优点是可以存取部分key,对于经常变化的或者部分key要求atom操作的适合
    列表(lists):可以用来存最新用户动态,时间轴,优点是有序,确定是元素可重复,不去重
    集合(sets):无序,唯一,对于要求严格唯一性的可以使用
    有序集合(sorted sets):集合的有序版,很好用,对于排名之类的复杂场景可以考虑
    参考链接
    ##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最大的键值
    参考链接1
    参考链接2
    参考链接3
    17.redis2 和 redis3 的区别,redis3 内部通讯机制。
    集群方式的区别,3采用Cluster,2采用客户端分区方案和代理方案
    通信过程说明:
    1) 集群中的每个节点都会单独开辟一个TCP通道, 用于节点之间彼此
    通信, 通信端口号在基础端口上加10000。
    2) 每个节点在固定周期内通过特定规则选择几个节点发送ping消息。
    3) 接收到ping消息的节点用pong消息作为响应。
    ##当前 redis 集群有哪些玩法,各自优缺点,场景。
    当缓存使用 持久化使用
    18.Memcache 的原理,哪些数据适合放在缓存中。
    基于libevent的事件处理
    内置内存存储方式SLab Allocation机制
    并不单一的数据删除机制
    基于客户端的分布式系统
    变化频繁,具有不稳定性的数据,不需要实时入库, (比如用户在线
    状态、在线人数…)
    门户网站的新闻等,觉得页面静态化仍不能满足要求,可以放入
    到memcache中.(配合jquey的ajax请求)
    ##redis 和 memcached 的内存管理的区别。
    Memcached默认使用Slab Allocation机制管理内存,其主要思想是按照预先规定的大小,将分配的内存分割成特定长度的块以存储相应长度的key-value数据记录,以完全解决内存碎片问题。
    Redis的内存管理主要通过源码中zmalloc.h和zmalloc.c两个文件来实现的。
    在Redis中,并不是所有的数据都一直存储在内存中的。这是和Memcached相比一个最大的区别。
    参考链接
    19.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乐观锁
    参考链接1
    参考链接2
    ##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正常工作后,就会去掉客观下线的标识,从而不需要进入故障转移流程。
    参考链接
    20.redis 的持久化的机制,aof 和 rdb 的区别。
    RDB 定时快照方式(snapshot): 定时备份,可能会丢失数据
    AOF 基于语句追加方式 只追加写操作
    AOF 持久化和 RDB 持久化的最主要区别在于,前者记录了数据的变更,而后者是保存了数据本身
    21.redis 的集群怎么同步的数据的。
    redis replication redis-migrate-tool等方式
    #搜索
    22.elasticsearch 了解多少,说说你们公司 es 的集群架构,索引数据大小,分片有多少,以及一些调优手段。elasticsearch 的倒排索引是什么。
    ElasticSearch(简称ES)是一个分布式、Restful的搜索及分析服务器,设计用于分布式计算;能够达到实时搜索,稳定,可靠,快速。和Apache Solr一样,它也是基于Lucence的索引服务器,而ElasticSearch对比Solr的优点在于:

    1.轻量级:安装启动方便,下载文件之后一条命令就可以启动。
    2.Schema free:可以向服务器提交任意结构的JSON对象,Solr中使用schema.xml指定了索引结构。
    3.多索引文件支持:使用不同的index参数就能创建另一个索引文件,Solr中需要另行配置。
    4.分布式: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_interval
    参考链接
    23.lucence 内部结构是什么
    索引(Index):
    在Lucene中一个索引是放在一个文件夹中的。
    如上图,同一文件夹中的所有的文件构成一个Lucene索引。
    段(Segment):
    一个索引可以包含多个段,段与段之间是独立的,添加新文档可以生成新的段,不同的段可以合并。
    如上图,具有相同前缀文件的属同一个段,图中共三个段 “_0” 和 "_1"和“_2”。
    segments.gen和segments_X是段的元数据文件,也即它们保存了段的属性信息。
    文档(Document):
    文档是我们建索引的基本单位,不同的文档是保存在不同的段中的,一个段可以包含多篇文档。
    新添加的文档是单独保存在一个新生成的段中,随着段的合并,不同的文档合并到同一个段中。
    域(Field):
    一篇文档包含不同类型的信息,可以分开索引,比如标题,时间,正文,作者等,都可以保存在不同的域里。
    不同域的索引方式可以不同,在真正解析域的存储的时候,我们会详细解读。
    词(Term):
    词是索引的最小单位,是经过词法分析和语言处理后的字符串。

    7.最后附一遍持续整理的博客

    彩蛋链接

    展开全文
  • JAVA面试基础

    万次阅读 多人点赞 2018-11-07 11:47:29
    1、面向对象的特征有哪些方面  (1)抽象:  抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节。...

    1、面向对象的特征有哪些方面
     (1)抽象:
     抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节。抽象包括两个方面,一是过程抽象,二是数据抽象。
     (2)继承:
     继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法。对象的一个新类可以从现有的类中派生,这个过程称为类继承。新类继承了原始类的特性,新类称为原始类的派生类(子类),而原始类称为新类的基类(父类)。派生类可以从它的基类那里继承方法和实例变量,并且类可以修改或增加新的方法使之更适合特殊的需要。
     (3)封装:
     封装是把过程和数据包围起来,对数据的访问只能通过已定义的界面。面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。
     (4) 多态性:
     多态性是指允许不同类的对象对同一消息作出响应。多态性包括参数化多态性和包含多态性。多态性语言具有灵活、抽象、行为共享 、代码共享的优势,很好的解决了应用程序函数同名问题。

    2、String是最基本的数据类型吗?
     基本数据类型包括byte、int、char、long、float、double、boolean和short。
     java.lang.String类是final类型的,因此不可以继承这个类、不能修改这个类。为了提高效率节省空间,我们应该用StringBuffer类

    3、int 和 Integer 有什么区别
     Java 提供两种不同的类型:引用类型和原始类型(或内置类型)。Int是java的原始数据类型,Integer是java为int提供的封类。
     Java为每个原始类型提供了封装类。
     原始类型封装类
     booleanBoolean
     charCharacter
     byteByte
     shortShort
     intInteger
     longLong
     floatFloat
     doubleDouble
     引用类型和原始类型的行为完全不同,并且它们具有不同的语义。引用类型和原始类型具有不同的特征和用法,它们包括:大小和速度问题,这种类型以哪种类型的数据结构存储,当引用类型和原始类型用作某个类的实例数据时所指定的缺省值。对象引用实例变量的缺省值为 null,而原始类型实例变量的缺省值与它们的类型有关。

    4、String 和StringBuffer的区别

    JAVA 平台提供了两个类:String和StringBuffer,它们可以储存和操作字符串,即包含多个字符的字符数据。这个String类提供了 数值不可改变的字符串。而这个StringBuffer类提供的字符串可以进行修改。当你知道字符数据要改变的时候你就可以使StringBuffer。典型地,你可以使用StringBuffers来动态构造字符数据

    5、运行时异常与一般异常有何异同?
     异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误。java编译器要求方法必须声明抛出可能发生的非运行时异常,但是并不要求必须声明抛出未被捕获的运行时异常。

    6、说出Servlet的生命周期,并说出Servlet和CGI的区别。
     Servlet被服务器实例化后,容器运行其init方法,请求到达时运行其service方法,service方法自动派遣运行与请求对应的doXXX方法(doGet,doPost)等,当服务器决定将实例销毁的时候调用其destroy方法。
     与cgi的区别在于servlet处于服务器进程中,它通过多线程方式运行其service方法,一个实例可以服务于多个请求,并且其实例一般不会销毁,而CGI对每个请求都产生新的进程,服务完成后就销毁,所以效率上低于servlet。

    7、说出ArrayList,Vector, LinkedList的存储性能和特性
     ArrayList 和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector由于使用了synchronized方法(线程安全),通常性能上较ArrayList差,而LinkedList使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。

    8、EJB是基于哪些技术实现的?并说出SessionBean和EntityBean的区别,StatefulBean和StatelessBean的区别。
     EJB包括Session Bean、Entity Bean、Message Driven Bean,基于JNDI、RMI、JAT等技术实现。
     SessionBean在J2EE应用程序中被用来完成一些服务器端的业务操作,例如访问数据库、调用其他EJB组件。EntityBean被用来代表应用系统中用到的数据。
     对于客户机,SessionBean是一种非持久性对象,它实现某些在服务器上运行的业务逻辑。
     对于客户机,EntityBean是一种持久性对象,它代表一个存储在持久性存储器中的实体的对象视图,或是一个由现有企业应用程序实现的实体。
     Session Bean 还可以再细分为 Stateful Session Bean 与 Stateless Session Bean ,这两种的 Session Bean都可以将系统逻辑 放在 method之中执行,不同的是 Stateful Session Bean 可以记录呼叫者的状态,因此通常来说,一个使用者会有一个相对应的 Stateful Session Bean 的实体。Stateless Session Bean 虽然也是逻辑组件,但是他却不负责记录使用者状态,也就是说当使用 者呼叫 Stateless Session Bean 的时候,EJB Container 并不会找寻特定的 Stateless Session Bean 的实体来执行这个 method 。换言之,很可能数个使用者在执行某个 Stateless Session Bean 的 methods 时,会是同一个 Bean 的 Instance 在执行。从内 存方面来看, Stateful Session Bean 与 Stateless Session Bean 比较, Stateful Session Bean 会消耗 J2EE Server 较多的 内存,然而 Stateful Session Bean 的优势却在于他可以维持使用者的状态。

    9、Collection 和 Collections的区别。
     Collection是集合类的上级接口,继承与他的接口主要有Set 和List.Collections是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。

    10、&和&&的区别。
     &是位运算符,表示按位与运算,&&是逻辑运算符,表示逻辑与(and)。

    11、HashMap和Hashtable的区别。
     HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口,主要区别在于HashMap允许空(null)键值(key),由于非线程安全,效率上可能高于Hashtable。
     HashMap允许将null作为一个entry的key或者value,而Hashtable不允许。
     HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因为contains方法容易让人引起误解。
     Hashtable继承自Dictionary类,而HashMap是Java1.2引进的Map interface的一个实现。
     最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而HashMap 就必须为之提供外同步。
     Hashtable和HashMap采用的hash/rehash算法都大概一样,所以性能不会有很大的差异。

    12、final, finally, finalize的区别。
     final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。
     finally是异常处理语句结构的一部分,表示总是执行。
     finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。

    13、sleep() 和 wait() 有什么区别?
     sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,把执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。
     wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。
                   
    14、Overload(重载)和Override(重写)的区别。Overloaded的方法是否可以改变返回值的类型?
     方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现,重载
     Overloading是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写
     (Overriding)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被”屏蔽”了。如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。Overloaded的方法是可以改变返回值的类型。

    15、error和exception有什么区别?
     error 表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指望程序能处理这样的情况。
     exception 表示一种设计或实现问题。也就是说,它表示如果程序运行正常,从不会发生的情况。

    16、同步和异步有何异同,在什么情况下分别使用他们?举例说明。
     如果数据将在线程间共享。例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那么这些数据就是共享数据,必须进行同步存取。
     当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异步途径往往更有效率。

    17、abstract class和interface有什么区别?
     声明方法的存在而不去实现它的类被叫做抽象类(abstract class),它用于要创建一个体现某些基本行为的类,并为该类声明方法,但不能在该类中实现该类的情况。不能创建abstract 类的实例。然而可以创建一个变量,其类型是一个抽象类,并让它指向具体子类的一个实例。不能有抽象构造函数或抽象静态方法。Abstract 类的子类为它们父类中的所有抽象方法提供实现,否则它们也是抽象类为。取而代之,在子类中实现该方法。知道其行为的其它类可以在类中实现这些方法。
     接口(interface)是抽象类的变体。在接口中,所有方法都是抽象的。多继承性可通过实现这样的接口而获得。接口中的所有方法都是抽象的,没有一个有程序体。接口只可以定义static final成员变量。接口的实现与子类相似,除了该实现类不能从接口定义中继承行为。当类实现特殊接口时,它定义(即将程序体给予)所有这种接口的方法。然后,它可以在实现了该接口的类的任何对象上调用接口的方法。由于有抽象类,它允许使用接口名作为引用变量的类型。通常的动态联编将生效。引用可以转换到接口类型或从接口类型转换,instanceof 运算符可以用来决定某对象的类是否实现了接口。


    18、short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错?
     short s1 = 1; s1 = s1 + 1; (s1+1运算结果是int型,需要强制转换类型)
     short s1 = 1; s1 += 1;(可以正确编译)

    19、Math.round(11.5)等於多少? Math.round(-11.5)等於多少?
     Math.round(11.5)==12
     Math.round(-11.5)==-11
     round方法返回与参数最接近的长整数,参数加1/2后求其floor.

    20、String s = new String(“xyz”);创建了几个String Object?
     两个(一个是“xyx”,一个是指向“xyx”的引用对象s)

    21、接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承实体类(concrete class)?
     接口可以继承接口。抽象类可以实现(implements)接口,抽象类是否可继承实体类,但前提是实体类必须有明确的构造函数。

    22、List, Set, Map是否继承自Collection接口?
     List,Set是,Map不是

    23、说出数据连接池的工作机制是什么?
     J2EE 服务器启动时会建立一定数量的池连接,并一直维持不少于此数目的池连接。客户端程序需要连接时,池驱动程序会返回一个未使用的池连接并将其表记为忙。如果当前没有空闲连接,池驱动程序就新建一定数量的连接,新建连接的数量由配置参数决定。当使用的池连接调用完成后,池驱动程序将此连接表记为空闲,其他调用就可以使用这个连接。

    24、abstract的method是否可同时是static,是否可同时是native,是否可同时是synchronized?
     都不能

    25、数组有没有length()这个方法? String有没有length()这个方法?
     数组没有length()这个方法,有length的属性。String有有length()这个方法。

    26、Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别?
     Set里的元素是不能重复的,那么用iterator()方法来区分重复与否。equals()是判读两个Set是否相等。
     equals()和==方法决定引用值是否指向同一对象equals()在类中被覆盖,为的是当两个分离的对象的内容和类型相配的话,返回真值 。

    27、构造器Constructor是否可被override?
     构造器Constructor不能被继承,因此不能重写Overriding,但可以被重载Overloading。

    28、是否可以继承String类?
     String类是final类故不可以继承。

    29、swtich是否能作用在byte上,是否能作用在long上,是否能作用在String上?
     switch(expr1)中,expr1是一个整数表达式。因此传递给 switch 和 case 语句的参数应该是 int、 short、 char 或者 byte。
     long,string 都不能作用于swtich。

    30、try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后?
     会执行,在return前执行。

    31、编程题: 用最有效率的方法算出2乘以8等於几?
     2 << 3 (有C背景的程序员特别喜欢问这种问题)

    32、两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?
     不对,有相同的hash code。

    33、当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
     是值传递。Java 编程语言只有值传递参数。当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用。对象的内容可以在被调用的方法中改变,但对象的引用是永远不会改变的。

    34、Java的接口和C++的虚类的相同和不同处。
     由于Java不支持多继承,而有可能某个类或对象要使用分别在几个类或对象里面的方法或属性,现有的单继承机制就不能满足要求。与继承相比,接口有更高的灵活性,因为接口中没有任何实现代码。当一个类实现了接口以后,该类要实现接口里面所有的方法和属性,并且接口里面的属性在默认状态下面都是public static,所有方法默认情况下是public.一个类可以实现多个接口。

    35、Java中的异常处理机制的简单原理和应用。
     当JAVA 程序违反了JAVA的语义规则时,JAVA虚拟机就会将发生的错误表示为一个异常。违反语义规则包括2种情况。一种是JAVA类库内置的语义检查。例如数组下标越界,会引发IndexOutOfBoundsException;访问null的对象时会引发NullPointerException。另一种情况就是JAVA允许程序员扩展这种语义检查,程序员可以创建自己的异常,并自由选择在何时用throw关键字引发异常。所有的异常都是 java.lang.Thowable的子类。


    36、你所知道的集合类都有哪些?主要方法?
     最常用的集合类是 List 和 Map。 List 的具体实现包括 ArrayList 和 Vector,它们是可变大小的列表,比较适合构建、存储和操
     作任何类型对象的元素列表。 List 适用于按数值索引访问元素的情形。
     Map 提供了一个更通用的元素存储方法。 Map 集合类用于存储元素对(称作"键"和"值"),其中每个键映射到一个值。

    37、描述一下JVM加载class文件的原理机制?
     JVM中类的装载是由ClassLoader和它的子类来实现的,Java ClassLoader 是一个重要的Java运行时系统组件。它负责在运行时查找和装入类文件的类。

    38、char型变量中能不能存贮一个中文汉字?为什么?
     能够定义成为一个中文的,因为java中以unicode编码,一个char占2个字节(Byte)共16位(bit),所以放一个中文是没问题的

    39、JSP的内置对象及方法
     request表示HttpServletRequest对象。它包含了有关浏览器请求的信息,并且提供了几个用于获取cookie, header, 和session数据的有用的方法。
     response表示HttpServletResponse对象,并提供了几个用于设置送回浏览器的响应的方法(如cookies,头信息等)
     out对象是javax.jsp.JspWriter的一个实例,并提供了几个方法使你能用于向浏览器回送输出结果。
     pageContext表示一个javax.servlet.jsp.PageContext对象。它是用于方便存取各种范围的名字空间、servlet相关的对象的API,并且包装了通用的servlet相关功能的方法。
     session表示一个请求的javax.servlet.http.HttpSession对象。Session可以存贮用户的状态信息
     applicaton 表示一个javax.servle.ServletContext对象。这有助于查找有关servlet引擎和servlet环境的信息
     config表示一个javax.servlet.ServletConfig对象。该对象用于存取servlet实例的初始化参数。
     page表示从该页面产生的一个servlet实例

    40、什么情况下调用doGet()和doPost()?
     Jsp页面中的form标签里的method属性为get时调用doGet(),为post时调用doPost()。

    41、JSP和Servlet有哪些相同点和不同点,他们之间的联系是什么?
     JSP 是Servlet技术的扩展,本质上是Servlet的简易方式,更强调应用的外表表达。JSP编译后是”类servlet”。Servlet和JSP最主要的不同点在于,Servlet的应用逻辑是在Java文件中,并且完全从表示层中的HTML里分离开来。而JSP的情况是Java和HTML可以组合成一个扩展名为.jsp的文件。JSP侧重于视图,Servlet主要用于控制逻辑。

    42、四种会话跟踪技术
     会话作用域ServletsJSP 页面描述
     page否是代表与一个页面相关的对象和属性。一个页面由一个编译好的 Java servlet 类(可以带有任何的 include 指令,但是没
     有 include 动作)表示。这既包括 servlet 又包括被编译成 servlet 的 JSP 页面
     request是是代表与 Web 客户机发出的一个请求相关的对象和属性。一个请求可能跨越多个页面,涉及多个 Web 组件(由于
     forward 指令和 include 动作的关系)
     session是是代表与用于某个 Web 客户机的一个用户体验相关的对象和属性。一个 Web 会话可以也经常会跨越多个客户机请求
     application是是代表与整个 Web 应用程序相关的对象和属性。这实质上是跨越整个 Web 应用程序,包括多个页面、请求和会话的 一个全局作用域

    43、Servlet执行时一般实现哪几个方法?
     public void init(ServletConfig config)
     public ServletConfig getServletConfig()
     public String getServletInfo()
     public void service(ServletRequest request,ServletResponse response)
     public void destroy()
     init ()方法在servlet的生命周期中仅执行一次,在服务器装载servlet时执行。缺省的init()方法通常是符合要求的,不过也可以
     根据需要进行 override,比如管理服务器端资源,一次性装入GIF图像,初始化数据库连接等,缺省的inti()方法设置了servlet的
     初始化参数,并用它的ServeltConfig对象参数来启动配置,所以覆盖init()方法时,应调用super.init()以确保仍然执行这些任务
     。
     service ()方法是servlet的核心,在调用service()方法之前,应确保已完成init()方法。对于HttpServlet,每当客户请求一个
     HttpServlet对象,该对象的service()方法就要被调用,HttpServlet缺省的service()方法的服务功能就是调用与 HTTP请求的方法
     相应的do功能,doPost()和doGet(),所以对于HttpServlet,一般都是重写doPost()和doGet() 方法。
     destroy()方法在servlet的生命周期中也仅执行一次,即在服务器停止卸载servlet时执行,把servlet作为服务器进程的一部分关闭
     。缺省的destroy()方法通常是符合要求的,但也可以override,比如在卸载servlet时将统计数字保存在文件中,或是关闭数据库连接。
     getServletConfig()方法返回一个servletConfig对象,该对象用来返回初始化参数和servletContext。servletContext接口提供有
     关servlet的环境信息。
     getServletInfo()方法提供有关servlet的信息,如作者,版本,版权。

    44、j2ee常用的设计模式?说明工厂模式。
     Java中的23种设计模式:
     Factory(工厂模式), Builder(建造模式), Factory Method(工厂方法模式),
     Prototype(原始模型模式),Singleton(单例模式), Facade(门面模式),
     Adapter(适配器模式), Bridge(桥梁模式), Composite(合成模式),
     Decorator(装饰模式), Flyweight(享元模式), Proxy(代理模式),
     Command(命令模式), Interpreter(解释器模式), Visitor(访问者模式),
     Iterator(迭代子模式), Mediator(调停者模式), Memento(备忘录模式),
     Observer(观察者模式), State(状态模式), Strategy(策略模式),
     Template Method(模板方法模式), Chain Of Responsibleity(责任链模式)
     工厂模式:工厂模式是一种经常被使用到的模式,根据工厂模式实现的类可以根据提供的数据生成一组类中某一个类的实例,通常这一组类有一个公共的抽象父类并且实现了相同的方法,但是这些方法针对不同的数据进行了不同的操作。首先需要定义一个基类,该类的子类通过不同的方法实现了基类中的方法。然后需要定义一个工厂类,工厂类可以根据条件生成不同的子类实例。当得到子类的实例后,开发人员可以调用基类中的方法而不必考虑到底返回的是哪一个子类的实例。

    45、JAVA语言如何进行异常处理,关键字:throws,throw,try,catch,finally分别代表什么意义?在try块中可以抛出异常吗?
     Java 通过面向对象的方法进行异常处理,把各种不同的异常进行分类,并提供了良好的接口。在Java中,每个异常都是一个对象,它是Throwable类或其它子类的实例。当一个方法出现异常后便抛出一个异常对象,该对象中包含有异常信息,调用这个对象的方法可以捕获到这个异常并进行处理。Java的异常处理是通过5个关键词来实现的:try、catch、throw、throws和finally。一般情况下是用try来执行一段程序,如果出现异常,系统会抛出(throws)一个异常,这时候你可以通过它的类型来捕(catch)它,或最后(finally)由缺省处理器来处理。
     用try来指定一块预防所有”异常”的程序。紧跟在try程序后面,应包含一个catch子句来指定你想要捕捉的”异常”的类型。
     throw语句用来明确地抛出一个”异常”。
     throws用来标明一个成员函数可能抛出的各种”异常”。
     Finally为确保一段代码不管发生什么”异常”都被执行一段代码。
     可以在一个成员函数调用的外面写一个try语句,在这个成员函数内部写另一个try语句保护其他代码。每当遇到一个try语句,”异常“的框架就放到堆栈上面,直到所有的try语句都完成。如果下一级的try语句没有对某种”异常”进行处理,堆栈就会展开,直到遇到有处理这种”异常”的try语句。

    46、MVC的各个部分都有那些技术来实现?如何实现?
     MVC 是Model-View-Controller的简写。”Model” 代表的是应用的业务逻辑(通过JavaBean,EJB组件实现), “View” 是应用的表示面,用于与用户的交互(由JSP页面产生),”Controller” 是提供应用的处理过程控制(一般是一个Servlet),通过这种设计模型把应用逻辑,处理过程和显示逻辑分成不同的组件实现。这些组件可以进行交互和重用。
     model层实现系统中的业务逻辑,view层用于与用户的交互,controller层是model与view之间沟通的桥梁,可以分派用户的请求并选择恰当的视图以用于显示,同时它也可以解释用户的输入并将它们映射为模型层可执行的操作。

    47、java中有几种类型的流?JDK为每种类型的流提供了一些抽象类以供继承,请说出他们分别是哪些类?
     字节流,字符流。字节流继承于InputStream OutputStream,字符流继承于InputStreamReader OutputStreamWriter。在java.io包中还有许多其他的流,主要是为了提高性能和使用方便。

    48、java中实现多态的机制是什么?
     方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现,重载
     Overloading是一个类中多态性的一种表现。

    49、静态变量和实例变量的区别?
     static i = 10; //常量
     class A a; a.i =10;//可变

    50、在JAVA中,如何跳出当前的多重嵌套循环?
     用break; return 方法。

    51、List、Map、Set三个接口,存取元素时,各有什么特点?
     List 以特定次序来持有元素,可有重复元素。Set 无法拥有重复元素,内部排序。Map 保存key-value值,value可多值。

    52、数据库事务的四大特性(ACID)

    原子性:整个事务中所有操作,要么全部完成,要么全部不完成,不可能停留在中间的某个环节。如果事务在执行的过程中遇到错误,会被回滚(Rollback)到事务的开始前的状态。

    一致性:在事务开始之前和结束之后,数据库的完整约束性不会被破坏。

    隔离性:如果有两个事务,运行在相同的时间内,执行相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。这种属性有时称为串行化,为了防止事务操作时间的混淆,必须串行化或序列化请求,使得在同一时间仅有一个请求用于同一数据。

    持久性:在事务完成以后,该事务对数据库所作的更改便持久的保存在数据库之中。

     

    展开全文
  • Java综合中级面试题

    万次阅读 2020-07-17 11:18:55
    大公司最喜欢问的Java集合类面试题40个Java集合面试问题和答案 java.util.Collections 是一个包装类。它包含有各种有关集合操作的静态多态方法。 java.util.Collection 是一个集合接口。它提供了对集合对象进行基本...
  • Java面试题全集(下)

    万次阅读 多人点赞 2015-04-15 08:55:56
    这部分主要是开源Java EE框架方面的内容,包括Hibernate、MyBatis、Spring、Spring MVC等,由于Struts 2已经是明日黄花,在这里就不讨论Struts 2的面试题。此外,这篇文章还对企业应用架构、大型网站架构和应用...
  • Java基础面试题整理

    万次阅读 多人点赞 2019-02-08 09:11:37
    面向对象的三个特征 封装,继承,多态.这个应该是人人皆知.有时候也会加上抽象. 多态的好处 允许不同类对象对同一消息做出响应,即同一消息可以根据发送对象的不同而采用多种不同的行为方式(发送消息就是函数调用)....
  • Java面试题全集(上)

    万次阅读 多人点赞 2016-12-28 22:56:50
    2013年年底的时候,我看到了网上流传的一个叫做《Java面试题大全》的东西,认真的阅读了以后发现里面的很多题目是重复且没有价值的题目,还有不少的参考答案也是错误的,于是我花了半个月时间对这个所谓的《Java面试...
  • java面试题大全(整理版)

    万次阅读 多人点赞 2018-03-05 19:12:11
    这几天在网上搜集各种java面试题:一是为了自己能复习方便,二是为了分享给大家~~题目都是来自网上大佬的分享,感谢大佬们的贡献~~(持续更新中...)1、面向对象的特征有哪些方面?- 抽象:抽象是将一类对象的共同...
  • Java 最常见的 200+ 面试题:面试必备

    万次阅读 多人点赞 2020-09-17 23:01:58
    这份面试清单是从我 2015 年做了 TeamLeader 之后开始收集的,一方面是给公司招聘用,另一方面是想用它来挖掘在 Java 技术栈中,还有那些知识点是我不知道的,我想找到这些技术盲点,然后修复它,以此来提高自己的...
  • Java面试笔试题大汇总一(最全+详细答案)

    万次阅读 多人点赞 2019-06-26 10:11:24
    本篇文章内容过多,只能分成两部分: 汇总一:... ... 2013年年底的时候,我看到了网上流传的一个叫做《Java面试题大全》的东西,认真的阅读了以后发现里面的很...
  • java面试题大全

    万次阅读 多人点赞 2020-10-23 12:02:43
    过完年,又有大批人要换工作了,这里整理了很全的java面试笔试题,希望对大家有所帮助! 面试题部分! SSH框架面试题集锦 网易2017春招笔试真题编程题集合题解 面试进行曲之技术面试(项目经验) ...
  • Java面试题内容聚合

    万次阅读 多人点赞 2019-12-04 14:08:10
    这是一份常见Java面试题分类汇总,希望对大家有用! 初级面试题 Java面试题-基础篇一 Java面试题-基础篇二 Java面试题-集合框架篇三 Java面试题-基础篇四 Java面试题-基础篇五 Java面试题-javaweb篇六 ...
  • 中科软java笔试题

    千次阅读 2014-03-21 18:41:17
    中科软java笔试题
  • java面试笔试资料 百度网盘

    千次阅读 2016-10-04 11:50:24
    面试宝典:微软、谷歌、百度、腾讯等各大公司笔试面试题整理全版 /面试宝典:微软、谷歌、百度、腾讯等各大公司笔试面试题整理全版 分享时间:2014-11-07 09:01分享用户:东东***07文件大小:未知文件类型:文件夹 ...
  • Java面试题阶段汇总

    千次阅读 多人点赞 2018-10-17 10:49:44
    希望能够坚持不断的整理,做最全的Java面试题题库,帮助更多的人在面试过程中发挥出自己的实力。也希望自己能够持之以恒的做一件事情不忘初心,加油!   初级面试题   Java面试题-基础篇一 Java面试题-基础篇...
  • 【面试】——Java面试题内容总结

    千次阅读 多人点赞 2019-09-21 12:12:39
    往期内容聚合 设计模式内容聚合 ...Java面试中遇到的坑【填坑篇】 Java面试中遇到的坑【篇二】 java面试遇到的坑[第三期] java面试填坑解惑篇[三] java面试遇到的坑[第四期] 面试官:你分析...
  • java算法大全_java经典算法_算法面试题大全含答案

    万次阅读 多人点赞 2019-05-16 09:44:18
    3、java笔试手写算法面试题大全含答案 4、java递归算法练习:使用递归算法写个程序计算n! 5、JVM的常见垃圾回收算法 6、《java算法大全》第一期 7、《java算法大全》第三期 8、《java算法大全》第二期 9、《java...
  • 刷题、面试必备网站(java)

    万次阅读 2019-04-11 09:24:28
    整理的一些刷题面试的网站,做一个汇总,分久必合 一. 刷题 LeetCode 牛客网 ...剑指offer第二部 系列: 剑指offer原书第二版的java实现 剑指offer第二版面试题-Java描述-持续更新 二. 面试 ...
  • Java面试,如何在短时间内做突击

    千次阅读 多人点赞 2019-08-14 12:48:58
    这里整理了很多常考面试题,希望对你有帮助。 面试技术文 Java岗 面试考点精讲(基础篇01期) Java岗 面试考点精讲(基础篇02期) Java岗 面试考点精讲(网络篇03期) Java 面试中遇到的坑 Java面试中遇到的...
1 2 3 4 5 ... 20
收藏数 204,141
精华内容 81,656
关键字:

java面试题