JAVA基础总结【面试】

前言

  近间陆续面试了很多的求职的前(JAVA)、后(WEB)端开发人员,包括实习生、应届毕业生、一两年工做经验的、也有三四年工做经验的,也算见过了比较多的开发人员,想在这里作个总结,本次主要讲一讲面试和后端(java)相关的东西;html

关于面试准备

  先推荐一个写的不错的博客,专门关于面试的,比较详尽仔细: 关于面试。我在这里简单总结几点:
  一、简历要用心准备好,我的信息,特别是联系方式必定要清晰明确,自身掌握的技能要完成清晰,项目经历最好按照时间顺序,说明本人在项目中的职责,完成的工做,有什么样的提高或收获;
  二、通常面试流程是电面=》HR现场面=》技术面=》结果,并非每个面试结果就能立马有结果,因此当面试官说回去等消息的时候,并不表明没有机会,有时候须要讨论筛选才能最终肯定人选。
  三、关于自我介绍,最好简明扼要,能体现自身的特色,表达流畅、自信,提早最好准备;
  四、准备好扎实的基础知识,以及对经历过的项目要有足够的认识,每个项目都是一次学习、提高的机会,通常JAVA集合类是考察的重点;
  五、通常好一点的面试官会顺着知识点逐渐深刻或者逐渐扩展,因此对于知识点的掌握最好全面深刻,不要蜻蜓点水式的学习;
  六、当遇到一些设计类的问题时,通常面试官考察的是你的思路,对问题的应变能力,对于事物观察的点;

