基于【程序员哪些事】微信公众号《如何准备阿里社招面试,顺谈Java程序员学习中各阶段的建议》中的罗列问题的总结

今天读了《如何准备阿里社招面试,顺谈Java程序员学习中各阶段的建议》,一直对作者是一个仰视的姿势,崇拜已久,为了便于自己学习和总结,在这里对文中出现的几个技术问题进行了学习,在这进行如下总结:

1、HashMap 有顺序吗?

答:Hashmap 是一个最常用的Map,它根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快的访问速度,遍历时,取得数据的顺序是完全随机的。

2、有没有有顺序的Map实现类?他们是如何保证他们的顺序的它们两个哪个的有序实现比较好?

答:TreeMapLinkedHashMap

TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。

LinkedHashMap保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的.也可以在构造时用带参数,按照应用次数排序。

TreeMap取出来的是排序后的键值对。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。
LinkedHashMap 是HashMap的一个子类,如果需要输出的顺序和输入的相同,那么用LinkedHashMap可以实现,它还可以按读取顺序来排列,像连接池中可以应用。

3、如果想实现所有的线程一起等待某个事件的发生,当某个事件发生时,所有线程一起开始往下执行的话,有什么好的办法吗?

答:栅栏

  • 栅栏类似闭锁,但是它们是有区别的.
    闭锁用来等待事件,而栅栏用于等待其他线程.什么意思呢?就是说闭锁用来等待的事件就是countDown事件,只有该countDown事件执行后所有之前在等待的线程才有可能继续执行;而栅栏没有类似countDown事件控制线程的执行,只有线程的await方法能控制等待的线程执行.

  • CyclicBarrier强调的是n个线程,大家相互等待,只要有一个没完成,所有人都得等着。

  • 原文链接:http://blog.csdn.net/csujiangyu/article/details/44338307
4、IO包的结构?

原文链接:http://blog.csdn.net/yczz/article/details/38761237


5、NIO中selector的功能及实现原理?

功能:Selector(选择器)是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件。这样,一个单独的线程可以管理多个channel,从而管理多个网络连接。

原理:原文链接:http://www.cnblogs.com/huaf/archive/2011/02/12/2373002.html

Selector是用来获取注册在其中的channel的相关事件的发生,也就是accept,read和write。selector中有3个key set。 

key set:包含代表所有在其中注册的channel,可以通过selector.keys()得到。 
selected-key set:包含所有被检测到有关注的操作已经就绪的key,通过selector.selectedKeys得到。 
cancelled-key set:包含所有已经被cancel,但是还没有channel还没有deregister的key,这个集合是不能直接被访问的。

key通过调用channel的register方法被加入到key set中。被取消的key在select的时候会被从相应的key set中移除。

key set自身是不可以直接进行修改的。 无论是通过调用channel的close方法还是调用key的cancel方法,key都会被放置到canceled-key set中。取消的key会将其channel在下一次select时将注册撤销,同时将key从所有的key set中移除。 

key在执行select操作时被加入到selected-key set中。在selected-key set中的key可以通过调用iterator的remove方法,将其从selected-key set中移除,不能通过其他的办法将其从selected-key set中移除。

通过selector的3个方法select(阻塞选择,直到有关心的事件发生时退出阻塞),selectNow(不阻塞选择),select(long)(指定超时选择,超时到达或者有关心事件发生时退出阻塞),来获取关心事件的发生。其执行步骤分为以下3步: 

1、将存在于canceled-key set中的key从所有的key set中移除,撤销注册的channel,清空canceled-key set。 
2、地层操作系统检查是否有关心的事件发生,当有关心的事件发生时,首先检查channel的key是否已经存在于selected-key set中,如果不存在,则将其加入到selected-key set中去,同时修改key的ready-operation set来表明当前ready的操作,而以前存在于ready-operation set中的信息会被删除。如果对应的key已经存在于selected-key set中,这直接修改其ready-operation set来表明当前ready的操作,删除原来ready-operation set中的信息。 
3、如果在第二步中有加入到canceled-key set中的key,在这一步会执行第一步的操作。 

