2018-06-27

一 基础篇

1.1 Java基础
  • 面向对象的特征

    抽象:将一类对象的共同特征总结出来构建类的过程。
    继承:对已有类的一种复制。
    多态:不同子类型的对象对同一种消息做出不同的回应。
    封装:把数据和操作数据的方法绑定起来,对数据访问时只能通过定义的接口
    
  • final、finally、finalize的区别

    final:修饰变量,被修饰的变量值不能改变
    finally:使用try捕获异常时候,一定会执行的代码块
    finalize:垃圾回收前,会调用finalize方法,释放对象持有的资源
    
    
  • Exception、Error、运行时异常与一般异常有何异同

    Exception与Error都是throwable的子类
    Eroor:系统内部错误与资源耗尽错误,程序不抛出这种错误
    Exception又分为runtimeException与I/OException。程序本身错误时runtimeException,Io就属于其他异常。
    
  • 请写出5种常见到的runtime exception,IOException

    1.NullPointerException (空指针异常)
    2.IndexOutBoundsException(下标越界异常)
    3.ArithmeticException(算数异常)
    4.SecurityException(安全异常)
    5.ArrayStoreException(数组存放类型异常)
    6.NumberFormatException(String转数字类型异常)
    
    1.FileNotFountException
    2.IOException
    3.EOFException
    
  • int 和 Integer 有什么区别,Integer的值缓存范围

     int是基本数据类型,Integer是包装数据类型,包装数据类型是对象,可以使用静态方法。
     Integer的值缓存范围-128-127
    
  • 包装类,拆箱和装箱

     拆箱和装箱的过程就是包装类型与基本数据类型相互转化的过程。
    
  • String、StringBuilder、StringBuffer
    提供了两种类型的字符串String和StringBuilder/StringBuffer都可以存储和操作字符串。
    String 是只读字符串,StringBuilder是单线程下使用的,所以方面都没有被Synchronized修饰。效率更高。

  • 重载和重写的区别

     都是实现多态:重载发生在同一个类下,相同的方法名,参数不同。而重写发生在子类与父类之间,方法名参数返回类型都相同。
     重载是编译时的多态性,而重写是运行时的多态性。
    
  • 抽象类与接口的区别

     抽象类与接口都不能被实例化,一个类继承了某个抽象类或者实现了某个接口,都需要对他们的所有方法进行实现。抽象类可以定义构造器,有抽象方法、具体方法,所有接口更抽象。
     抽象类中的成员可以是public、private的,但是接口中成员全部都是public,接口中定义的成员变量其实是常量。
    
  • 说说反射的用途及实现

  • 自定义注解的实现

  • get请求与post请求的区别

     get请求查询字符串在url上拼接着,post请求的是单独的。get请求能够被缓存,存放书签等
    
  • Session与Cookie区别

     cookie存放在浏览器本地,session存放在服务器,浏览器可以禁止cookie,但是不能禁止session,
    
  • 列出常用的jdk包

     1.java.lang 2.java.util 3.java.sql 4. java.math 5.java.nio  6.java.net
    
  • MVC设计思想

  • equals与==的区别

     ==:比较的是栈中存放的对象的内存地址,判断是否指向同一个对象。
     equals:Object.equals()实际调用的依然是 ==,只有其他地方进行重写String、Integer
    
  • hashCode和equals方法的区别与联系

     hashCode计算出实例的hash码,并返回hash码,equals判断两个对象的地址是不是同一个。
     hashcode相同,equals不一定相同;equals相同,hashcode一定相同。
     hashMap中,hashcode定位到应该存放的位置,如果该位置已经存在元素了,再调用equals。
    
  • 什么是Java序列化和反序列化,如何实现Java序列化?或者请解释Serializable 接口的作用。

     无论什么样的数据都是以二进制的形式在网络上传送的。把Java对象转化为字节码序列的过程就称为对象的序列化,把字节码转为Java对象就叫做反序列化。
     调用OutputStream的writeObject方法
    
  • Object类中常见的方法,为什么wait notify会放在Object里边?

     wait本来就是暂停获取锁的对象
    
1.2、Java常见集合
  • List 和 Set 区别

        list和set都是继承了Collection接口。
            list可以允许重复的对象,允许插入多个null元素,是一个有序容器,保留插入的顺序。常用的实现类有ArrayList LinkedList和Vector.arraylist提供了索引的随意访问,而linkedList对经常需要添加删除的场合更加合适。
            set不允许有重复的元素,无序容器,TreeSet通过Comparator或者Comparable维护排序。只允许一个null元素。set接口实现的类有HashSet,LinkedHashSet以及TreeSet.TreeSet还实现了Sorted接口,因此是一个根据compare()与compareTo()的定义进行排序的有序容器。
    
  • Set和hashCode以及equals方法的联系

        HashSet通过hashCode与equals维护元素的唯一性。
    
  • List 和 Map 区别

        list继承conllection,而map是接口,map以key-value的形式,value可能相同,但是key一定唯一,null-key唯一。
    
  • Arraylist 与 LinkedList 区别

        ArrrayList实现了基于动态数组的数据结构,而LinkedList是基于链表的数据结构,并且是双向链表。
        对于随机访问get set,A>L,因为L需要移动指针。
        对于新增删除来说L>A,因为A要移动数据。
    
  • ArrayList 与 Vector 区别

        Vector的方法都是同步的、线程安全的,而ArrayList不是,所以ArrayList的性能较好。
        当容量达到初始大小后,Vector会翻倍,而Arraylst会上涨0.5倍。更加节省空间
    
  • HashMap 和 Hashtable 的区别

        都是基于哈希表的,HashMap继承的是map 而HashTable继承的是Dictionary。HashMap的初始容量是16,HashTable 11,填充因子0.75,2n 2n+1
    
  • HashSet 和 HashMap 区别

        HashSet实现了set接口,不容许重复,存储对象是需要重写hashCode与equals方法。使用add添加元素,hashCode计算时利用成员对象
        HasgMap实现了map接口,key允许一个null。存储key value,使用put方法添加元素,使用key来计算hashcode
    
  • HashMap 和 ConcurrentHashMap 的区别

        想要线程安全的HashMap可以通过Collections的静态方法SynchronizedMap来获得。CouncurrecnHashMap 分段锁,默认16个。
        使用put的时候,根据key的hash值得到在数组中的位置,然后放到位置中,如果已经有元素,那么将以链表的形式存放。新插入的在前面 1.8之后先插入的在后面。
    
  • HashMap 的工作原理及代码实现,什么时候用到红黑树

        1.6 1.7采用的是位桶加链表的形式,1.8采用位桶加链表加红黑树。当链表的长度超过阀值(8)时采用红黑树,将减少查找的时间。
        根据key计算hash得到在位桶(数组)中的位置,元素放到后面列表。如果已有元素添加到后面。
    
  • 多线程情况下HashMap死循环的问题

        rehash的时候链表结构发生变化,会发生闭合的回路。
    
  • HashMap出现Hash DOS攻击的问题

  • ConcurrentHashMap 的工作原理及代码实现,如何统计所有的元素个数

  • 手写简单的HashMap

  • 看过那些Java集合类的源码

