Fork me on GitHub

蚂蚁金服HR电话面

1、先自我介绍一下。

2、问到项目问题。(项目介绍,用到哪些技术,如何测试的。)

3、一些基础知识。

  a) list、map、set是继承了collection的吗? 

   

  List:1.可以允许重复的对象。

      2.可以插入多个null元素。

          3.是一个有序容器,保持了每个元素的插入顺序,输出的顺序就是插入的顺序。

          4.常用的实现类有 ArrayList、LinkedList 和 Vector。ArrayList 最为流行,它提供了使用索引的随意访问,而 LinkedList 则对于经常需要从 List 中添加或删除元素的场合更为合适。

  Set:1.不允许重复对象

        2. 无序容器,你无法保证每个元素的存储顺序,TreeSet通过 Comparator  或者 Comparable 维护了一个排序顺序。

          3. 只允许一个 null 元素

          4.Set 接口最流行的几个实现类是 HashSet、LinkedHashSet 以及 TreeSet。最流行的是基于 HashMap 实现的 HashSet;TreeSet 还实现了 SortedSet 接口,因此 TreeSet 是一个根据其 compare() 和 compareTo() 的定义进行排序的有序容器。

  Map:1.Map不是collection的子接口或者实现类。Map是一个接口。

    2.Map 的 每个 Entry 都持有两个对象,也就是一个键一个值,Map 可能会持有相同的值对象但键对象必须是唯一的。

    3. TreeMap 也通过 Comparator  或者 Comparable 维护了一个排序顺序。

    4. Map 里你可以拥有随意个 null 值但最多只能有一个 null 键。

    5.Map 接口最流行的几个实现类是 HashMap、LinkedHashMap、Hashtable 和 TreeMap。(HashMap、TreeMap最常用)

  b) 进程和线程

    1)调度。线程是独立调度的基本单位;进程是拥有资源的基本单位。同一进程中,线程的切换不会引起进程切换,不同进程中线程切换,会引起进程切换。

    2)拥有资源。进程是拥有资源的基本单位,线程可以访问隶属进程的系统资源。

    3)并发性。进程之间可并发,线程也可,使操作系统有更好的并发性,提高系统吞吐量。

    4)系统开销。创建撤销进程时系统为之分配或回收资源,如内存空间,I/O设备。远大于线程开销。在进程切换时,涉及当前执行进程CPU环境的保存及新调度到进程CPU环境的设 置,线程切换时需保存和设置少量寄存器内容,开销小。此外,同一进程内的多线程共享进程的地址空间,因此线程间同步与通信很容易。

    5)地址空间和其他资源。进程的地址空间相互独立,同一进程的各线程间共享进程的资源,某进程内的线程对于其它进程不可见。

    6)通信方面。进程间通信(IPC)需要进程同步与互斥手段的辅助,保证数据的一致性,而线程间可直接读/写进程数据段(如全局变量)来进行通信。

  

  c)overload和override

    1、方法的覆盖是子类和父类之间的关系,是垂直关系;方法的重载是同一个类中方法之间的关系,是水平关系。

 

    2、覆盖只能由一个方法,或只能由一对方法产生关系;方法的重载是多个方法之间的关系。

 

    3、覆盖要求参数列表相同;重载要求参数列表不同。

 

    4、覆盖关系中,调用那个方法体,是根据对象的类型来决定;重载关系,是根据调用时的实参表与形参表来选择方法体的。

  

  d) hashmap和hashtable

    HashMap 是线程不安全的,HashMap 是一个接口,是 Map的一个子接口,是将键映射到值得对象,不允许键值重复,允许空键和空值;由于非线程安全, HashMap的效率要较 HashTable 的效率高一些. 

    HashTable 是线程安全的一个集合,不允许 null 值作为一个 key 值或者 Value 值;
    HashTable 是 sychronize(同步化),多个线程访问时不需要自己为它的方法实现同步,而 HashMap 在被多个线程访问的时候需要自己为它的方法实现同步;   

           

    主要体现在:线程安全性,同步(synchronization),以及速度。

  1. HashMap几乎可以等价于Hashtable,除了HashMap是非synchronized的,并可以接受null(HashMap可以接受为null的键值(key)和值(value),而Hashtable则不行)。
  2. HashMap是非synchronized,而Hashtable是synchronized,这意味着Hashtable是线程安全的,多个线程可以共享一个Hashtable;而如果没有正确的同步的话,多个线程是不能共享HashMap的。Java 5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的扩展性更好。
  3. 另一个区别是HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。这条同样也是Enumeration和Iterator的区别。
  4. 由于Hashtable是线程安全的也是synchronized,所以在单线程环境下它比HashMap要慢。如果你不需要同步,只需要单一线程,那么使用HashMap性能要好过Hashtable。
  5. HashMap不能保证随着时间的推移Map中的元素次序是不变的。

  

  e) sleep和wait    

    1、这两个方法来自不同的类分别是,sleep来自Thread类,和wait来自Object类。sleep是Thread的静态类方法,谁调用的谁去睡觉,即使在a线程里调用了b的sleep方法,实际上还是a去睡觉,要让b线程睡觉要在b的代码中调用sleep。

    2、最主要sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。sleep不出让系统资源;wait是进入线程等待池等待,出让系统资源,其他线程可以占用CPU。一般wait不会加时间限制,因为如果wait线程的运行资源不够,再出来也没用,要等待其他线程调用notify/notifyAll唤醒等待池中的所有线程,才会进入就绪队列等待OS分配系统资源。sleep(milliseconds)可以用时间指定使它自动唤醒过来,如果时间不到只能调用interrupt()强行打断。Thread.Sleep(0)的作用是“触发操作系统立刻重新进行一次CPU竞争”。

    3、使用范围:wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用  
     synchronized(x){  
          x.notify()  
         //或者wait()  
     }

    4、sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常

  

  f) exception和error

  Error和Exception都继承自Throwable;

  二者不同之处:

  Exception:

  1.可以是可被控制(checked)或者不可控制(unchecked);

  2.表示一个由程序员导致的错误;

  3.应该在应用程序级被处理; 

  Error:

  1.总是不可控制的(unchecked);

  2.经常用来表示系统错误或者底层资源错误;

  3.如果可能的话,应该在系统级被捕捉;

  

  g) GC

   什么是GC?

    Garbage Collection,垃圾收集,垃圾回收,是Java与C++/C的主要区别之一,作为Java开发者,一般不需要专门编写内存回收和垃圾清理代 码,对内存泄露和溢出的问题,也不需要像C程序员那样战战兢兢。这是因为在Java虚拟机中,存在自动内存管理和垃圾清扫机制。概括地说,该机制对 JVM(Java Virtual Machine)中的内存进行标记,并确定哪些内存需要回收,根据一定的回收策略,自动的回收内存,永不停息(Nerver Stop)的保证JVM中的内存空间,放置出现内存泄露和溢出问题

  

  怎么理解GC?

    Java GC机制主要完成3件事:确定哪些内存需要回收,确定什么时候需要执行GC,如何执行GC。

 

  GC算法

    我们一般讨论的垃圾回收主要针对Java堆内存中的新生代和老年代,也正因为新生代和老年代结构上的不同,所以产生了分代回收算法,即新生代的垃圾回收和老年代的垃圾回收采用的是不同的回收算法。针对新生代,主要采用复制算法,而针对老年代,通常采用标记-清除算法或者标记-整理算法来进行回收。

  

  h) 如何建立索引更高效

  1、较频繁的作为查询条件的字段应该创建索引.

  2、唯一性太差的字段不适合单独创建索引,即使频繁作为查询条件。

  3、更新非常频繁的字段不适合创建索引。

  4、频繁在where从句、join关联字段中出现。

  5、不要在常被修改到字段上建索引。

  6、主键外键上建立索引。

  7、创建一个索引时,评估该索引给查询带来的性能优化是否比因其而引起INSERT,UPDATE,DELETE操作的性能下降以及索引占用的空间更要值得。

  

  i) 死锁

  死锁是什么?

    死锁是指多个进程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进。例如,在某一个计算机系统中只有一台打印机和一台输入 设备,进程P1正占用输入设备,同时又提出使用打印机的请求,但此时打印机正被进程P2 所占用,而P2在未释放打印机之前,又提出请求使用正被P1占用着的输入设备。这样两个进程相互无休止地等待下去,均无法继续执行,此时两个进程陷入死锁状态。

 

  死锁产生的原因

    1. 系统资源的竞争

    系统资源的竞争导致系统资源不足,以及资源分配不当,导致死锁。

 

    2. 进程运行推进顺序不合适

 

    进程在运行过程中,请求和释放资源的顺序不当,会导致死锁。

  

  死锁的四个必要条件

    互斥条件:一个资源每次只能被一个进程使用,即在一段时间内某 资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。

    请求与保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源 已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。

    不可剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能 由获得该资源的进程自己来释放(只能是主动释放)。

    循环等待条件: 若干进程间形成首尾相接循环等待资源的关系

    这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。

  

  死锁的避免与预防死锁避免的基本思想:

    系统对进程发出的每一个系统能够满足的资源申请进行动态检查,并根据检查结果决定是否分配资源,如果分配后系统可能发生死锁,则不予分配,否则予以分配,这是一种保证系统不进入死锁状态的动态策略。 如果操作系统能保证所有进程在有限时间内得到需要的全部资源,则系统处于安全状态否则系统是不安全的。   

    我们可以通过破坏死锁产生的4个必要条件来 预防死锁,由于资源互斥是资源使用的固有特性是无法改变的。

  1. 破坏“不可剥夺”条件:一个进程不能获得所需要的全部资源时便处于等待状态,等待期间他占有的资源将被隐式的释放重新加入到 系统的资源列表中,可以被其他的进程使用,而等待的进程只有重新获得自己原有的资源以及新申请的资源才可以重新启动,执行。
  2. 破坏”请求与保持条件“:第一种方法静态分配即每个进程在开始执行时就申请他所需要的全部资源。第二种是动态分配即每个进程在申请所需要的资源时他本身不占用系统资源。
  3. 破坏“循环等待”条件:采用资源有序分配其基本思想是将系统中的所有资源顺序编号,将紧缺的,稀少的采用较大的编号,在申请资源时必须按照编号的顺序进行,一个进程只有获得较小编号的资源才能申请较大编资源的进程。

 

 
 
 

 

posted @ 2019-04-11 22:39  皮皮丶码  阅读(315)  评论(0编辑  收藏  举报