9月24面试查漏补缺

包装类了解?Integer为什么超过127不能用==比较,其底层原理是什么

Integer类内部通过静态内部类提供了一个缓存池,范围在-128~127之间,如果超过这个范围 Integer 值都是new出来的对象

public static Integer valueOf(int paramInt) {
        assert (IntegerCache.high >= 127);
        if ((paramInt >= -128) && (paramInt <= IntegerCache.high))
            return IntegerCache.cache[(paramInt + 128)];
        return new Integer(paramInt);
}

volatile有什么特性?每个特性是怎么实现的?没有volatile多线程访问变量内部实现又是怎么样的?

volatile特性:可保证有序性、可见性

有序性原理:

通过插入内存屏障来禁止指令重排。

可见性原理:

  1. 每个处理器会通过嗅探总线上的数据来查看自己的数据是否过期,一旦处理器发现自己缓存对应的内存地址被修改,就会将当前处理器的缓存设为无效状态。此时,如果处理器需要获取这个数据需重新从主内存将其读取到本地内存。
  2. 当处理器写数据时,如果发现操作的是共享变量,会通知其他处理器将该变量的缓存设为无效状态

java内存模型:

Java内存模型的一个抽象概念,它包含了控制器、运算器、缓存等,本地内存并不是真实存在的。同时Java内存模型规定,线程对共享变量的操作必须在自己的本地内存中进行,不能直接在主内存中操作共享变量。这种内存模型会出现什么问题呢?,

|线程A|。。。。。。|线程B|

↓。。。。。。。。。。↓

|本地内存A|。。。|本地内存B|

↓。。。。。。。。。。↓

----------------主内存----------------

​ 共享变量X

----------------主内存----------------

  1. 线程A获取到共享变量X的值,此时本地内存A中没有X的值,所以加载主内存中的X值并缓存到本地内存A中,线程A修改X的值为1,并将X的值刷新到主内存中,这时主内存及本地内存中的X的值都为1。
  2. 线程B需要获取共享变量X的值,此时本地内存B中没有X的值,加载主内存中的X值并缓存到本地内存B中,此时X的值为1。线程B修改X的值为2,并刷新到主内存中,此时主内存及本地内存B中的X值为2,本地内存A中的X值为1。
  3. 线程A再次获取共享变量X的值,此时本地内存中存在X的值,所以直接从本地内存中A获取到了X为1的值,但此时主内存中X的值为2,到此出现了所谓内存不可见的问题。

Linux中查询一个文件的某个字符怎么实现?

grep “要查找的字符串” 文件名

Linux中怎么将日志文件内容实时打印到控制台

tail -f xxx.log

Map使用put过程是怎么样的?为什么实际使用更多地用String类型来当key?

put的过程:

  1. HashMap底层是使用Entry对象数组存储的,而Entry是一个单项的链表,当调用一个put方法将一个键值对添加进来时先使用hash函数获取该对象的hash值。
  2. 然后调用indexFor方法查找该对象在数组中应该存储的下标。
  3. 如果该位置为空,就将value值插入。
  4. 如果该下标下不为空,如果这两个Entry的key通过equals比较返回true,新Entry的value将覆盖原有Entry的value,但key不会覆盖。
  5. 如果这两个Entry的key通过equals比较返回false,新添加的Entry将与集合中原有的Entry形成Entry链,而且新添加的Enetry位于Entry链的头部。

String类型当key:

  1. String 对象的 hashCode() 值是根据 String 对象的内容计算的,并不是根据对象的地址计算;
  2. String不可变的特性可以使得 hash 值也不可变,因此只需要进行一次计算。即使非String对象重写了hashCode和equals 方法也,不如String高效,因为String中缓存有个hash变量,它可以缓存hashCode,避免重复计算hashCode。

使用TreeSet时对自定义对象排序怎么实现?

自然排序(使用空参构造):

自定义类实现Comparable接口,并重写compareTo方法后,直接使用TreeSet对象进行添加。

比较器排序(使用有参构造):

另外提供一个实现了Comparator的接口的类,在new TreeSet时传入类对象。或直接使用匿名内部类实现。

class Mycompare implements Comparator<Person>{

    @Override
    public int compare(Person o1, Person o2) {
        return 0;
    }

}

Set<Person> set=new TreeSet<>(new Mycompare());
Set<Person> set = new TreeSet<>(new Comparator<Person>() {
    //采用匿名内部类传入比较器对象;
    @Override
    public int compare(Person o1, Person o2) {
    return 0;
    }
});

Comparable和Comparator的区别:

Comparable来自java.lang包,Comparator来自java.util包

很多常用类都实现了Comparable接口,像Integer、String等,所以直接调用Collection.sort直接可以使用。当对类自带的自然排序不满意而又不能修改其源代码的情况,使用Comparator比较合适。

使用Comparator可以避免添加额外的代码与我们的目标类耦合,同时可以定义多种排序规则,这一点Comparable无法做到。

BIO,NIO,AIO?

BIO(blocking I/O):

同步阻塞IO,使用BIO当前线程只能进行IO操作。服务器实现模式为一个连接一个线程,即客户端有连接请求时服务就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,可以通过线程池机制改善。

NIO (non-blocking I/O):

同步非阻塞IO,基于Reactor模型。NIO利用了单线程轮询事件机制。服务器实现模式为一个请求一个线程,即课客户端发生的连接请求都会注册到多路复用器上,多路复用器轮询到连接有IO请求时才启动一个线程进行处理。

应用场景:聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持

AIO(Asynchronous I/O) :

异步非阻塞IO,基于Proactor模型的。它不是在IO准备好时再通知线程,而是在IO操作已经完成以后由操作系统再给线程发出通知。因此AIO是不会阻塞的。服务器实现模式为一个有效请求一个线程。

应用场景:相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值