selector自身是线程安全的,而他的key set却不是。在一次选择发生的过程中,对于key的关心事件的修改要等到下一次select的时候才会生效。另外,key和其代表的channel有可能在任何时候被cancel和close。因此存在于key set中的key并不代表其key是有效的,也不代表其channel是open的。如果key有可能被其他的线程取消或关闭channel,程序必须小心的同步检查这些条件。

6、什么时候一个对象会被GC?

答:gc判读一个对象是否要被回收,主要是依据这个对象是否可达。
不能仅仅根据引用数量来确定一个对象是否可以被回收,比如:对象A被对象B引用,但对象B本身已经处于不可达状况,这样对象A和对象B就形成一个孤岛,下一次回收的时候A和B都会被回收。

7、GC都有哪些分类?这些策略分别都有什么优劣势?都适用于什么场景?

  1. 串行垃圾回收器(Serial Garbage Collector)
  2. 并行垃圾回收器(Parallel Garbage Collector)
  3. 并发标记扫描垃圾回收器(CMS Garbage Collector)
  4. G1垃圾回收器(G1 Garbage Collector
原文链接:垃圾回收器种类:http://www.importnew.com/13827.html

8、Java的类加载器都有哪些?每个类加载器都加载哪些类?这些类加载之间的父子关系是怎样的?


主要分为Bootstrap ClassLoader、Extension ClassLoader、Application ClassLoader和User Defined ClassLoader。

启动类加载器(Bootstrap ClassLoader):

这个类加载器使用C++语言实现,并非ClassLoader的子类。主要负责加载存放在JAVA_HOME /  jre /  lib / rt.jar里面所有的class文件,或者被-Xbootclasspath参数所指定路径中以rt.jar命名的文件。

扩展类加载器(Extension ClassLoader):

这个加载器由sun.misc.Launcher$ExtClassLoader实现,它负责加载AVA_HOME /  lib / ext目录中的,或者被java.ext.dirs系统变量所指定的路径中的所有类库。

应用程序类加载器(Application ClassLoader):

这个加载器由sun.misc.Launcher$AppClassLoader实现,它负责加载classpath对应的jar及目录。一般情况下这个就是程序中默认的类加载器。

自定义类加载器(User Defined ClassLoader):

开发人员继承ClassLoader抽象类自行实现的类加载器,基于自行开发的ClassLoader可用于并非加载classpath中(例如从网络上下载的jar或二进制字节码)、还可以在加载class文件之前做些小动作 如:加密等。

原文链接:http://www.importnew.com/22270.html

9、什么是双亲委派模型?为什么Java的类加载器要使用双亲委派模型?

上图中所展示的类加载器之间的这种层次关系,就称为类加载器的双亲委托模型。双亲委托模型要求除了顶层的启动类加载器外,其余的类加载器都应当有自己的父类加载器。这里类加载器之间的父子关系一般不会以继承的关系来实现,而是使用组合关系来复用父加载器的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
public abstract class ClassLoader { 
 
    privatestatic nativevoid registerNatives(); 
    static
        registerNatives(); 
    
 
    // The parent class loader for delegation 
    privateClassLoader parent; 
 
    // Hashtable that maps packages to certs 
    privateHashtable package2certs = newHashtable(11); 
}

双亲委托的工作过程:如果一个类加载器收到了一个类加载请求,它首先不会自己去加载这个类,而是把这个请求委托给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父类加载器反馈自己无法完成加载请求(它管理的范围之中没有这个类)时,子加载器才会尝试着自己去加载。

使用双亲委托模型来组织类加载器之间的关系,有一个显而易见的好处就是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,例如java.lang.Object存放在rt.jar之中,无论那个类加载器要加载这个类,最终都是委托给启动类加载器进行加载,因此Object类在程序的各种类加载器环境中都是同一个类,相反,如果没有双亲委托模型,由各个类加载器去完成的话,如果用户自己写一个名为java.lang.Object的类,并放在classpath中,应用程序中可能会出现多个不同的Object类,java类型体系中最基本安全行为也就无法保证。




  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值