Java面试题

  1. 重写equals方法时,必须同时重写hashCode方法?

○是√

○否

  1. 当一个线程进入一个对象的synchronized方法A之后,其它线程是否可进入此对象的synchronized方法B?

○是

○否√

  1. 下列哪个对象不可用于线程同步的实现?

○ReentrantLock

○Semaphore

○CountdownLatch

○FutureTask

○ThreadLocal√

  1. 下面哪个Set的插入和遍历顺序是一致的?

○LinkedHashSet√

○HashSet

○AbstractSet

○TreeSet

  1. 以下关于final关键字说法错误的是?

○final是java中的修饰符,可以修饰接口、抽象类√

○final修饰的类肯定不能被继承

○final修饰的方法不能被重载

○final修饰的变量不允许被再次赋值

  1. 请选择Java线程的几种实现方式?

□Runnable接口√

□继承Thread类√

□使用Excutor框架√

□Serializable接口

□Callable接口√

  1. 关于分布式系统里保证数据一致性的描述正确的是?

□可用synchronized关键字保证

□可以基于数据的版本号来实现乐观锁√

□调整数据库事务的隔离级别为串行化√

□推荐用Redis实现分布式锁√

  1. 在下列场景下,哪种排序是最快的?

场景:在一个数组里,大多数的数据是有序的,少部分是乱序的。

□冒泡排序

□选择排序

□插入排序√

□归并排序

□快速排序

  1. Redis支持的数据结构有?

□String√

□List√

□Set√

□Hash√

□Tuple

  1. 下列哪些与数据库性能优化相关?

□拆分联合索引以应对多变的SQL√

□使用外键

□Explain (Plan) √

□将嵌套查询中返回结果集较小的查询作为子查询√

□精准查询放在前,范围查询放在后面√

□尽量避免having语句√

浅谈微服务及十二要素

微服务

微服务架构是各种因素影响下的产生的一种新的架构风格。

  1. 使用传统的单体式架构应用开发系统,如CRM、ERP等大型应用,随着新需求的不断增加,企业更新和修复大型单体式应用变得越来越困难。
  2. 随着移动互联网的发展,企业被迫将其应用迁移至流行的UI界面以便能兼容移动设备,这要求企业能实现应用功能的快速上线。
  3. 随着应用云化的日益普及,生于云端的应用具有与传统IT不同的技术基因和开发运维模式,云端的庞大计算计算能力及互联网公司大量开源轻量级技术不停涌现并日渐成熟。
  4. 新的方法与工具,如敏捷,运维开发一体化,极限编程的出现。
  5. 简化的基础设施如操作系统虚拟化,容器化,基础设施即服务(IaaS),服务平台化(PaaS),以及软件即服务(SaaS)的概念和应用的深入。

受到以上各种因素的影响,微服务架构应运而生

1.    微服务定义

微服务是一个抽象统称,在不同的语境里有不同的含义。在具体的交流中,可以分为微服务架构、微服务系统、API或消息。

1.1           微服务架构

微服务架构是在单体应用高复杂度、业务单元无法拆解的背景下,为了提升交付效率和加大系统的弹性,采用将多个可独立进行开发、管理、迭代的单一功能的模块组合出复杂的大型应用系统、各功能模块使用与编程语言无关的API集合相互通讯的方式的一种新的关于系统整体结构的抽象描述,用于指导大型系统各个方面的设计。

1.2           微服务系统

采用微服务架构思路设计的系统,我们称之为微服务系统。

1.3           微服务(API或消息)

我们更倾向于把提供特定的具体的功能的可以被外部调用的实现叫做API(Application Programming Interface)或者消息,比如Rest API、ActiveMQ或者RocketMQ等。

2      微服务标准(微服务十二要素)

2.1     基准代码

一份基准代码,多份部署,基准代码和应用之间总是保持一一对应的关系。所有部署的基准代码相同,但每份部署可以使用其不同的版本。多个应用不可以共享同一份代码,可以将代码拆分独立的类库后通过依赖策略去加载。

2.2     显式依赖

通过依赖清单,明确的声明所有依赖项,在运行时,通过依赖隔离工具确保程序不会调用系统中存在却未声明的依赖项,开发环境与生产环境都应尊从。另外每个组件的依赖应该明确列出,由于多个组件存在相似的依赖,需要进行冗余依赖排除,减少版本冲突。