JAVA基础(答案仅供参考,若有不对之处请批评指正)

   一、HashMap源码,实现原理,JDK8之后对HashMap作了怎样的优化。
  答:HashMap是基于哈希表的Map接口的非同步实现,提供全部可选的映射操做,并容许使用null值和null键,不保证映射的顺序;HashMap是一个“链表散列”的数据结构,即数组和链表的结合体;它的底层就是一个数组结构,数组中的每一项又是一个链表,每当新建一个HashMap时,就会初始化一个数组;
  而在JDK8中引入了红黑树的部分,当存入到数组中的链表长度大于(默认)8时,即转为红黑树;利用红黑树快速增删改查的特色提升HashMap的性能,其中会用到红黑树的插入、删除、查找等算法。本文再也不对红黑树展开讨论,想了解更多红黑树数据结构的工做原理能够参考 http://blog.csdn.net/v_july_v/article/details/6105630
 
   二、HashMap的扩容是怎样扩容的,为何都是2的N次幂的大小。
  答:能够参考上文  JAVA8系列之从新认识HashMap  有详细的讲解
 
   三、HashMap,HashTable,ConcurrentHashMap的区别
  答:   

  a、HashMap是非线程安全的,HashTable是线程安全的。前端

  b、HashMap的键和值都容许有null值存在,而HashTable则不行。java

  c、由于线程安全的问题,HashMap效率比HashTable的要高。面试

  HashMap:它根据键的hashCode值存储数据,大多数状况下能够直接定位到它的值,于是具备很快的访问速度,但遍历顺序倒是不肯定的。 HashMap最多只容许一条记录的键为null,容许多条记录的值为null。HashMap非线程安全,即任一时刻能够有多个线程同时写HashMap,可能会致使数据的不一致。若是须要知足线程安全,能够用 Collections的synchronizedMap方法使HashMap具备线程安全的能力,或者使用ConcurrentHashMap。
   Hashtable:Hashtable是遗留类,不少映射的经常使用功能与HashMap相似,不一样的是它承自Dictionary类,而且是线程安全的,任一时间只有一个线程能写Hashtable,并发性不如ConcurrentHashMap,由于ConcurrentHashMap引入了分段锁。
 
   四、极高并发下HashTable和ConcurrentHashMap哪一个性能更好,为何,如何实现的。
  答:固然是ConcurrentHashMap,由于ConcurrentHashMap引入了分段锁,而HashTable则使用的是方法级别的锁;所以在新版本中通常不建议使用HashTable,不须要线程安全的场合可使用HashMap,而须要线程安全的场合可使用ConcurrentHashMap;
 
   五、HashMap在高并发下若是没有处理线程安全会有怎样的隐患,具体表现是什么。
  答:可能形成死循环,具体表现链表的循环指向;
 
   六、JAVA中四种修饰符的限制范围。
  private:修饰的成员只能在同类中别访问,而在同包、子类和其余包中都不能被访问
  public:修饰的成员在同类、同包、子类(继承自本类)、其余包均可以访问
  protected:修饰的成员在同类、同包、子类中能够访问,其余包中不能被访问
  default:修饰的成员在同类、同包中能够访问,但其余包中无论是否是子类都不能被访问
 
   七、Object中的方法
  构造函数
  hashCode():用户获取对象的hash值,用于检索
  queals():用于确认两个对象是否相等;补充,哈希值相同的对象不必定equals(),但equals()的两个对象,hash值必定相等
  toString():返回一个String对象,用来标识本身
  getClass():返回一个class对象,打印的格式通常为  class package.name.xxx,常常用于java的反射机制
  clone():用来另存一个当前存在的对象
  finalize():垃圾回收的时候回用到,匿名对象回收以前会调用到
  wait():用于让当前线程失去操做权限,当前线程进入等待序列
  wait(long)、wait(long,int):用户设定下一次获取锁的距离当前释放锁的间隔时间
  notify():用于随机通知一个持有对象锁的线程获取操做的权限
  notifyAll():用于通知全部持有对象锁的线程获取操做权限
 
   八、接口和抽象类的区别 
  答:一个类能够实现多个接口,但只能继承一个抽象类;抽象类能够包含具体的方法,接口全部的方法都是抽象的(JDK8开始新增功能接口中有default方法);抽象类能够声明和使用字段,接口则不能,但能够建立静态的final常量;抽象类的方法能够是protected、public、private或者默认的package,接口的方法都是public;抽象类能够定义构造函数,接口不能;接口被声明为public,省略后,包外的类不能访问接口;
 
   九、动态代理的两种方式,以及区别
  答:jdk动态代理和cglib动态代理;
  JDK动态代理只能对实现了接口的类生成代理,而不能针对类;cglib是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,由于是继承,因此该类或方法最好不要声明称final,final能够阻止继承和多态;
  
   十、java序列化的方式
  答:实现Serializable接口、实现Externalizable接口(通常只但愿序列化一部分数据,其余数据都使用transient修饰的话有点麻烦,这时候可使用externalizable接口,指定序列化的属性)
 
   十一、传值和传引用的区别,java是怎么样的,有没有传值传引用
  答:首先,java中是没有指针的,只存在值传递;而咱们常常看到对于对象的传递彷佛有点像引用传递,能够改变对象中的某个属性的值,请不要被这个假象蒙蔽了双眼,实际上这个传入函数的值是对象引用的拷贝,即传递的是引用的地址值,因此仍是按值传递;
  传值调用时,改变的是形参的值,并无改变实参的值,实参的值能够传递给形参,可是这个传递是单向的,形参不能传递会实参;
  传引用调用时,若是参数是对象,不管是对象作了何种操做,都不会改变实参对象的引用,可是若是改变了对象的内容,就会改变实参对象的内容;
 
   十二、@transactional注解在什么状况下会失效,为何。
  答:一个目标对象的方法调用改目标对象的另一个方法时,即便被调用的方法已使用了@Transactional注解标记,事务也不会有效执行;Spring的官方说明在代理下(默认或者配置为proxy-targer-class="true"),只有当前代理类的外部方法调用注解方法时代理才会被拦截。

数据结构和算法

  一、B+树redis

  参考:B+树介绍算法

  二、八大排序算法sql

  参考:八大排序算法JAVA实现数据库

   三、一致性Hash算法,一致性Hash算法的应用
  答:一致性hash算法是一个负载均衡算法,能够用在分布式缓存、数据库的分库分表等场景,还能够应用在负载均衡器中做为负载均衡算法。在多台服务器时,对于某个请求资源经过hash算法,映射到某一台服务器,当增长或者减小一台服务器时,可能会改变这些资源对应的hash值,这样可能致使一部分缓存或者数据的丢失。一致性hash就是尽量在将同一个资源请求到同一台服务器中;

