JAVA面试:记一次阿里电话面试(中)
Posted 残留的存在主义
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA面试:记一次阿里电话面试(中)相关的知识,希望对你有一定的参考价值。
最新发现老天挺照顾我的,有两三个月了,没有再让我在上班的路上肚子疼痛到要立马解决,说来奇妙,这种疼痛总是拖延到我已经在公司楼下等电梯的那一刻才爆发出,就这么一回事,我想不到不感谢上苍的理由,嗯,这样才不会觉得自己很废材。
什么时候觉得废材呢?比如昨天晚上,吃快餐,看到隔壁桌的男子点了一瓶啤酒,好生羡慕,同时,对自己有种巨大的失落感。
回到家里,只想赶快喝药睡觉,在睡觉前能够读一读毛姆的文字就更好了,他教我崇尚自由,又教我热爱生活。
钟爱毛姆的文字,曾经怀疑是因为青年的迷茫与向往自由,可即便当自由仅仅是每天的繁忙挤出的一丝闲暇、当生活每天对我露出狰狞面孔的时候,也钟爱着毛姆的文字,这使我愈发好奇,究竟毛姆的文字的魅力在哪里?更令我好奇的是,如果有一天,我不再钟爱毛姆的文字,那该是经历了什么样的事?堕落、抑或是突破。
两大容器
容器可以管理对象的生命周期、对象与对象之间的依赖关系,你可以使用一个配置文件,在上面定义好对象的名称、如何产生(Prototype 方式或Singleton 方式)、哪个对象产生之后必须设定成为某个对象的属性等,在启动容器之后,所有的对象都可以直接取用,不用编写任何一行程序代码来产生对象,或是建立对象与对象之间的依赖关系。
这正是Spring框架带给我们的好处。
Spring的两大容器是BeanFactory与ApplicationContext.
BeanFactory是比较原始的Factory,采用延迟加载形式注入bean,只有在使用每个bean(调用getBean()),才进行实例化。无法支持Spring的很多插件,如AOP功能、web应用等;
ApplicationContext是在容器启动时,一次性创建了所有的bean。
IOC/DI与AOP
可以参照我之前写的文章:
事务
a.事务的四大特性(ACID)
原子性、一致性、隔离性、持久性
b.编程式事务与声明式事务
编程式:通过编码方式实现事务,类似于JDBC实现事务管理。对于编程性事务,Spring推荐使用TranscationTemplate。
声明式:基于AOP技术实现的声明式事务管理,实质就是:在方法执行前后进行拦截,然后在目标方法开始之前创建并加入事务,执行完目标方法后根据执行情况提交或回滚事务。 声明式事务管理又有两种方式:基于XML配置文件的方式;另一个是在业务方法上进行@Transactional注解,将事务规则应用到业务逻辑中。 (非侵入式开发)
对于底层使用的是JDBC或者iBatis持久化API的应用,Spring采用的实现类是DataSourceTransactionMaange.
c.传播行为
d.隔离级别
事务的隔离级别有4个,由低到高依次为Read uncommitted、Read committed、Repeatable read、Serializable,这四个级别可以逐个解决脏读(读错)、不可重复读(针对update修改数据)、幻读(针对insert增加记录),如下:
线程池
Spring使用ThreadPoolTaskExecutor可实现一个基于线程池的TaskExecutor
配置示例如下(注意几个主要参数):
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<!-- 线程池维护线程的最少数量 -->
<property name="corePoolSize" value="5" />
<!-- 允许的空闲时间 -->
<property name="keepAliveSeconds" value="200" />
<!-- 线程池维护线程的最大数量 -->
<property name="maxPoolSize" value="10" />
<!-- 缓存队列 -->
<property name="queueCapacity" value="20" />
<!-- 对拒绝task的处理策略 -->
<property name="rejectedExecutionHandler">
<bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />
</property>
</bean>
乐观锁与悲观锁
悲观锁,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
乐观锁,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。
java.util.concurrent包
a.CountDownLatch
允许一个或多个线程等待一系列指定操作的完成。可用于统计。
b.ConcurrentHashMap
线程安全的HashMap,可参考
c.ExecutorService
用于创建线程池
d.Executor
具体Runnable任务的执行者
e.BlockingQueue
阻塞队列
CAS算法
CAS(Compare And Swap):比较并交换。
java.util.concurrent包中借助CAS实现了区别于synchronouse同步锁的一个乐观锁。CAS有三个操作数,内存制V、旧的预期值A、要修改的新值B,当且仅当预期值A与内存值V相同时,将内存值V改为B,否则do nothing.
CAS会产生ABA问题,可以参照:https://www.cnblogs.com/onlywujun/articles/3529572.html
(因为CAS需要在操作值的时候检查下值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了。ABA问题的解决思路就是使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加一,那么A-B-A 就会变成1A-2B-3A。
从Java1.5开始JDK的atomic包里提供了一个类AtomicStampedReference来解决ABA问题。这个类的compareAndSet方法作用是首先检查当前引用是否等于预期引用,并且当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。)
多线程\线程池
Java通过Executors提供四种线程池,分别为:
a.newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
b.newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
c.newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
d.newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
在Spring中,通过任务执行器,也就是TaskExecutor来实现多线程和并发编程。
使用ThreadPoolTaskExecutor可实现一个基于线程池的TaskExecutor。
使用哪些数据库
可参考本人文章:
数据库引擎
主要是mysql的MyIsam、CSV与InnoDB数据库引擎。
InnoDB是一个事务型的存储引擎,有行级锁定和外键约束,适用于以下的场合:
a. 更新多的表,适合处理多重并发的更新请求。
b. 支持事务。
c. 可以从灾难中恢复(通过bin-log日志等)。
d. 外键约束。只有他支持外键。
e. 支持自动增加列属性auto_increment。
想看原创小说、诗词、游记与食谱的,可关注下面这位美女 雪言齋
以上是关于JAVA面试:记一次阿里电话面试(中)的主要内容,如果未能解决你的问题,请参考以下文章
「真实分享」三年经验,记一次4月阿里Java面试,谈谈心酸历程!