1.3、进程和线程
  • 线程和进程的概念、并行和并发的概念

     进程:是一个程序的实例,每个进程都有自己的虚拟地址空间和控制线程。
     线程:线程是操作系统调度器分配处理器的基础单元。
     并行:一个cpu同步处理多个进程。
     并发:一个cpu可以异步的处理多个进程。
    
  • 创建线程的方式及实现

     Thread是实现了Runnable的。
     有三种,1.继承Thread  2.实现了runnable 3.使用callable和future创建线程。
    
  • 进程间通信的方式 !!!!!!!!!!!

     线程之间通信方式:
         1.共享变量  --必须指向同一个共享实例的引用(synchronized)
         2.wait/notify机制
         3.Lock/Condition
         4.管道(缺点:只能两个线程之间,只能单向通信)
            创建管道输出流PipedOutputStream pos 与输入流PipedInputStream pis
            将pos与pis匹配,pos.connect(pis);
            pos赋给信息输入线程,pis赋给信息获取线程。
            
     进程之间的通信方式:
         1.管道
         2.命名管道
         3.信号
         4.消息队列
         5.共享内存
         6.内存映射
         7.信号量
         8.套接口
    
  • 说说 CountDownLatch、CyclicBarrier 原理和区别

     CountDownLatch:一个线程等待其他多个线程完成。CountDownLatch有一个构造方法,两个常用的方法 await() --等待变为0和countdown() ---减一
     CyclicBarrier:所有线程到达某个状态,再一起执行    await()加一
    
  • 说说 Semaphore 原理

     Semaphore:一个是用于多个共享资源的互斥使用,另一个用于并发线程数的控制。 AQS控制
    
  • 说说 Exchanger 原理

     两个工作线程之间的交换数据,等同时到达某一个状态 进行交换数据
    
  • ThreadLocal 原理分析,ThreadLocal为什么会出现OOM,出现的深层次原理

     ThreadLocal:线程本地变量或线程本地存储。
     ThreadLocal在每个线程中会对该变量创建一个副本(资源消耗的问题),先set再get,如果不set,可以重写initalValue方法
    
  • 讲讲线程池的实现原理

     多线程技术主要解决处理器单元内多个线程执行的问题。可以显著的减少处理器单元的闲置时间。增加啊处理器单元的吞吐能力。T1+T3>>>T2
         1.线程池管理器(ThreadPool):用于创建并管理线程池,包括创建线程,销毁线程,添加新任务
         2.工作线程(PoolWorker):线程池中线程,在没有任务时处于等待章台,可以循环的执行任务。
         3.任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,主要规定了任务的入口、任务执行完的收尾工作,任务的执行状态
         4.任务队列(taskQueue):用于存放没有处理的任务,一种缓冲机制。
     常见的线程池:Executors中的静态方法
         1.newSingleThreadExecutor  单个线程,串行执行
         2.newFixedThreadExecutor(n)    固定数量的线城市
         3.newCacheThreadExecutor    可缓存线程池,当线程池大小超过了处理任务所需的线程,就会回收线程,有新任务来时,添加新的线程来执行
         4.newScheduleThreadExecutor 大小无限制的线程池,支持定时和周期性的执行线程
         
         newWorkStealingPool 多个队列的线程池 减少连接数
     重要的类:
         ExecutorService  --真正的线程池接口
         ScheduledExecutorService  --和Timer/TimerTask类似,解决需要重复执行的问题
         ThredPoolExecutor   --ExecutorService的默认实现
         ScheduledThredPoolExecutor  --继承ScheduledExecutorService接口时间,周期性任务调度的类实现
     queue有三种类型,即排毒有三种通用策略:
         直接提交:工作队列默认是SynchronousQueue。当命令超过队列所能处理的平均数连续到达数,此策略允许无界线程具有增长的可能性。使用这种策略,要求maxnumPoolSize是无界的,可以保证A2一定在A1后执行。
         无界队列:不具有预定义容量的LinkedBlockingQueue,corePoolSize线程都忙时新任务在队列中等待,当超过corePoolSize,新任务始终添加到队列中
         有界队列:ArrayBlockingQueue. 拒绝策略,够了就不添加到队列中去了
     可选择的饱和策略RejectExceptionHandler
         1.AbortPolicy   中止策略,饱和时会抛出RejectedExcutionException
         2.discardPolicy   抛弃策略,不做任何处理 直接抛弃
         3.discardOldestPolicy  抛弃旧任务策略  优先级队列,会抛弃优先级较高的,不建议
         4.CallerRunsPolicy  调用者运行,调用调用者的主线程来执行任务。所以主线程无法再提交新任务。
     
     
     线程池最核心的一个类  java.util.concurrent.ThreadPoolExcutor类
     Executor是一个顶层接口,在它里面只声明了一个方法execute(Runnable),返回值为void,参数为Runnable类型,从字面意思可以理解,就是用来执行传进去的任务的;
     
     然后ExecutorService接口继承了Executor接口,并声明了一些方法:submit、invokeAll、invokeAny以及shutDown等;
     
     抽象类AbstractExecutorService实现了ExecutorService接口,基本实现了ExecutorService中声明的所有方法;
     
     然后ThreadPoolExecutor继承了类AbstractExecutorService。
     
     在ThreadPoolExecutor类中有几个非常重要的方法:
         execute()
         submit()
         shutdown()
         shutdownNow()
     execute()方法实际上是Executor中声明的方法,在ThreadPoolExecutor进行了具体的实现,这个方法是ThreadPoolExecutor的核心方法,通过这个方法可以向线程池提交一个任务,交由线程池去执行。
     submit()方法是在ExecutorService中声明的方法,在AbstractExecutorService就已经有了具体的实现,在ThreadPoolExecutor中并没有对其进行重写,这个方法也是用来向线程池提交任务的,但是它和execute()方法不同,它能够返回任务执行的结果,去看submit()方法的实现,会发现它实际上还是调用的execute()方法,只不过它利用了Future来获取任务执行结果(Future相关内容将在下一篇讲述)。
    
  • 线程池的几种实现方式

  • 线程的生命周期,状态是如何转移的

     (1)New:创建线程对象后,该线程处于新建状态,此时它不能运行,和其他Java对象一样,仅仅有Java虚拟机为其分配了内存,没有表现出任何线程的动态特征; 
     (2)Runnable:线程对象调用了start()方法后,该线程就进入了就绪状态(也称可运行状态)。处于就绪状态的线程位于可运行池中,此时它只是具备了运行的条件,能否获得CPU的使用权开始运行,还需要等待系统的调度; 
     (3)Runing:处于就绪状态的线程获得了CPU使用权,开始执行run()方法中的线程执行体,则线程处于运行状态。当一个线程启动后,它不能一直处于运行状态(除非它的线程执行体足够短,瞬间结束),当使用完系统分配的时间后,系统就会剥脱该线程占用的CPU资源,让其他线程获得执行的机会。只有处于就绪状态的线程才可能转换到运行状态。 
     (4)Blocked:一个正在执行的线程在某些特殊情况下,如执行耗时的输入/输出操作时,会放弃CPU的使用权,进入阻塞状态。线程进入阻塞状态后,就不能进入排队队列。只有当引用阻塞的原因,被消除后,线程才可以进入就绪状态。 
         ——当线程试图获取某个对象的同步锁时,如果该锁被其他线程所持有,则当前线程进入阻塞状态,如果想从阻塞状态进入就绪状态必须得获取到其他线程所持有的锁。 
         ——当线程调用了一个阻塞式的IO方法时,该线程就会进入阻塞状态,如果想进入就绪状态就必须要等到这个阻塞的IO方法返回。 
         ——当线程调用了某个对象的wait()方法时,也会使线程进入阻塞状态,notify()方法唤醒。 
         ——调用了Thread的sleep(long millis)。线程睡眠时间到了会自动进入阻塞状态。 
         ——一个线程调用了另一个线程的join()方法时,当前线程进入阻塞状态。等新加入的线程运行结束后会结束阻塞状态,进入就绪状态。 
         线程从阻塞状态只能进入就绪状态,而不能直接进入运行状态,即结束阻塞的线程需要重新进入可运行池中,等待系统的调度。 
     (5)Terminated:线程的run()方法正常执行完毕或者线程抛出一个未捕获的异常(Exception)、错误(Error),线程就进入死亡状态。一旦进入死亡状态,线程将不再拥有运行的资格,也不能转换为其他状态。
    
  • 可参考:《Java多线程编程核心技术》