JVM

  一、JVM的内存结构编程

  答:主要分为三大块 堆内存、方法区、栈;栈又分为JVM栈、本地方法栈segmentfault

    堆(heap space),堆内存是JVM中最大的一块,有年轻代和老年代组成,而年轻代又分为三分部分,Eden区,From Survivor,To Survivor,默认状况下按照8:1:1来分配

    方法区(Method area),存储类信息、常量、静态变量等数据,是线程共享的区域

    程序计数器(Program counter Register),是一块较小的内存空间,是当前线程所执行的字节码的行号指示器

    JVM栈(JVM stacks),也是线程私有的,生命周期与线程相同,每一个方法被执行时都会建立一个栈帧,用于存储局部变量表、操做栈、动态连接、方法出口等信息

    本地方法栈(Native Mthod Stacks),为虚拟机使用的native方法服务

  二、关于垃圾回收和常见的GC算法,请参考:GC专家系列-理解java垃圾回收

多线程

  一、JAVA实现多线程的几种方式

  a、继承Thread类实现

public class MyThread extends Thread {  
  public void run() {  
   System.out.println("MyThread.run()");  
  }  
}  

MyThread myThread1 = new MyThread();  
MyThread myThread2 = new MyThread();  
myThread1.start();  
myThread2.start();  

  b、实现Runnable接口

  若是本身的类已经extends另外一个类,就没法直接extends Thread,此时,必须实现一个Runnable接口,以下:
public class MyThread extends OtherClass implements Runnable {  
  public void run() {  
   System.out.println("MyThread.run()");  
  }  
}  

MyThread myThread = new MyThread();  
Thread thread = new Thread(myThread);  
thread.start();  

  c、使用ExecutorService、Callable、Future实现有返回结果的多线程

import java.util.concurrent.*;  
import java.util.Date;  
import java.util.List;  
import java.util.ArrayList;  
  
/** 
* 有返回值的线程 
*/  
@SuppressWarnings("unchecked")  
public class Test {  
public static void main(String[] args) throws ExecutionException,  
    InterruptedException {  
   System.out.println("----程序开始运行----");  
   Date date1 = new Date();  
  
   int taskSize = 5;  
   // 建立一个线程池  
   ExecutorService pool = Executors.newFixedThreadPool(taskSize);  
   // 建立多个有返回值的任务  
   List<Future> list = new ArrayList<Future>();  
   for (int i = 0; i < taskSize; i++) {  
    Callable c = new MyCallable(i + " ");  
    // 执行任务并获取Future对象  
    Future f = pool.submit(c);  
    // System.out.println(">>>" + f.get().toString());  
    list.add(f);  
   }  
   // 关闭线程池  
   pool.shutdown();  
  
   // 获取全部并发任务的运行结果  
   for (Future f : list) {  
    // 从Future对象上获取任务的返回值,并输出到控制台  
    System.out.println(">>>" + f.get().toString());  
   }  
  
   Date date2 = new Date();  
   System.out.println("----程序结束运行----,程序运行时间【"  
     + (date2.getTime() - date1.getTime()) + "毫秒】");  
}  
}  
  
class MyCallable implements Callable<Object> {  
private String taskNum;  
  
MyCallable(String taskNum) {  
   this.taskNum = taskNum;  
}  
  
public Object call() throws Exception {  
   System.out.println(">>>" + taskNum + "任务启动");  
   Date dateTmp1 = new Date();  
   Thread.sleep(1000);  
   Date dateTmp2 = new Date();  
   long time = dateTmp2.getTime() - dateTmp1.getTime();  
   System.out.println(">>>" + taskNum + "任务终止");  
   return taskNum + "任务返回运行结果,当前任务时间【" + time + "毫秒】";  
}  
}  

   二、Callable和Future

  答:Callable接口相似于Runnable,可是Runnable不会返回结果,而且没法抛出返回结果的异常,而Callable更强大,被线程执行之后,能够返回值,这个返回值就是经过Future拿到,也就是说,Future能够拿到异步执行任务的返回值,能够看如下例子: 