2.3     代码与配置分离

不建议将可配置的信息硬编码到程序中,可以存在在环境变量里,建议用配置中心存储各应用的配置,这样使用一套代码可以很方便的在不同环境上部署,启动时只需要指定配置环境,而不用改动任何代码,此配置应该与编程语言无关。

2.4     后端服务

把后端的服务当成资源。比如本地数据库,云数据库,消息服务,第三方服务,SMTP服务等,微服务系统不应区别对待本地还是第三方服务,不论使用本地服务还是使用云服务,通过URL或配置可以方便替换。禁止后端服务之间的耦合。

2.5     构建、发布、运行

严格的划分编译、发布、运行阶段,每个阶段由工具进行管理。持续集成,持续部署。如需修改运行的代码则需要重新进行构建、发布、运行三个环节,且顺序执行。三个环节可以手动执行,也可以自动执行。持续集成,持续发布一般在敏捷管理平台上进行管理。建议每个CI都只对应一套代码库。

2.6     无状态进程

应用必须为无状态应用,Session信息应该独立于应用存储,比如存储在Memcached或Redis中。需要持久化的数据应该存储于后端服务中,比如数据库mysql。在负载均衡策略上,由于应用的无状态性,所以要用轮询请求应用服务器的方式,以使各应用服务器的负载更加均衡。

2.7     数据隔离

建议只允许通过服务API 来访问服务的持久化数据,防止微服务之间隐式契约,确保微服务不能紧密耦合。不允许数据共享。微服务之间通过API或消息互相访问,也加大了微服务后台选型的灵活性,比如微服务后台数据库选型mysql还是oracle已经与服务调用者无关。

2.8     提升并发能力

进程优先于线程。通过横向扩展容器来提升吞吐能力,纵向扩展一般不推荐,比如增加内存,增加CPU核数,一般内存和CPU占用率过高都存在潜在的风险,需要优化程序逻辑。线程的使用要慎重,尽量减少线程的资源占用。

2.9     快速启动和优雅终止

在启动时应禁止自动执行的任务,及禁止同步加载大量数据,减少启动时间,这样有利于快速的对应用进行伸缩,快速响应配置和代码的变化。进程还应该在突然死亡时仍然保持健壮,比如重要数据要实时存储到后台。

2.10 开发与生产环境一致

缩小本地与线上差异,保证各环境的一致性,包括OS,容器规格,虚拟机规格,Tomcat版本,数据库版本,JDK版本,PaaS组件版本等,尽可能减少开发环境与生产环境的差异。

2.11 把日志当做事件流

应用应该把日志存储于日志云平台,不要自己存储在本地。要能够在终端看到应用的实时日志流,最好能够做到实时日志的聚合展示。通过日志要能够查询到每个服务的执行时间。

2.12 管理进程与其它应用进行使用同一份代码和配置

脚本,系统管理后台同样要用代码仓库管理,并且与应用代码保存在同一套代码库里,而且应该不受环境影响,要保证脚本可重复执行.

Mysql事务的串行化

串行读特别简单,就当成是对同一个批数据不允许并发操作,按顺序更新,插入,或者删除。

那么问题来了,同一批数据该如何界定?这是个问题。之前的看图说话中,似乎还没提到这个问题。

先看串行读,事务开启,先事务A select,然后事务B进行 update,注意,此时事务B是不可能马上提交成功的,要等事务A 提交后,事务B才会提交,这就是串行。(如果不start transaction,意味着未开启事务,那么就是自动提交,自动提交也是事务)

先看图说话:

事务A (下图B更新+1,A也更新+1)

下图为事务B 因为等待事务A的提交而超时。

基本上三种隔离级别都实验了。

对于开篇提出的疑问,“一批数据”指的到底是什么,经过实验,三种隔离级别里,都是对整张被查询的表进行隔离,而不管有没有where条件。这个隔离级别跟表锁和行锁不是一回事,莫混淆。

此时此刻应该再搞搞MVCC了。

Mysql事务的可重复读

Repeatable Read 即 可重复读。Mysql默认的隔离级别。

理解了不可重复读,再来看可重复读就简单的多,也就是不管其它事务B是否修改了该数据,事务A内读多次该数据都是一致的,当然有个前提就是事物A在多次读之前都没有对数据进行修改,插入,删除的操作,否则怎么会一致呢。