1.4、锁机制
  • 说说线程安全问题,什么是线程安全,如何保证线程安全

    线程安全:多个线程同时运行,每次结果与单线程的结果一样,变量也与预期一样。线程安全问题都是由全局变量以及静态变量引起的
    1.保证原子性:锁和同步  lock()  synchronized  CAS AtomicInteger
    2.保证可见性:volatile
    happens-before原则(先行发生原则)
    
  • 重入锁的概念,重入锁为什么可以防止死锁

    重入锁:同一个线程再次进入同步代码块的时候,使用自己已获取的锁
    synchronized 和   ReentrantLock 都是可重入锁
    
  • 产生死锁的四个条件(互斥、请求与保持、不可剥夺、循环等待)

  • 如何检查死锁(通过jConsole检查死锁)

  • volatile 实现原理(禁止指令重排、刷新内存)

    volatile保证可见性的原理是在每次访问变量时都会进行一次刷新,因此每次访问都是主内存中最新的版本。所以volatile关键字的作用之一就是保证变量修改的实时可见性。
    还有另一个重要的作用:在JDK1.5之后,可以使用volatile变量禁止指令重排序。
    
  • synchronized 实现原理(对象监视器)

    Java对象头和monitor是实现synchronized的基础
    
  • synchronized 与 lock 的区别

    1.首先synchronized是java内置关键字,在jvm层面,Lock是个java类;
    
    2.synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁;
    
    3.synchronized会自动释放锁(a 线程执行完同步代码会释放锁 ;b 线程执行过程中发生异常会释放锁),Lock需在finally中手工释放锁(unlock()方法释放锁),否则容易造成线程死锁;
    
    4.用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了;
    
    5.synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可判断、可公平(两者皆可)
    
    6.Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。
    
  • synchronized 与 ReentrantLock的区别

    由于ReentrantLock是java.util.concurrent包下提供的一套互斥锁,相比Synchronized,ReentrantLock类提供了一些高级功能,主要有以下3项:
    
            1.等待可中断,持有锁的线程长期不释放的时候,正在等待的线程可以选择放弃等待,这相当于Synchronized来说可以避免出现死锁的情况。
    
            2.公平锁,多个线程等待同一个锁时,必须按照申请锁的时间顺序获得锁,Synchronized锁非公平锁,ReentrantLock默认的构造函数是创建的非公平锁,可以通过参数true设为公平锁,但公平锁表现的性能不是很好。
    
            3.锁绑定多个条件,一个ReentrantLock对象可以同时绑定对个对象。
    
  • AQS同步队列

  • CAS无锁的概念、乐观锁和悲观锁

  • 常见的原子操作类

  • 什么是ABA问题,出现ABA问题JDK是如何解决的

  • 乐观锁的业务场景及实现方式

  • Java 8并法包下常见的并发类

  • 偏向锁、轻量级锁、重量级锁、自旋锁的概念