import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class Test {
    
    public static void main(String[] args) {
        Callable<Integer> callable = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                return new Random().nextInt(100);
            }        
        };
        FutureTask<Integer> futureTask = new FutureTask<Integer>(callable);
        new Thread(futureTask).start();
        try {
            Thread.sleep(1000);
            System.err.println(futureTask.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

ExecutorService继承自Executor,目的是为咱们管理Thread对象,从而简化并发变成,Executor使咱们无需显示的去管理线程的声明周期,是JDK5以后启动任务的首选方式。

执行多个带返回值的任务,并取得多个返回值,代码以下:

import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CallableAndFuture {
    
    public static void main(String[] args) {
        ExecutorService threadPool = Executors.newCachedThreadPool();
        CompletionService<Integer> cs = new ExecutorCompletionService<Integer>(threadPool);
        for( int i = 0; i < 5; i++ ){
            final int taskId = i;
            cs.submit(new Callable<Integer>() {
                @Override
                public Integer call() throws Exception {
                    return taskId;
                }
            });
        }
        
        for( int i = 0; i < 5; i++ ){
            try {
                System.err.println(cs.take().get());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

  

  三、线程池的参数有哪些,在线程池建立一个线程的过程

  corePoolSize:核心线程数,可以同时执行的任务数量

  maximumPoolSize:除去缓冲队列中等待的任务,最大能容纳的任务数(其实就是包括了核心线程池的数量)

  keepAliveTime:超出workQueue的等待任务的存活时间,就是指maximumPoolSize里面的等待任务的存活等待时间

  unit:时间单位

  workQueue:阻塞等待线程的队列,通常使用new LinkedBlockingQueue()这个,若是不指定容量,会一直往里添加,没有限制,workQueue永远不会满,通常选择没有容量上限的队列

  threadFactory:建立线程的工厂,使用系统默认的类

  handler:当任务数超过maximumPoolSize时,对任务的处理策略,默认策略是拒绝添加

  执行流程:当线程数小于corePoolSize时,每添加一个任务,则当即开启线程执行;当corePoolSize满的时候,后面添加的任务将放入缓冲队列workQueue等待;当workQueue满的时候,看是否超过maximumPoolSize线程数,若是超过,则拒绝执行,若是没有超过,则建立线程理解执行;  

 1 import java.util.concurrent.Executors;
 2 import java.util.concurrent.LinkedBlockingQueue;
 3 import java.util.concurrent.ThreadPoolExecutor;
 4 import java.util.concurrent.TimeUnit;
 5 
 6 /**
 7  * 对线程池进行管理和封装
 8  * @author guoqing
 9  *
10  */
11 public class ThreadPoolManager {
12     
13     private static ThreadPoolManager mInstance = new ThreadPoolManager();
14     private ThreadPoolExecutor executor;
15     
16     private int corePoolSize;    //核心线程池数量,表示可以同时执行的任务数量
17     private int maximumPoolSize;    //最大线程池数量,实际上是包含了核心线程池数量在内的
18     private long keepAliveTime = 1;        //存活时间,表示最大线程池中等待任务的存活时间
19     private TimeUnit unit = TimeUnit.HOURS;        //存活时间的时间单位
20     
21     public static ThreadPoolManager getInstance() {
22         return mInstance;
23     }
24     
25     private ThreadPoolManager() {
26         //核心线程数量的计算规则:当前设备的可用处理器核心数*2+1,可以让cpu获得最大效率的发挥
27         corePoolSize = Runtime.getRuntime().availableProcessors()*2+1;
28         maximumPoolSize = corePoolSize;    //虽然用不到,可是不能为0,不然会报错
29         //线程池机制:领工资的机制
30         executor = new ThreadPoolExecutor(corePoolSize, 
31                 maximumPoolSize, 
32                 keepAliveTime, 
33                 unit, 
34                 new LinkedBlockingQueue<Runnable>(),    //缓冲队列,超出核心线程池的任务会被放入缓冲队列中等待
35                 Executors.defaultThreadFactory(),        //建立线程的工厂类
36                 new ThreadPoolExecutor.AbortPolicy()    //当最大线程池也超出的时候,则拒绝执行
37                 );    
38     }
39     
40     /**
41      * 往线程池中添加任务
42      * @param r
43      */
44     public void executor(Runnable r) {
45         if(r!=null) {
46             executor.execute(r);
47         }
48     }
49     
50     /**
51      * 从线程池中移除任务
52      * @param r
53      */
54     public void remove(Runnable r) {
55         if(r!=null) {
56             executor.remove(r);
57         }
58     }
59 }

 

  四、volatile关键字的做用,原理

  答:保证内存可见性和禁止指令重排。实现原理可参考:JAVA并发变成--valatile关键字剖析

 

  五、synchronized关键字的用法,优缺点

  答:java关键字,当它用来修饰一个方法或者代码块的时候,可以保证在同一时刻最多只有一个线程执行该代码段的代码;

    synchronized修饰的方法或者对象,只能以同步的方式执行,会引发性能问题;没法中断一个正在等候得到锁的线程,也没法经过投票得到锁;一个优先级高的线程等待一个优先级低的线程释放锁会致使优先级倒置,引发性能风险;

  

  六、Lock接口有哪些实现类,使用场景是什么

  答:Lock接口有三个实现类,一个是ReentrantLock,另两个是ReentrantReadWriteLock类中的两个静态内部类ReadLock和WriteLock。

  使用场景:通常应用于多度少写,由于读的线程之间没有竞争,因此比起synchronzied,性能要好不少;

   
   七、悲观锁、乐观锁的优缺点,CAS有什么缺陷,该如何解决
  悲观锁:老是假设最坏的状况,每次去拿数据的时候都认为别人会修改,因此每次拿数据的时候都会上锁,这样别人拿数据的时候就会阻塞知道它拿到锁;好比关系型数据库的行锁、表锁、读锁、写锁;好比java里面的同步原语synchronized关键字的实现也是悲观锁;
  乐观锁:每次去拿数据的时候都认为别人不会修改,因此不会上锁,可是在更新的时候会判断一下再次期间别人有没有更新这个数据。乐观锁适用于多读的应用类型,能够提升吞吐量。java中java.util.conncurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的;
  CAS:CAS是乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其余线程都失败,失败的线程不会被挂起,而是被告知此次竞争失败,并能够再次尝试;
  CAS的缺陷:ABA问题、循环时间长开销大,只能保证一个共享变量的原子操做;
  
   八、ABC三个线程如何保证顺序执行
  答:用Thread.join() 方法,或者线程池newSingleThreadExecutor(原理是会将全部线程放入一个队列,而队列则保证了FIFO),也能够经过ReentrantLock,state整数用阿里判断轮到谁来执行
 
   九、线程的状态都有哪些(五大状态)
  新建状态(new):当用new操做符建立一个线程时,如new Thread(),线程尚未开始运行,此时处于仙剑状态;
  就绪状态(runnable):一个新建立的线程并不自动开始运行,要执行线程,必需要调用线程的start()方法,当线程对象调用start()方法即启动了线程,start()方法建立线程运行的系统资源,并调度线程运行run()方法。当start()方法返回后,线程就处于就绪状态;
  运行状态(running):当线程得到cpu时间后,他才进入运行状态,真正开始实行run()方法
  阻塞状态(blocked):当线程运行过程当中,可能因为各类缘由进入阻塞状态;
    a.线程经过调用sleep方法进入睡眠状态
    b.线程调用一个在I/O上被阻塞的操做,即该操做在输入输出操做完成以前不会返回到它的调用者
    c.线程试图获得一个锁,而该锁正被其余线程持有
    d.线程正等待某个触发条件
  死亡状态(dead):run方法天然退出而天然死亡,或者一个未捕获的异常终止了run方法而使线程猝死
  

 

  十、sleep和wait的区别

  答:首先,sleep()方法属于Thread类的,而wait()方法是属于Object类的;sleep()方法致使了程序暂停执行指定的时间,让出cpu给其余线程,可是他的监控状态依然保持,当指定的时间到了又自动回恢复运行状态,调用了sleep()方法的过程当中,线程不会释放对象锁;而当调用了wait()方法的时候,线程回放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备。

 
   十一、notify()和notifyAll()的区别
  答:notify()方法表示,当前线程已经放弃对资源的占有,通知等待的线程来获取对资源的占有权,可是只有一个线程可以从wait状态中恢复;notifyAll()方法表示,当前的线程已经放弃对资源的占有,通知全部的等待线程从wait()方法后的语句开始执行,但最终只有一个线程能竞争得到锁并执行;notify()是对notifyAll()的一个优化,
 
    十二、ThreadLocal的了解,实现原理。
   答:ThreadLocal,线程本地变量。定义了一个ThreadLocal,每一个线程往这个ThreadLocal中读写都是线程隔离的,互相之间不会影响,他提供了一种将可变数据经过每一个线程有本身的独立副本从而实现线程封闭的机制;实现的思路,Thread类有一个类型为ThreadLocal.ThreadLocalMap的实例变量threadLocals,也就是说每一个线程都有一个本身的ThreadLocalMap。ThreadLocalMap有本身的独立实现,能够简单的将它的key视做ThreadLocal,value为代码中放入的值(实际上key并非ThreadLocal本省,而是它的一个弱引用)。每一个线程在往ThreadLocal里set值的时候,都会往本身的ThreadLocalMap里存,读也是已某个ThreadLocal做为引用,在本身的map里找对应的key,从而实现了线程的隔离。若是想详细了解,能够参考: ThreadLocal源码解读

数据库相关

  一、常见的数据库优化手段

  答:库表优化,表设计合理化,符合三大范式;添加适当的索引(普通索引、主键索引、惟一索引、全文索引);分库分表;读写分离等;sql语句优化,定位执行效率低,慢sql的语句,经过explain分析低效率的缘由;

 

  二、索引的优缺点,什么字段上创建索引

  答:优势方面:第一,经过建立惟一索引能够保证数据的惟一性;第二,能够大大加快数据的检索速度,是主要目的;第三;在使用分组和排序子句进行数据检索时,能够显著减小查询中分组和排序的时间;第四,能够在查询中使用优化隐藏器,提升系统的性能;

  缺点方面:第一,建立索引和维护索引要耗费时间,而且随着数据量的增长而增长;第二,每个索引须要占用额外的物理空间,须要的磁盘开销更大;第三,当对表中的数据进行增长、删除、修改操做时,索引也要动态维护,下降了数据的维护速度;

  通常来讲,在常常须要搜索的列上,强制该列的惟一性和组织表中数据的排列结构的列,在常常用在连接的列上,在常常须要排序的列上,在常用在where字句的列上能够添加索引,以提高查询速度;一样,对于一些甚少使用或者参考的列,只有不多数值的列(如性别),定义为text,image,bit的列,修改性能远远大于检索性能的列不适合添加索引;
 
   三、数据库链接池
  答:数据库链接池(Connection pooling)是程序启动时创建足够的数据库链接,并将这些链接组成一个链接池,由程序动态的对池中的链接进行申请、使用、释放;
  (1)程序初始化时建立链接池
  (2)使用时向链接池申请可用链接
  (3)使用完毕,将链接返还给链接池
  (4)程序退出时,断开全部的链接,并释放资源

计算机网络

  一、TCP和UDP的区别

  答:TCP(传输控制协议),UDP(用户数据报协议)

  (1)TCP面向链接(如打电话先拨号创建链接);UDP是无链接的,即发送数据以前不须要创建链接;

  (2)TCP提供可靠的服务。也就是说,经过TCP链接传送的数据,无差错,不丢失,不重复,且按序达到;UDP尽最大努力交付,即不保证可靠交付;

  (3)TCP面向字节流,其实是TCP把数据当作一连串无结构的字节流;UDP是面向报文,UDP没有拥塞控制,所以网络出现拥塞不会使源主机的发送速率下降(对实时应用颇有用,如IP电话,实时视频会议等)

  (4)每一条TCP链接只能是点到点的,UDP支持一对一,一对多,多对一和多对多的交互通讯;

  (5)TCP首部开销20字节,UDP首部开销8字节;

  (6)TCP的逻辑通讯信道是全双工的可靠信道,DUP则是不可靠信道;

 
   二、三次握手,四次挥手,为何要四次挥手。
  答:三次握手的目的是创建可靠的通讯信道,简单来讲就是数据的发送与接收,主要目的是双方确认本身与对方的发送和接收机能正常;    
    第一次握手:Client什么都不能确认,Server确认了对方发送正常;
    第二次握手:Clent确认了,本身发送、接收正常,对方发送、接收正常;Server确认了本身接收正常,对方发送正常;
    第三次握手:Clent确认了,本身发送、接收正常,对方发送、接收正常;Server确认了本身发送、接收正常,对方发送、接收正常;
  因此,通过三次握手以后,就能确认双方收发功能都正常;

  四次挥手:

    A:“喂,我不说了 (FIN)。”A->FIN_WAIT1

    B:“我知道了(ACK)。等下,上一句还没说完。Balabala…..(传输数据)”B->CLOSE_WAIT | A->FIN_WAIT2

    B:”好了,说完了,我也不说了(FIN)。”B->LAST_ACK

    A:”我知道了(ACK)。”A->TIME_WAIT | B->CLOSED

    A等待2MSL,保证B收到了消息,不然重说一次”我知道了”,A->CLOSED

  

  三、长链接和短链接。

  短链接:链接=》传输数据=》关闭链接

  HTTP是无状态的,浏览器和服务器之间每进行一次http操做,就创建一次链接,但任务结束就中断链接;也能够理解为短链接是指socket链接后,发送接收完数据立刻断开链接;

  长链接:链接=》传输数据=》保持链接=》传输数据=》。。。=》关闭链接

  长链接指创建socket链接后无论是否使用都保持链接,但安全性较差;

 设计模式

  此处推荐阅读:java23种设计模式 深刻理解

  一、单例模式的几种写法

  懒汉模式

public class Singleton {

    private static Singleton instance = null;
    private Singleton(){}

    public static synchronized Singleton getInstance(){
        //若是尚未被实例化过,就实例化一个,而后返回
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}

  饿汉模式

public class Singleton {
    //类加载的时候instance就已经指向了一个实例
    private static Singleton instance = new Singleton();
    private Singleton(){}

    public static Singleton getInstance(){
        return instance;
    }
}

  双重检验锁

public class Singleton {
    
    private static Singleton instance = null;
    private Singleton(){}

    public static Singleton getInstance(){
        if(instance == null){
            synchronized (Singleton.class){
                if(instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

  静态内部类:由于JAVA静态内部类的特性,加载的时候不会加载内部静态类,使用的时候才会加载,而使用的时候类加载又是线程安全的,这就完美达到了效果;

public class Singleton {

    private static class SingletonHolder{
        private static Singleton instance = new Singleton();
    }

    private Singleton(){}

    public static Singleton getInstance(){
        return SingletonHolder.instance;
    }
}

  枚举:

public enum Singleton {
    INSTANCE;
}

  

  二、Spring使用了哪些设计模式

  (1)工厂模式,在各类BeanFactory以及ApplicationContext建立中都用到了;

  (2)模板模式,也是在各类BeanFactory以及ApplicationContext建立中都用到了;

  (3)代理模式,在AOP实现中用到了JDK的动态代理;

  (4)单例模式,好比建立bean的时候;

  (5)策略模式,第一个地方,加载资源文件的地方,使用了不一样的方法,好比:classPathResource,FileSystemResource,ServletContextResource,UrlResource但他们都有共同的接口Resource;第二个地方就是AOP的实现中,采用了不一样的方式,JDK动态代理和CGLIB代理;

分布式相关

  一、分布式事务的控制

  能够参考分布式系统事务一致性解决方案

 

  二、分布式锁

  答:通常使用zk瞬时有序节点实现的分布式锁,或者利用redis的setnx()封装分布式锁;提供思路,具体的能够自行详细理解;

 

  三、分布式session如何设计

  答:一个比较成熟的方案是经过redis进行session共享。详细的原理能够参考一种分布式session实现方案

 

  四、关于dubbo

  能够参考博文:Dubbo学习总结(2)——Dubbo架构详解

 

  五、能够了解zk相关知识

 

缓存相关

  一、redis和memcached的区别

  (1)redis和memcache都是将数据放入内存中,都是内存数据库。可是memcache能够缓存图片、视频等数据;

  (2)redis不只仅支持简单的k/v数据,还提供list、set、hash等数据结构的存储;

  (3)虚拟内存--redis当物理内存用完时,能够将一些好久没有用到的value交换到磁盘;

  (4)过时策略--memcache在set时就指定,例如set key1008,即永不过时,redis经过expire设定;

  (5)分布式--设定memcache集群,利用magent作一主多从;redis能够作一主多从或一主一从;

  (6)存储数据安全--memcache挂掉后,数据没了,redis能够按期保存到磁盘进行持久化;

  (7)灾难恢复--memcache挂掉后,数据不可恢复。redis数据丢失后能够经过aof恢复;

  (8)redis支持数据备份,即master-slave主备模式;

 

  二、redis是单线程的么(是的)

  三、redis的持久化策略

  答:rdb:快照形式是直接把内存中的数据保存到一个dump文件中,定时保存

    aof:把全部的对redis的服务器进行修改的命令都存到一个文件里,命令的集合

框架相关

  一、SpringMvc工做原理

  (1)用户发送请求至前端控制器DispatcherServlet

  (2)DispatcherServlet收到请求调用HandlerMapping处理映射器

  (3)处理器映射器找到具体的处理器(能够根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(若有则生成)一并返回给DispatcherServlet

  (4)DispatcherServlet调用HandlerAdapter处理器映射器

  (5)HandlerAdapter通过适配调用具体的处理器(Controller,也叫后端控制器)

  (6)Controller执行完成返回ModelAndView

  (7)HandlerAdapter将Controller执行结果ModelAndView返回给DispatcherServlet

  (8)DispatcherServlet将ModelAndView传给ViewResolver视图解析器

  (9)ViewResolver解析后返回具体的view

  (10)DispatcherServlet根据view进行试图渲染(即将模型数据填充至视图中)

  (11)DispatcherServlet响应用户 

 

  如下组件一般使用框架提供实现:

  DispatcherServlet:做为前端控制器,整个流程控制的中心,控制其它组件执行,统一调度,下降组件之间的耦合性,提升每一个组件的扩展性。

  HandlerMapping:经过扩展处理器映射器实现不一样的映射方式,例如:配置文件方式,实现接口方式,注解方式等。 

  HandlAdapter:经过扩展处理器适配器,支持更多类型的处理器。

  ViewResolver:经过扩展视图解析器,支持更多类型的视图解析,例如:jsp、freemarker、pdf、excel等。

  

  二、Quartz概念及原理

  org.quartz.Job:它是一个抽象接口,表示一个工做,也是咱们要执行的具体的内容,只定义了一个接口方法:void execute(JobExecutionContext context)

  org.quartz.JobDetail:JobDetail表示一个具体的可执行的调度程序,Job是这个可执行调度程序所要执行的内容,它包含了这个调度任务的方案和策略

  org.quartz.Trigger:Trigger是一个抽象接口,表示一个调度参数的配置,经过配置他,来告诉调度器何时去调用JobDetail

  org.quartz.Scheduler:一个调度容器,能够注册多个Trigger和JobDetail。当Trigger和JobDetail组合,就能够被Scheduler容器调度了

  

  三、Spring的IOC有什么优点

  答:要了解IOC首先要明白依赖倒置原则(Dependency Inversion Principle),就是把本来的高层建筑依赖底层建筑倒置过来,变成底层建筑依赖高层建筑。高层建筑决定须要什么,底层去实现这样的需求,可是高层并不用管底层的是怎么实现的;而控制反转(Inversion of Control)就是依赖倒置原则的一种代码的设计思路;

  

  IOC思想的核心,资源不禁使用资源的双方管理,由不适用资源的第三方管理。

  优点:资源集中管理,实现资源的可配置和易管理;下降了使用资源双方的依赖程度,也就是下降了耦合度;

 

  四、Mybatis的设计思想,以及动态代理的真正实现

  Mybatis中的mapper没有实现类,只有对应的xml文件,是如何实现的;

  Spring整合Mybatis时sqlsession为什么不须要自动释放或关闭;

相关文章
相关标签/搜索