还有个小提示就是:事务A开启后,如果还没有执行任何语句,事务B进行了更新操作,那么事务A的第一次select结果一定是事物B操作后的。

看图说话:

隔离级别

下图事务A读两次,第一次读bill有1000块钱,红框表示事务B进行了update操作。

事务A

事务B更新

事务A第二次读的结果bill的钱仍是1000,与事务B更新后读出的结果不同。

事务A里读了两次都是1000,即可重复读。

可是,如果事务B更新为999块钱时,事务A进行更新操作把bill的钱减1,然后事务A再次读取,会显示Bill有多少钱呢,999还是998?在事务A执行中间,事务B进行了插入或者删除操作呢?

看图继续:

事务B

事务A

从上图可知,事务B的插入和删除,对事务A依然是不可见的,即不影响事务A的多次读的结果,也就是说仍然是可重复读即数据一致。

然而,一旦事务A有修改操作,就会在事务B更新的结果上进行修改,再次读,就会读出更新后的结果。

这么看,多次读的结果是否是一致的,非很多场景,依赖于其它事务干了什么,依赖于本事务干了什么,不可笼统的讲。

这个场景,如果拿出来面试,血流成河。

Mysql事务的不可重复读

事务的ACID属性中的I是Isolation,言外之意就是多个事务之间的数据隔离问题,所以在谈论事务时一定是在多个事务即一般意义上是多个数据库连接同时操作的数据库的情况下。单个事务内是没有isolation概念的,即单个事务内的数据无隔离性,全可视。

四种隔离级别中的

第一种:Read Uncommitted,几乎无实际用处,请忽略。

第二种:Read Committed也叫做Non Repeatable Read,即不可重复读。

这个级别是多数数据库的默认的隔离级别,但是MYSQL不是。

不可重复读?指的是什么?

首先要搞清楚,是谁第一次读、第二次读?是指在一个事务内的两次select,也就是在一个数据库链接中操作。

为何叫不可?是因为这个级别的事务A开启后,第一次select后,另一个事务B有update这条记录的操作,并且commit了,再之后这个事务A再次select,得到的结果和第一次select的结果不同,这就是不可重复读。

下面我们看下实验(mysql版本5.6.17):

表结构

表数据

设置隔离级别

事务A先select(红框上面),然后事务B(另一个数据库连接)update了记录为999(红框表示有事务B执行).

事务A:

事务B:

然后事务A再次执行select(红框下面),读出的结果与第一次不同(bill第一次有1000,第二次有999,因为两次读中间,事务B修改了bill的钱)。

这就是不可重复读,但是只是update情况,那么insert和delete情况如何?继续看下。

事务B中进行insert操作,然后事务A读一下,然后事务B再次delete,然后事务A再读。

事务B

事务A

可见,这个级别是彻底的不可重复读。

如果事务A中,先读,事务B更新,事物A再更新同一条记录的同一个字段,然后事务A再读该字段,会出现什么情况?这个字段的值该如何变化?

这个情形,不可重复读和可重复读是一致的,见下一篇《Mysql事务的可重复读》。

什么是微服务架构

微服务架构定义:

微服务架构是在单体应用高复杂度、业务单元无法拆解的背景下,为了提升交付效率和加大系统弹性,采用可将多个可独立开发、管理、迭代的单一功能的模块组合出复杂的大型应用系统、各模块使用编程语言无关的API集合相互通讯的方式的一种新的关于系统整体结构的抽象描述,用于指导大型系统的各个方面的设计。

色诺芬

既然自制能够保证在最为平庸的事物中找到“难以忘怀的”乐趣,而试图寻找快感的大多数做法因缺乏自我主宰结果一无所获,那么自制则能比它物获得更多快感或找到最佳快感。《色诺芬与苏格拉底》,p39。

苏格拉底还是个节食主义者!

理学vs心学

王守仁说看见小孩掉进井里,则必有恻隐之心;小孩看见鸟兽哀鸣,则必有不忍之心,所以其仁必与孺子鸟兽为一体。

可这正说明心与仁的分离,仁乃心外之物。何以证明心即理呢,反而恰好证明性即理。

王守仁糊涂。