面试题:Java 如何开启线程?怎么保证线程安全?
在回答这个问题之前,我们首先来回答线程和进程的区别。进程是操作系统进行资源分配的最小单元,那么线程是操作系统进行任务分配的最小单元,那么县城隶属于进城。接下来回答如何开启线程,那么有 4 个方法,第一,继承thread,实现 run 方法第二,实现 reliable 接口,实现 run 方法三实现 countable 接口,实现靠方法。那么通过 fact task 创建一个线程,获取到线程执行的返回值。那第四个通过线程池来开启线程,那么怎么保证线程的安全?首先加锁有两种方式,第一种就是通过 JVM 提供的锁,也就是新的 rest 的关键字来加锁,第二个可以通过 JDK 提供的各种锁local。
面试题:Java池化技术你了解多少?
首先来看一下 Java 中公用的池化包 Commons Pool 2,来了解一下对象池的一般结构。根据我们的业务需求,使用这套 API 能够很容易实现对象的池化管理。
面试题:简单说说Java有哪些数据类型
答:①分为基本数据类型和引用数据类型。②基本数据类型包括:数值型(byte、short、int、long、float、double),字符型(char)以及布尔型(boolean)。除了基本类型外,其他数据类型都属于引用类型,包括类、接口、数组等。
面试题:float number=3.4;有没有问题?为什么?
答:有问题,因为3.4 是双精度数,将双精度型(double)赋值给浮点型(float)属于向下转型,可能会造成精度损失,所以必须进行强制类型转换,正确的写法是float number =(float)3.4;/ float number =3.4F;。
面试题:使用Java池化技术时,把超时参数设置成多大呢?
答:对象池在进行初始化时,要指定三个主要的参数:
maxTotal 对象池中管理的对象上限
maxIdle 最大空闲数
minIdle 最小空闲数
其中 maxTotal 和业务线程有关,当业务线程想要获取对象时,会首先检测是否有空闲的对象。如果有,则返回一个;否则进入创建逻辑。此时,如果池中个数已经达到了最大值,就会创建失败,返回空对象。
对象在获取的时候,有一个非常重要的参数,那就是最大等待时间(maxWaitMillis),这个参数对应用方的性能影响是比较大的。该参数默认为 -1,表示永不超时,直到有对象空闲。
如下图,如果对象创建非常缓慢或者使用非常繁忙,业务线程会持续阻塞 (blockWhenExhausted 默认为 true),进而导致正常服务也不能运行。
一般都会把最大等待时间,设置成接口可以忍受的最大延迟。比如,一个正常服务响应时间 10ms 左右,达到 1 秒钟就会感觉到卡顿,那么这个参数设置成 500~1000ms 都是可以的。超时之后,会抛出 NoSuchElementException 异常,请求会快速失败,不会影响其他业务线程,这种 Fail Fast 的思想,在互联网应用非常广泛。
带有evcit 字样的参数,主要是处理对象逐出的。池化对象除了初始化和销毁的时候比较昂贵,在运行时也会占用系统资源。比如,连接池会占用多条连接,线程池会增加调度开销等。业务在突发流量下,会申请到超出正常情况的对象资源,放在池子中。等这些对象不再被使用,我们就需要把它清理掉。
超出 minEvictableIdleTimeMillis 参数指定值的对象,就会被强制回收掉,这个值默认是 30 分钟;softMinEvictableIdleTimeMillis 参数类似,但它只有在当前对象数量大于 minIdle 的时候才会执行移除,所以前者的动作要更暴力一些。
还有 4 个 test 参数:testOnCreate、testOnBorrow、testOnReturn、testWhileIdle,分别指定了在创建、获取、归还、空闲检测的时候,是否对池化对象进行有效性检测。
开启这些检测,能保证资源的有效性,但它会耗费性能,所以默认为 false。生产环境上,建议只将 testWhileIdle 设置为 true,并通过调整空闲检测时间间隔(timeBetweenEvictionRunsMillis),比如 1 分钟,来保证资源的可用性,同时也保证效率。
面试题:讲一讲模板方法模式
答:①模板方法模式定义了一个算法框架,并通过继承的方式将算法的实现延迟到子类中,使得子类可以在不改变算法框架及其流程的前提下重新定义该算法在某些特定环节的实现,是一种类行为型模式。②该模式在抽象类中定义了算法的结构并实现了公共部分算法,在子类中实现可变的部分并根据不同的业务需求实现不同的扩展。模板方法模式的优点在于其父类(抽象类)中定义了算法的框架以及保障算法的稳定性,同时在父类中实现了算法公共部分的方法保证代码的复用,将部分算法延迟到子类实现,因此子类可以通过继承扩展或重新定义算法的功能而不影响稳定性,符合开闭原则。③抽象类:定义算法框架,由基本方法和模板方法组成。基本方法定义了算法有哪些环节,模板方法定义了算法各个环节执行的流程。具体子类:对在抽象类中定义的算法根据需求进行不同的实现。
面试题:讲一讲观察者模式
答:①观察者模式指在被观察者的状态发生变化时,系统基于事件驱动理论将其状态通知到订阅其状态的观察者对象中,以完成状态的修改和事件传播。观察者模式是一种对象行为模式,观察者和被观察者之间的关系属于抽象耦合关系,主要优点是观察者与被观察者之间建立了一套事件触发机制,以降低二者之间的耦合度。②观察者模式的主要角色如下:抽象主题Subject:持有订阅了该主题的观察者对象的集合,同时提供了增加删除观察者对象的方法和主题状态变化后的通知方法。具体主题Concrete Subject:实现了抽象主题的通知方法,在主题内部状态发生变化时,调用该方法通知订阅了主题状态的观察者对象。抽象观察者Observer:观察者的抽象类或接口,定义了主题状态变化时需要调用的方法。具体观察者 Concrete Observer:抽象观察者的实现类,在收到主题状态变化的信息后执行具体触发机制。
面试题:Java集合框架是什么?说出一些集合框架的优点?
每种编程语言中都有集合,最初的Java版本包含几种集合类:Vector、Stack、HashTable和Array。随着集合的广泛使用,Java1.2提出了囊括所有集合接口、实现和算法的集合框架。在保证线程安全的情况下使用泛型和并发集合类,Java已经经历了很久。它还包括在Java并发包中,阻塞接口以及它们的实现。集合框架的部分优点如下:
(1)使用核心集合类降低开发成本,而非实现我们自己的集合类。
(2)随着使用经过严格测试的集合框架类,代码质量会得到提高。
(3)通过使用JDK附带的集合类,可以降低代码维护成本。
(4)复用性和可操作性。
面试题:讲一讲迭代器模式
答:①迭代器模式提供了顺序访问集合对象中的各种元素,而不暴露该对象内部结构的方法。Java中的集合就是典型的迭代器模式,比如HashMap,当遍历HashMap时,需要迭代器不停地获取Next元素就可以循环遍历集合中所有元素。②迭代器模式将遍历集合中所有元素地操作封装成一个迭代器类,目的是在不暴露集合对象内部结构地情况下,对外提供统一访问集合内部数据的方法。迭代器的实现一般包括一个迭代器,用于执行具体的遍历操作,以及一个Collection,用于存储具体的数据。
面试题:讲一讲责任链模式
答:①责任链模式用于避免请求发送者与多个请求处理者耦合在一起,让所有请求的处理者持有下一个对象的引用,从而将请求串联成一条链,在有请求发生时,可将请求沿着这条链传递,直到遇到该对象的处理器。②该模式下用户只需将请求发送到责任链上即可,无需关心请求的处理细节和传递过程,所以责任链模式优雅地将请求的发送和处理进行了解耦。责任链模式常用于Web模式。③责任链模式包含以下三种角色:Handler接口:规定责任链上要执行的具体方法。AbstractHandler抽象类:持有Handler实例并通过get/set方法将各个具体的业务Handler串联成一个责任链,客户端上的请求在责任链上执行。业务Handler:用户根据具体的业务需求实现的业务逻辑。
面试题:遍历一个List有哪些不同的方式?
答:List strList = new ArrayList<>();
//使用for-each循环
for(String obj : strList){
System.out.println(obj);
}
//using iterator
Iterator it = strList.iterator();
while(it.hasNext()){
String obj = it.next();
System.out.println(obj);
}
使用迭代器更加线程安全,因为它可以确保,在当前遍历的集合元素被更改的时候,它会抛出ConcurrentModificationException。
面试题:死锁产生的原因和解决方法?
答:①死锁是多个进程竞争共享资源而造成互相等待的僵局,若无外力作用这些进程都将无法向前推进。②死锁产生的原因是非剥夺资源的竞争和进程的不恰当推进顺序。③预防死锁:破坏互斥条件、破坏不剥夺条件、破坏请求和保持条件、破坏循环等待条件。④预防死锁:安全状态:能找到一个分配资源的序列让所有进程都顺序完成。银行家算法:采用预分配策略检查分配完成时系统是否处于安全状态。⑤检测死锁:利用死锁定理化简资源分配图检测死锁的存在。⑥解除死锁:资源剥夺法:挂起某些死锁进程并抢夺它的资源,以便其他线程继续推进。撤销进程法:强制撤销部分、甚至全部进程并抢夺其资源,以便让其他进程继续推进。进程回退法:让一个或多个进程回退到足以避免死锁的地步。