1.5、JVM
  • JVM运行时内存区域划分

       内存区划分为:堆、Java栈、本地方法栈、程序计数器、方法区
       所有线程共享的区域:堆、方法区
       程序计数器:记录执行的指令的地址(native方法)
       Java栈:存放的是一个个的栈帧,对应的调用方法,在栈帧中包括局部变量表、操作数栈、当前方法所属类的常量尺码的引用,方法返回地址。!!当线程执行一个方法时,就会创建一个对应的栈帧,并压栈,方法执行完毕后就会出栈。
       本地方法栈:是执行本地方法服务的
       堆:用来存储对象本身以及数组(数组引用存放在Java栈中)
       方法区:存储了每个类的信息(类的名称、方法信息、字段信息)、静态变量、常量和编译后的代码
    
  • 内存溢出OOM和堆栈溢出SOE的示例及原因、如何排查与解决

       OOM:过多的静态变量、大量递归、大量循环、sql查询超过十万条,集合中存放对象的引用而不是对象、非字面量字符串+操作
       栈溢出:递归调用、大量循环、全局变量过多、数组 list map数据是否过大,DDMS工具
    
  • 如何判断对象是否可以回收或存活

       引用计数法:引用加1,引用失效减1  但无法解决对象之间的循环引用的问题 
       可达性分析:通过一系列被称为"GC ROOTS"的对象作为起始点,搜索所走过的路径称为引用链。当没有引用链的时候,就认为不可达 可以被回收。
    
  • 常见的GC回收算法及其含义

       1.引用计数法:
       2.标记-清除法:
       3.copy:
       4.标记-整理
       5.分区:对于栈来说
    
  • 常见的JVM性能监控和故障处理工具类:jps、jstat、jmap、jinfo、jconsole等

  • JVM如何设置参数--tomcat的配置文件中

  • JVM性能调优

  • 类加载器、双亲委派模型、一个类的生命周期、类是如何加载到JVM中的

       .java文件通过编译器(javac)编译成为.class的二进制文件,通过类加载器加载到内存中。
       类的生命周期:加载、验证、准备、解析、初始化、使用、卸载。
       加载:通过类的全限定名来获取定义此类的二进制字节流,将字节流代表的静态存储结构转化为区域运行时的数据结构。在Java堆中生成一个代表这个类的java.lang.class对象,作为方法区数据的访问入口。
       验证:分为四个阶段文件格式、元数据、字节码、符号引用
       解析:是将常量池的符号引用转化为直接引用,四种类型的引用解析:类或接口的解析、字段解析、方法解析、接口方法解析
       初始化:根据程序员制定的计划去初始化。包括static{} 构造函数、父类初始化等。
       
       双亲委派模型:机制:类加载器(bootstrap)-->标准扩展(Extension)类加载器-->系统加载器-->上下文加载器。从上到下加载,先将加载任务委托给父类加载器、依次递归,如果父类成功完成,就返回成功、无法完成时才去自己加载。
    
  • 类加载的过程:加载、验证、准备、解析、初始化

  • 强引用、软引用、弱引用、虚引用

       强引用:只要引用存在,永远不会被回收
       软引用:非必须引用,内存溢出之前回收,类似缓存
       弱引用:第二次垃圾回收时回收 监控被垃圾回收器标记为即将被回收的垃圾
       虚引用:垃圾回收时回收,无法通过引用取到对象值。检测是否从内存中删除
    
  • Java内存模型JMM

       JMM的主要目标是定义程序中各个变量的访问规则,虚拟机中将变量存储到内存和从内存中取出变量的细节。
    
1.6、设计模式
  • 常见的设计模式

        1.单例模式
        2.工厂模式
        3.建造者模式
        4.门面模式
        5.策略模式
    
  • 设计模式的的六大原则及其含义

        1.开闭原则(抽象类和接口):对扩展开放,对修改关闭
        2.里氏代换原侧(使用抽象类继承):基类可以被子类替换
        3.依赖倒转原则(针对接口编程):要依赖抽象
        4.接口隔离(建立最小接口):多接口更好
        5.迪米特法则:尽量减少与其他实体相互作用
        6.合成复用法则:减少继承
    
  • 常见的单例模式以及各种实现方式的优缺点,哪一种最好,手写常见的单利模式

        饿汉:定义静态,如果实例没有被引用,会造成资源浪费。
        懒汉:synchronized 并发效率低。
    
  • 设计模式在实际场景中的应用

  • Spring中用到了哪些设计模式

  • MyBatis中用到了哪些设计模式

  • 你项目中有使用哪些设计模式

  • 说说常用开源框架中设计模式使用分析

  • 动态代理很重要InvocationHandler

    手写代理模式:1.先写接口,定义接口内方法  2.写主人类,实现接口内的方法。 3.写代理类,实现InvocationHandler
        利用到了反射
    
1.7、数据结构
  • 树(二叉查找树、平衡二叉树、红黑树、B树、B+树
  • 深度有限算法、广度优先算法

  • 克鲁斯卡尔算法、普林母算法、迪克拉斯算法

  • 什么是一致性Hash及其原理、Hash环问题

  • 常见的排序算法和查找算法:快排、折半查找、堆排序等

2.1、数据库

  • MySQL 索引使用的注意事项

     索引的目的在于提高查询效率。索引的类型:1.index 2.unique 3.primary key 4.fulltext 5.组合索引
     创建索引:1.ALTER TABLE table_name ADD INDEX index_name (col_name1,col_name2)
              2. CREATE INDEX index_name ON table_name(col_name)
     删除索引:1.DROP INDEX index_name ON table_name;
              2.ALTER TABLE table_name DROP PRIMART KEY;
     注意事项:EXPLAIN可以帮助开发人员分析sql的问题。
             1.索引在提高查询毒素的同时,也降低了更新表的速度,不仅要保存数据,还需要保存索引文件
             2.建立索引会占用磁盘空间的索引文件
    
  • DDL、DML、DCL分别指什么

     DML:有select、update、insert、delete 对数据库的数据进行操作的数据
     DDL:有create、alter、drop 主要是定义或改变表结构,表建立时使用
     DCL:数据库控制功能,用来设置数据库用户或角色权限的语句
    
  • explain命令

  • left join,right join,inner join

  • 数据库事物ACID(原子性、一致性、隔离性、持久性)

     操作序列要么都执行要么都不执行。
     原子性:事务是一个不可分割的工作单位、要么都执行要么都不执行。
     一致性:开始与结束后,数据库的完整性没有被破坏。解决办法,约束
    
  • 事物的隔离级别(读未提交、读以提交、可重复读、可序列化读)

     读未提交:
     读以提交:等到提交完在读取数据。
     可重复读:执行事务的时候不允许其他事务进入
     可序列化读:Serializable 是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。
    
  • 脏读、幻读、不可重复读

     脏读:读取到还未确认的数据   ===>事务提交前,对其他事务不可读取其修改的值。
     幻读:对同一行数据做出修改,更新丢失  ===>对行加锁,只允许并发一个更新事务。
     不可重复读:多次读取不一致  ====> 只有当修改事务完全提交后才可以读取数据。
     幻象读:读取后新增操作  ===>在操作完成数据处理之前,任何事务都不可以在添加新数据。
    
  • 数据库的几大范式(三大范式)

     1NF: 原子性,列不应该再分为几列(电话|家庭电话/手机)
     2NF: 1.必须有主键2.完全依赖于主键 数据冗余的问题
     3NF: 不能传递依赖,反作用依赖,非主键依赖于主键
    
  • 数据库常见的命令

--- 数据库的扩展:业务拆分、主从复制、数据库的分库分表

  • 说说分库与分表设计

         单表的记录行数过大:采用Master-Slave复制模式的mysql架构。写操作集中在Master,并且挂在的Slave受到master能力和负载的限制。
         拆表可以用取余的办法,表的数量一般是2的N次方,分表一般解决单表数量过大带来的查询效率问题。无法解决并发问题,所以还得分库。
         
         分库分表的策略:1.中间变量=user_id%(库容量*每个库中表的数量);
                       2.库序号=取整(中间变量/每个库中表的数量)
                       3.表序号=中间变量%每个库中表的数量
         先计算出中间变量,库序号取整、表序号取模,都是针对单个库中表的数量。
    
  • 分库与分表带来的分布式困境与应对之策(如何解决分布式下的分库分表,全局表?)

         1.数据迁移与扩容问题 2.表关联的问题 3.分页与排序的问题 4.分布式事务的问题 5.分布式全局唯一ID
         跨库Join的几种解决办法:
         1.全局表:将这类表在其他每个数据库均保存一份
         2.字段冗余:反范式,把需要的字段加到列中。
         3.数据同步,关联的库同步了
         4.数据组装
    
  • 说说 SQL 优化之道

         1.explain 查询  十万条数据分水岭
         2.创建正确的索引
         3.不使用默认配置
             > 1 innodb_buffer_pool_size
             > 2 innodb_log_file_size  单个innodb日志文件大小
             > 3 最大连接数
         4 数据库转入到内存中
         5 固态硬盘
    
  • MySQL遇到的死锁问题、如何排查与解决

         死锁成因:两个事务相互等待 innodb_lock_wait_timeout
         wait-for graph:是否形成环形有向图、
         1.2 innodb隔离级别、索引与锁
             索引与锁的关系:无索引查询是全表扫描,二级索引会先锁住二级索引,接着会锁住相对应的主键对应的记录 3.一级索引会直接锁住那一行
             
             隔离级别:
                 1.未提交读:
                 2.提交读:
                 3.重复读:
                 4.可串行读:
         定位死锁:根据日志找到相应事务对应的sql,确定数据库的隔离级别,innodb的级别是RC,排除gar锁。
                  查看死锁的日志:show innodb status
    
  • 存储引擎的 InnoDB与MyISAM区别,优缺点,使用场景
    myISAM:不支持事务处理、外键和行级锁。执行大量的select

  • 索引类别(B+树索引、全文索引、哈希索引)、索引的原理

         常用的索引类型:主键索引、唯一索引、全文索引、普通索引和组合索引
         常用的索引结构:b+树索引、哈希索引
             索引的原理:
    
  • 什么是自适应哈希索引(AHI)

         InnoDB存储引擎会监控表上各索引页的查询。检测到如果检测到建立哈希索引带来更高的速度,就建立哈希索引,称之为自适应哈希索引。
    
  • 为什么要用 B+tree作为MySQL索引的数据结构

         1.文件很大,不可能全部存储在内存中,所以存储到磁盘里
         2.索引的结构组织要尽量减少查到磁盘中I/O的存取次数
         3.红黑树 比较深
    
  • 聚集索引与非聚集索引的区别

  • 遇到过索引失效的情况没,什么时候可能会出现,如何解决

         1.or语句
         2.like 以%开头的
         3.多列索引,不是使用的第一部分
         4.列类型是字符串,需要在条件中用引号引用起来
    
  • limit 20000 加载很慢怎么解决

         1.order by 加索引
         2.反向查找  超过一般,偏移逆转
    
  • 如何选择合适的分布式主键方案

         1.UUID  2.自然主键
    
  • 选择合适的数据存储方案

  • 常见的几种分布式ID的设计方案

         1.Twitter的snowflake算法  2.利用zookeeper生成唯一ID  3.利用redis生成唯一ID
    
  • 常见的数据库优化方案,在你的项目中数据库如何进行优化的

         1.选择最有效率的表名顺序(笔试常考) 从右到左顺序处理
         2.WHERE子句中的连接顺序
         3.SELECT子句中避免使用*号
         4.删除全表,利用Truncate
         5.尽量多使用COMMIT
         6.用WHERE子句替换HAVING子句
         7.多使用内部函数提高SQL效率
         8.使用别名
    
2.2、Redis
  • Redis 有哪些数据类型,可参考《Redis常见的5种不同的数据类型详解》

         string(最大可以512M,文件图片都可以)、list、set、hash(key-value)、zset(不同的是每个元素都会关联一个double类型的分数)
    
  • Redis 内部结构

  • Redis 使用场景

         1.为什么使用
             解决应用服务器的cpu与内存压力
             减少IO操作,减轻IO压力
             关系型数据库扩展性不强,难以改变表结构
         2.优点
             nosql数据库没有关联关系,数据结构简单
             读取速度快,对较大数据处理快
         3.适用场景
             数据高并发的读写
             海量数据的读写
             扩展性能高的数据
         4.不适用的场景
             需要事物支持
             关系复杂,需要sql结构化查询存储的。
             
         5使用场景
             1.配合关系型数据库做高速缓存
                 缓存高频访问的数据,降低数据库io
                 分布式架构,做session缓存
             2.可以持久化特定数据
                 利用zset类型可以存储排行榜
                 利用list的自然时间排序存储n个最新数据
         redis基础知识:端口6379 默认16个数据库,下标从0开始,
             redis:单线程+io多路复用:检查文件描述的就绪状态
             memchached:多线程+锁
    
  • Redis 持久化机制,可参考《使用快照和AOF将Redis数据持久化到硬盘中》

         redis提供了两种不同方式的持久化:1.快照(RDB) 2.只追加文件(AOF)
         一、创建快照的方式
             (1)客户端向redis发送BGSAVE命令  save 60 1000(当60秒内有1000次写入操作时)
             (2)客户端向redis发送SAVE命令,会阻断其他命令,shutdown前调用
             注意:可以考虑关闭自动快照,选择适当的时间通过命令保存
         二、AOF持久化(将被执行的写命令写道AOF文件的末尾)
              appendonly yes:打开AOF
              appendfsync everysec(每秒执行一次)/always(每个命令都执行,会降低redis的速度)/no(系统决定)
         三、重写/压缩AOF文件
              BGREWRITEAOF  与BGSAVE一样会创建子线程
                 自动压缩文件条件:auto-aof-rewrite-percentage  auto-aof-rewrite-min-size 
    
  • Redis 集群方案与实现

         Redis Cluster,阿里云redis
    
  • Redis 为什么是单线程的?

         对于redis来说,cpu不是瓶颈,而是来自机器内存或者网络带宽
    
  • 缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级

         缓存雪崩:原有缓存时效,新缓存未到,大量请求到了数据库  (加锁排队,请求量不大的时候)(设置过期标志更新缓存)(为key设置不同的缓存失效时间)
         缓存穿透:缓存没有、数据库也没有,两次无用查询 (bitmap:布隆过滤器)(对空结果进行缓存)
         缓存预热:系统上线后,提前把相关的缓存数据加载到缓存系统中
         缓存更新:定时清理  或者等用户请求
         缓存降级:一般、警告、严重、严重错误
    
  • 使用缓存的合理性问题

  • Redis常见的回收策略(6)
    根据过期时间:
    1.volatile-lru:淘汰最少使用的
    2.volatile-ttl:淘汰即将要过期的
    3.volatile-random:任意淘汰
    从数据集
    4.allkeys-lru:数据集中最少使用的
    5.allkeys-random:数据集中任意淘汰

             6.no-envication:禁止驱逐
    
2.3、消息队列
  • 消息队列的使用场景

         主要解决:应用耦合、异步消息、流量削峰、日志等问题
         使用场景:异步处理,应用解耦,流量削锋和消息通讯四个场景。
    
  • 消息的重发补偿解决思路

         处理失败:onMessageListener的onMessage方法抛出RuntimeException Message头里有两个相关字段:Redelivered默认false RedeliveryCounter默认0
         消息先由broker发送给consumer,consumer调用listener,如果处理失败,本地redeliveryCounter++,给broker一个特定的应答,broker端的message里redeliveryCount++,延迟一点时间继续调用,默认1s。超过六次,给Broker另一个特定应答,broker直接发送消息到DLD
         如果失败2次,consumer重启,redeliveryCount=2 本地再重试四次进入DLQ
    
  • 消息的幂等性解决思路

         上半场幂等:MQ-client没有收到消息回执,再次发送===> 对每条消息,MQ系统内部必须生成一个inner-msg-id,作为去重与幂等的依据, 1.全局唯一2.MQ生成,与业务无关
         
         下半场幂等:MQ-server没有拿到ack,服务端超时后重发消息。===》保证业务幂等,业务消息体中必须由一个biz-id,1.对于同一个业务场景,全局唯一2.由业务消息发送方生成,业务相关,对mq透明。3.判重也是由业务消息方判断。
    
  • 消息的堆积解决思路

         消息发送的效率远远大于消费的效率。默认情况下rabbitmq消费者为单线程串行消费。可以通过设置并发消费提高消费的效率。
         concurrentConsumers:设置并发消费者的个数
         prefetchCount:每次一次性从broker里面取得待消费的个数
    
  • 自己如何实现消息队列

  • 如何保证消息的有序性

     调用一个master的consumer,其他slave消费,利用zookeeper进行选主。
     脑裂问题:zookeeper可以用来选主,但不能保证某一时间内只有一个主。exclusive consumer。全部消息会发给这个consumer,如果这个挂了,会自动选择另外一个
    

三、开源框架和容器

3.1、SSM/Servlet
  • Servlet的生命周期

    生命周期:加载--->实例化--->服务--->销毁
     init():只会执行一次init,在服务器装入servlet时进行,负责初始化servlet对象
     service():是servlet的核心,负责响应客户的请求 ServletRequest  ServletResponse
     destroy():仅执行一次,服务端停止且卸载Servlet时执行该方法。
    
  • 转发与重定向的区别

    1.转发是服务器行为,重定向是客户端行为,
    2.重定向是两次request,传输的信息会丢失  
    
  • BeanFactory 和 ApplicationContext 有什么区别

     BeanFactory是比较原始的Factory,无法支持spring的很多插件,例如AOP功能,web应用。
     ApplictionContext是由BeanFactory派生而来,以一种更面向框架的方式工作以及对上下文分层,实现继承。
     ApplictionContext还提供以下功能:
         * MessageSource,提供国际化的消息访问(i18n)
         * 资源访问,url和文件
         * 事件传播
         * 载入多个上下文,使每一个上下文都专注于一个特定的层次。
     1.利用MessagSource进行国际化(i18n) 2.强大的事件机制(Event)3.底层资源的访问(ResourceLoader)4.对web应用的支持
             其他:BeanFactory是延迟加载的,这样不能及时发现问题 手动注册,而ApplicationContext在容器启动时,一次性创建所有的Bean 自动注册
    
  • Spring Bean 的生命周期
    -----beanFactory----
    * Bean的建立,由BeanFactory读取bean的定义文件,生成各个实例。
    * Setter注入,执行Bean的属性依赖注入
    -----beanFactory----

     * 实例化一个Bean  new
     * 按照spring上下文对实例化的Bean进行配置,也就是IOC注入。
     * BeanNameAware的setBeanName(),如果实现该接口,则执行setBeanName方法。
     * BeanFactoryAware的setBeanFactory(),如果实现该接口,则执行setBeanFactory方法。
     
     -----ApplicationContext----
     * ApplicationContextAware接口,则执行其setApplicationContext()方法
     -----ApplicationContext----
     
     * BeanPostProcessor的processBeforeInitialization(),如果有关联的processor,则在初始化之前都会执行这个实例的processBeforeInitialization()方法。
     * InitializingBean的afterPropertiesSet(),实现了该接口,则执行其afterPropertieSet()方法。
     * Bean定义文件中定义init-method
     * BeanPostProcessors的processAfterInitialization(),如果有关联的processor,则在Bean初始化之前都会执行这个实例的processAfterInitialization()方法
     * DisposableBean的destory(),在容器关闭时,如果bean类实现了该接口,则会执行destroy()方法
     * Bean定义文件定义了destroy-method。在容器关闭时,可以在Bean定义文件中使用"destroy-method"定义的方法。
    
  • Spring IOC 如何实现

     IOC是一种思想,而DI(依赖注入)是实现IoC的一种方法:将对象的创建转移给第三方。
         实现方式:1.xml  2.注解
         注入方式:1.构造方法注入  2.setter注入   3.接口注入
    
  • Spring中Bean的作用域,默认的是哪一个

     spring中注入的bean默认是配置为单例模式,四种作用域: ConfigurableBeanFactory.SCOPE_xxx
         1.singleton:单例 singleton 整个应用只创建一个实例 
         2.prototype: 原型 prototype 每次注入时都创建一个实例
         3.session: 会话 session 为每次会话创建一个
         4. request:请求 request 为每个请求创建一个实例
         5.globalsession::每个全局的HTTP Session,使用session定义的Bean都将产生一个新实例。典型情况下,仅在使用portlet context的时候有效。同样只有在Web应用中使用Spring时,该作用域才有效
     单例对象需要注入请求对象,请求对象并没有被创建,此时会先注入一个代理对象,当这个对象被使用时,则会委托给真正的bean去完成。
         <bean id="xxx" class=""xx.xxx.xxx" scope="session">
             <aop:scoped-proxy/>
         </bean>
         <aop:scoped-proxy/>
         
         @Scope(value=WebApplicationContext.SCOPE_SESSION,proxyMode=ScopeProxyMode.INTERFACES)
    
  • 说说 Spring AOP、Spring AOP 实现原理

     面向切面编程,aop分为静态代理(AspectJ 编译时增强 在编译阶段将代码织入)与动态代理(Spring AOP)
     Spring AOP的动态方式有两种,JDK动态代理与CGLIB动态代理,JDK动态代理通过反射来接收InvocationHandler与Proxy。如果类被final标记,则无法使用CGLIB做动态代理
    
  • 动态代理(CGLib 与 JDK)、优缺点、性能对比、如何选择

     使用JDK动态代理,目标类必须实现某个接口,如果没有实现接口则无法生成代理对象。
     
     CGLIB的原理是针对目标类生成一个子类,覆盖其中的方法,所以目标修不能被声明为final类型。
     
     从执行效率上看CgLib动态代理效率更高。
    
  • Spring 事务实现方式、事务的传播机制、默认的事务类别

     事物的配置有五种方式,spring中配置文件中关于事物的配置有三个部分组成。分别是DataSource、TransactionManager和代理机制三个部分,变化的只是代理机制这部分。
     
     Spring配置文件=====>实现方式:
         方式一:通过事务代理工厂bean进行配置 xml方式
             1.引入一系列的约束头文件与标签
             2.配置C3P0数据源,以及dao、service
             3.配置事物管理器以及事物代理工厂bean.,测试类getBean获取代理工厂id
             
         方式二:注解
             <tx:annotation-driven transaction-manager-"mytx"/>
             
             @Transactional(rollbackFor=StockExption.class)
             
         方式三:Aspecth AOP配置事物
             <tx:advice id="txAdvice" transaction-manager="mytx">
                 <tx:attributes>
                     <tx:method name="add* islation="DEFAULT" ..../>
                 </tx:attributes>
             </tx:advice>
             <aop:config>
             </aop:config>
             
     事物的传播机制:多个事物同时存在时,srping应该如何处理这些事物的行为(七个)
      (默认)PROPAGATION_REQUIRED:支持当前事物,如果当前没有事物,就创建一个事物,默认的事物的传播
         PROPAGATION_REQUIRED_NEW:新建事物,如果当前事物存在,就将当前事物挂起,是两个独立的事物,外层事物失败回滚,不能回滚内层事物执行的结果,内存事物失败抛出异常,外层捕获异常,也可以不回滚。
         PROPAGATION_SUPPORTS:支持当前事物,如果当前没有事物,就以非事物的方式执行。
         PROPAGATION_MANDATORY:支持当前事物,如果没有则抛出异常
         PROPAGATION_NOT_SUPPORTS:以非事物方式执行操作,如果当前存在事物,就把当前事物挂起。
         PROPAGATION_NEVER:以非事物方式执行,如果当前存在事物,则抛出异常
         PROPAGATION_NEWTES:如果一个活动的事物存在就,就运行在一个嵌套的事物中,如果没有事物,就按照默认模式执行.
     
      七大事物传播行为的使用:
           充值行为
             不论扣款和创建订单只要有一个异常,不允许提交直接混滚:PROPAGATION_MANDATORY
             不管充值是否成功,必须记录日志:PROPAGATION_REQUIRES_NEW
             业务完成后需要统计,统计耗时长不适合事物:PROPAGATION_NEVER
             
           办理银行卡,等级成功与否不影响卡片的创建:新增卡片的行为回滚,登记就没意义了,也需要回滚,但是登记的回滚不影响新增卡片的行为。所以保存银行卡的事物传播行为可以设置为PARPAGATION_REQUIRED,PARPAGATION_MANDATORY.
      Spring中的隔离级别:
           ISOLATION_DEFAULT:使用数据库默认的事物隔离级别
           ISOLATION_READ_UNCOMMITTED:
           ISOLATION_READ_COMMITTED:
           ISOLATION_REPEATABLE_READ:
           ISOLATION_SERIALIZABLE:
    
  • Spring 事务底层原理

     Spring的事务管理是基于TransactionManager
    
  • Spring事务失效(事务嵌套),JDK动态代理给Spring事务埋下的坑,可参考《JDK动态代理给Spring事务埋下的坑!》

  • 如何自定义注解实现功能

     元注解有四个:@Document @Targrt @Retention @Inherited
    
  • Spring MVC 运行流程

     1.DispatchServlet前端控制器接收发过来的请求,交给handleMapping处理映射器。
     2.HandleMapping处理映射器,根据请求路径找到相对于的HandlerAdapter处理适配器(拦截器或者)controller
     3.HandleAdapter处理器适配器,处理一些功能请求,返回一个ModelAndView
     4.ViewResolver视图解析器,根据modelAndView中的设置View解析具体视图,
     5.将Model模型中的数据渲染到View上。
    
  • Spring MVC 启动流程 需要看的

     SpringMVC启动过程一局两个配置大致分为两个过程
         1.ContextLoaderListener初始化,实例化IoC容器,并将此容器实例注册到ServletContent中
         2.DispatcherServlet初始化,建立上下文,也注册到ServletContext.
    
  • Spring 的单例实现原理

     懒汉、饿汉、静态内部类、枚举,这些单例模式的构造方法都是私有的,不可继承,spring为实现单例类可继承,使用的是单例注册表。
         1、使用map实现注册表  2.使用protected修饰构造方法
    
  • Spring 框架中用到了哪些设计模式

     1.代理模式——在AOP和remoting中被使用的比较多,同样用到反射
     2.单例模式——单例注册表,在配置文件中定义的bean默认为单例模式
     3.模板方法——用来解决代码重复的问题,比如RestTemplate JmsTemplate
     4.工厂方法——BeanFactory用来创建对象的实例。
     5.适配器——spring aop
     6.装饰器——spring data hashmapper
     7.观察者——spring 时间驱动模型,applicationListener
     8.回调—— spring ResourceLoadAware回调接口
     9.策略模式
    
  • Spring 其他产品(Srping Boot、Spring Cloud、Spring Secuirity、Spring Data、Spring AMQP 等)

     1.Srping Boot:
     2.Spring Cloud:
     3.Spring Secuirity:
     4.Spring Data:
     5.Spring AMQP:
    
  • 有没有用到Spring Boot,Spring Boot的认识、原理

     自动配置
    
  • MyBatis的原理

     mybatis是什么:
         mybatis是一个优秀的持久层框架,对JDBC操作数据库的过程进行了封装,使开发者只需要关注sql本身,不去关注例如注册驱动,加载连接,得到statement ,处理结果集等过程。
         mabatis通过xml或者注解的方式,将需要执行的各种sql语句配置起来,并通过Java对象与statement中的sql语句映射生成最终的sql语句,交给mybatis框架执行sql语句,并将结果映射Java对象返回
     工作原理:
         mybatis通过配置文件创建sqlsessionFactory,根据配置文件来源于1.xml 2.注解 获取sqlSession。sqlSession包含了执行sql语句的所有方法。
         可以通过sqlSession直接运行映射的sql语句,完成对数据的增删改查和事务的提交工作,用完之后关闭sqlsession.
     工作流程:
         mapper接口:
             接口的全类名是xml文件中namespace的值。
                 接口的方法名是xml文件中mapperstatement的id值。
                 接口中的方法的参数就是传递给sql的参数
                 mapper接口是没有实现类的,当调用一个方法时,接口的全类名定位一个配置文件,接口的方法名定位这个配置文件中的一个namestatement,所以mapper的方法名是不能
                 是不能被重载的, 因为mapperStatement的保存和寻找策略。
                 mapper接口的工作原理,mybatis会使用JDK动态代理接口创建proxy对象,代理对象会拦截接口中的防范,转而执行mapperstatment锁代表的sql语句,然后将捷酷封装返回。
         mybatis解决的问题:
             1.使用数据库连接池管理链接,避免频繁创建、关闭连接带来的性能资源问题。
             2.xml管理sql语句,让Java代码与sql分离,代码更加容易维护。
             3.条件参数,将Java对象颜射到sql语句,通过statement的parameterType定义输入的参数的类型。
             4.将结果集封装成Java对象,通过statement的resyltType定义输出的类型。避免因为sql变化,对结果集厂里麻烦的问题。
    
3.2、Netty
  • 为什么选择 Netty

  • 说说业务中,Netty 的使用场景

  • 原生的 NIO 在 JDK 1.7 版本存在 epoll bug

  • 什么是TCP 粘包/拆包

  • TCP粘包/拆包的解决办法

  • Netty 线程模型

  • 说说 Netty 的零拷贝

  • Netty 内部执行流程

  • Netty 重连实现

3.3、Tomcat
  • Tomcat的基础架构(Server、Service、Connector、Container)

  • Tomcat如何加载Servlet的

  • Pipeline-Valve机制

  • 可参考:《四张图带你了解Tomcat系统架构!》

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,490评论 18 139
  • 人一生下来,原本是一张白纸,等着自己持笔来完成这一幅盛世大作,却被人嘲笑说根本不可能。 当你表现的对某种东西感兴趣...
    dream大梦阅读 350评论 0 1
  • 今天想跟大家分享一个关于cocopoads管理依赖库的经历,我接手了一个别人开发了一个版本的项目。原项目没有使用c...
    Alvin_d372阅读 3,488评论 0 0
  • 本次出游,实实在在感受到了幸福就是一家人在一起开开心心、快快乐乐! 这一天是这两年内最幸福快乐的一天!平常就一直说...
    霜霜_bb0c阅读 3,728评论 0 2
  • 放学路上,李航嘟嘟囔囔地背诵“飞呀飞呀“的儿歌。 “我们来让鸡蛋飞!”杨飞突发奇想说。 张新打趣道:“让狗蛋飞还差...
    三门峡014张丽娜阅读 1,056评论 5 10