2021超全大数据面试宝典,吐血总结十万字,大数据面试收藏这一篇就够了 (五)

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
简介: 2021超全大数据面试宝典
  1. MySql中表的分类


实体表,维度表,事务型事实表,周期性事实表

其实最终可以把事务型事实表,周期性事实表统称实体表,实体表,维度表统称维度表

 

订单表(order_info)(周期型事实表)

订单详情表(order_detail)(事务型事实表)

商品表(实体表)

用户表(实体表)

商品一级分类表(维度表)

商品二级分类表(维度表)

商品三级分类表(维度表)

支付流水表(事务型实体表)


  1. 同步策略

 

实体表,维度表统称维度表,每日全量或者每月(更长时间)全量

事务型事实表:每日增量

周期性事实表:拉链表


  1. 关系型数据库范式理论


1NF:属性不可再分割(例如不能存在5台电脑的属性,坏处:表都没法用)


2NF:不能存在部分函数依赖(例如主键(学号+课名)-->成绩,姓名,但学号--》姓名,所以姓名部分依赖于主键(学号+课名),所以要去除,坏处:数据冗余)


3NF:不能存在传递函数依赖(学号--》宿舍种类--》价钱,坏处:数据冗余和增删异常)


Mysql关系模型:关系模型主要应用与OLTP系统中,为了保证数据的一致性以及避免冗余,所以大部分业务系统的表都是遵循第三范式的。


Hive 维度模型:维度模型主要应用于OLAP系统中,因为关系模型虽然冗余少,但是在大规模数据,跨表分析统计查询过程中,会造成多表关联,这会大大降低执行效率。所以HIVE把相关各种表整理成两种:事实表和维度表两种。所有维度表围绕着事实表进行解释。


  1. 数据模型


雪花模型、星型模型和星座模型


(在维度建模的基础上又分为三种模型:星型模型、雪花模型、星座模型。)

星型模型(一级维度表),雪花(多级维度),星座模型(星型模型+多个事实表)


  1. 业务数据数仓搭建


sqoop


导数据的原理是mapreduce,


import  把数据从关系型数据库 导到 数据仓库,自定义InputFormat,


export  把数据从数据仓库 导到 关系型数据库,自定义OutputFormat,


用sqoop从mysql中将八张表的数据导入数仓的ods原始数据层


全量无条件,增量按照创建时间,增量+变化按照创建时间或操作时间。

 

origin_data


sku_info商品表(每日导全量)

user_info用户表(每日导全量)

base_category1商品一级分类表(每日导全量)

base_category2商品二级分类表(每日导全量)

base_category3商品三级分类表(每日导全量)

order_detail订单详情表(每日导增量)

payment_info支付流水表(每日导增量)

order_info订单表(每日导增量+变化)


  1. ods

(八张表,表名,字段跟mysql完全相同)

从origin_data把数据导入到ods层,表名在原表名前加ods_


  1. dwd

对ODS层数据进行判空过滤。对商品分类表进行维度退化(降维)。其他数据跟ods层一模一样


订单表 dwd_order_info

订单详情表 dwd_order_detail

用户表 dwd_user_info

支付流水表 dwd_payment_info

商品表 dwd_sku_info


其他表字段不变,唯独商品表,通过关联3张分类表,增加了


   category2_id` string COMMENT '2id',

   `category1_id` string COMMENT '3id',

   `category3_name` string COMMENT '3',

   `category2_name` string COMMENT '2',

   `category1_name` string COMMENT '1',


小结:


  1. 维度退化要付出什么代价?或者说会造成什么样的需求处理不了?

如果被退化的维度,还有其他业务表使用,退化后处理起来就麻烦些。

还有如果要删除数据,对应的维度可能也会被永久删除。


  1. 想想在实际业务中还有那些维度表可以退化

城市的三级分类(省、市、县)等


  1. dws

从订单表 dwd_order_info 中获取 下单次数 和 下单总金额

从支付流水表 dwd_payment_info 中获取 支付次数 和 支付总金额

从事件日志评论表 dwd_comment_log 中获取评论次数

最终按照user_id聚合,获得明细,跟之前的mid_id聚合不同


  1. 需求一:GMV成交总额

从用户行为宽表中dws_user_action,根据统计日期分组,聚合,直接sum就可以了。


  1. 需求二:转化率
  1. 新增用户占日活跃用户比率表

 

从日活跃数表 ads_uv_count 和 日新增设备数表 ads_new_mid_count 中取即可。


  1. 用户行为转化率表

 

从用户行为宽表dws_user_action中取,下单人数(只要下单次数>0),支付人数(只要支付次数>0)


从日活跃数表 ads_uv_count 中取活跃人数,然后对应的相除就可以了。


  1. 需求三:品牌复购率

需求:以月为单位统计,购买2次以上商品的用户


  1. 用户购买商品明细表(宽表)

 

  1. 品牌复购率表

 

从用户购买商品明细宽表dws_sale_detail_daycount中,根据品牌id--sku_tm_id聚合,计算每个品牌购买的总次数,购买人数a=购买次数>=1,两次及以上购买人数b=购买次数>=2,三次及以上购买人数c=购买次数>=3,


单次复购率=b/a,多次复购率=c/a


  1. 项目中有多少张宽表

宽表要3-5张,用户行为宽表,用户购买商品明细行为宽表,商品宽表,购物车宽表,物流宽表、登录注册、售后等。


  1. 为什么要建宽表

需求目标,把每个用户单日的行为聚合起来组成一张多列宽表,以便之后关联用户维度信息后进行,不同角度的统计分析。


  1. 拉链表

 

订单表拉链表 dwd_order_info_his

   `id` string COMMENT '订单编号',

   `total_amount` decimal(10,2) COMMENT '订单金额',

   `order_status` string COMMENT '订单状态',

   `user_id` string COMMENT '用户id' ,

   `payment_way` string COMMENT '支付方式',

   `out_trade_no` string COMMENT '支付流水号',

   `create_time` string COMMENT '创建时间',

   `operate_time` string COMMENT '操作时间' ,

   `start_date`  string COMMENT '有效开始日期',

   `end_date`  string COMMENT '有效结束日期'


1)创建订单表拉链表,字段跟拉链表一样,只增加了有效开始日期和有效结束日期

初始日期,从订单变化表ods_order_info导入数据,且让有效开始时间=当前日期,有效结束日期=9999-99-99


(从mysql导入数仓的时候就只导了新增的和变化的数据ods_order_info,dwd_order_info跟ods_order_info基本一样,只多了一个id的判空处理)


2)建一张拉链临时表dwd_order_info_his_tmp,字段跟拉链表完全一致


3)新的拉链表中应该有这几部分数据,


(1)增加订单变化表dwd_order_info的全部数据


(2)更新旧的拉链表左关联订单变化表dwd_order_info,关联字段:订单id, where 过滤出end_date只等于9999-99-99的数据,如果旧的拉链表中的end_date不等于9999-99-99,说明已经是终态了,不需要再更新


如果dwd_order_info.id is null , 没关联上,说明数据状态没变,让end_date还等于旧的end_date


如果dwd_order_info.id is not null , 关联上了,说明数据状态变了,让end_date等于当前日期-1


把查询结果插入到拉链临时表中


4)把拉链临时表覆盖到旧的拉链表中


  1. 项目中遇到过哪些问题


  1. Hadoop宕机
  1. 如果MR造成系统宕机。此时要控制Yarn同时运行的任务数,和每个任务申请的最大内存。调整参数:yarn.scheduler.maximum-allocation-mb(单个任务可申请的最多物理内存量,默认是8192MB)
  2. 如果写入文件过量造成NameNode宕机。那么调高Kafka的存储大小,控制从Kafka到HDFS的写入速度。高峰期的时候用Kafka进行缓存,高峰期过去数据同步会自动跟上。


  1. Ganglia监控

Ganglia监控Flume发现尝试提交的次数大于最终成功的次数

  1. 增加Flume内存
  2. 增加Flume台数


  1. Flume小文件

Flume上传文件到HDFS时参数大量小文件?

调整hdfs.rollInterval、hdfs.rollSize、hdfs.rollCount这三个参数的值。


  1. Kafka挂掉
  1. Flume记录
  2. 日志有记录
  3. 短期没事


  1. Kafka消息数据积压,Kafka消费能力不足怎么处理?
  1. 如果是Kafka消费能力不足,则可以考虑增加Topic的分区数,并且同时提升消费组的消费者数量,消费者数=分区数。(两者缺一不可)
  2. 如果是下游的数据处理不及时:提高每批次拉取的数量。批次拉取数据过少(拉取数据/处理时间<生产速度),使处理的数据小于生产的数据,也会造成数据积压。


  1. Kafka数据重复

在下一级消费者中去重。(redis、SparkStreaming)


  1. Mysql高可用

Hive的metadata存储在MySql中(配置MySql的高可用(主从复制和读写分离和故障转移))


  1. 自定义UDF和UDTF解析和调试复杂字段

自定义UDF(extends UDF 实现evaluate方法) 解析公共字段

自定义UDTF(extends Genertic UDTF->实现三个方法init(指定返回值的名称和类型)、process(处理字段一进多出)、close方法) -> 更加灵活以及方便定义bug


  1. Sqoop数据导出Parquet

Ads层数据用Sqoop往MySql中导入数据的时候,如果用了orc(Parquet)不能导入,需转化成text格式


  1. Sqoop数据导出控制

Sqoop中导入导出Null存储一致性问题:  

Hive中的Null在底层是以“\N”来存储,而MySQL中的Null在底层就是Null,为了保证数据两端的一致性。在导出数据时采用--input-null-string和--input-null-non-string两个参数。导入数据时采用--null-string和--null-non-string。


  1. Sqoop数据导出一致性问题

当Sqoop导出数据到MySql时,使用4个map怎么保证数据的一致性


因为在导出数据的过程中map任务可能会失败,可以使用—staging-table  –clear-staging

sqoop export --connect jdbc:mysql://192.168.137.10:3306/user_behavior --username root --password 123456 --table app_cource_study_report --columns watch_video_cnt,complete_video_cnt,dt --fields-terminated-by "\t" --export-dir "/user/hive/warehouse/tmp.db/app_cource_study_analysis_${day}" --staging-table app_cource_study_report_tmp --clear-staging-table --input-null-string '\N'


任务执行成功首先在tmp临时表中,然后将tmp表中的数据复制到目标表中(这个时候可以使用事务,保证事务的一致性)


  1. SparkStreaming优雅关闭

如何优雅的关闭SparkStreaming任务(将写好的代码打包,Spark-Submit)

Kill -9 xxx ?

开启另外一个线程每5秒监听HDFS上一个文件是否存在。如果检测到存在,调用ssc.stop()方法关闭SparkStreaming任务(当你要关闭任务时,可以创建你自定义监控的文件目录)


  1. Spark OOM、数据倾斜解决
  1. 项目经验
  2. 框架经验


  1. Hadoop
  1. Hadoop集群基准测试(HDFS的读写性能、MapReduce的计算能力测试)
  2. 一台服务器一般都有很多个硬盘插槽(插了几个插槽)


如果不配置datanode.data.dir多目录,每次插入一块新的硬盘都需要重启服务器

配置了即插即用


  1. Hdfs参数调优

Namenode有一个工作线程池,用来处理与datanode的心跳(报告自身的健康状况和文件恢复请求)和元数据请求    dfs.namenode.handler.count=20 * log2(Cluster Size)


4)编辑日志存储路径dfs.namenode.edits.dir设置与镜像文件存储路径    dfs.namenode.name.dir尽量分开,达到最低写入延迟(提高写入的吞吐量)


5)YARN参数调优yarn-site.xml

(1)服务器节点上YARN可使用的物理内存总量,默认是8192(MB)

(2)单个任务可申请的最多物理内存量,默认是8192(MB)。


6)HDFS和硬盘空闲控制在70%以下。


  1. Flume
  1. Flume内存配置为4G(flume-env.sh修改)
  2. FileChannel优化


通过配置dataDirs指向多个路径,每个路径对应不同的硬盘,增大Flume吞吐量。

checkpointDir和backupCheckpointDir也尽量配置在不同硬盘对应的目录中,保证checkpoint坏掉后,可以快速使用backupCheckpointDir恢复数据


  1. Sink:HDFS Sink小文件处理

这三个参数配置写入HDFS后会产生小文件,hdfs.rollInterval、hdfs.rollSize、hdfs.rollCount


  1. Kafka
  1. Kafka的吞吐量测试(测试生产速度和消费速度)
  2. Kafka内存为6G(不能超过6G)
  3. Kafka数量确定:2 * 峰值生产速度(m/s)* 副本数 / 100  + 1 = ?
  4. Kafka中的数据量计算


每天数据总量100g(1亿条)   10000万/24/60/60 = 1150条/s

平均每秒钟:1150条

低谷每秒:400条

高峰每秒钟:1150 * 10 = 11000 条

每条日志大小: 1K左右

每秒多少数据量:20MB


  1. Kafka消息数据积压,Kafka消费能力不足怎么处理?
  1. 如果是Kafka消费能力不足,则可以考虑增加Topic的分区数,并且同时提升消费组的消费者数量,消费者数=分区数。(两者缺一不可)
  2. 如果是下游的数据处理不及时:提高每批次拉取的数量。批次拉取数据过少(拉取数据/处理时间<生产速度),使处理的数据小于生产的数据,也会造成数据积压。


  1. Tez引擎优点(略过)?

Tez可以将多个有依赖的作业转换为一个作业,这样只需写一次HDFS,且中间节点较少,从而大大提升作业的计算性能。


  1. Sqoop参数
  1. Sqoop导入导出Null存储一致性问题
  2. Sqoop数据导出一致性问题

–staging-table方式 --clear-staging

  1. Sqoop数据导出的时候一次执行多长时间

Sqoop任务5分钟-2个小时的都有。取决于数据量。


  1. Azkaban每天执行多少个任务
  1. 每天集群运行多少job?
  2. 每个任务的资源是如何分配的?
  3. 多个指标(200)*6=1200(1000-2000个job)
  4. 每天集群运行多少个task? 1000*(5-8)=5000多个
  5. 任务挂了怎么办?运行成功或者失败都会发邮件

Zip a.job b.job c.job   job.zip  把压缩的zip包放到azkaban的web界面上提交(指定sechduler)


  1. 业务经验


  1. ODS层采用什么压缩方式和存储格式?

压缩采用Snappy,存储采用orc,压缩比是100g数据压缩完10g左右。


  1. DWD层做了哪些事?
  1. 数据清洗
  1. 空值去除
  2. 过滤核心字段无意义的数据,比如订单表中订单id为null,支付表中支付id为空
  3. 对手机号、身份证号等敏感数据脱敏
  4. 对业务数据传过来的表进行维度退化和降维。
  5. 将用户行为宽表和业务表进行数据一致性处理

select case when a is null then b else a end as JZR,

   ...

from A

  1. 清洗的手段

Sql、mr、rdd、kettle、Python(项目中采用sql进行清除)

  1. 清洗掉多少数据算合理

1万条数据清洗掉1条。


  1. DWS层做了哪些事?
  1. DWS层有3-5张宽表(处理100-200个指标   70%以上的需求)

具体宽表名称:用户行为宽表,用户购买商品明细行为宽表,商品宽表,购物车宽表,物流宽表、登录注册、售后等。


  1. 哪个宽表最宽?大概有多少个字段?

最宽的是用户行为宽表。大概有60-100个字段


  1. 具体用户行为宽表字段名称

评论、打赏、收藏、关注--商品、关注--人、点赞、分享、好价爆料、文章发布、活跃、签到、补签卡、幸运屋、礼品、金币、电商点击、gmv


CREATE TABLE `app_usr_interact`(

 `stat_dt` date COMMENT '互动日期',

 `user_id` string COMMENT '用户id',

 `nickname` string COMMENT '用户昵称',

 `register_date` string COMMENT '注册日期',

 `register_from` string COMMENT '注册来源',

 `remark` string COMMENT '细分渠道',

 `province` string COMMENT '注册省份',

 `pl_cnt` bigint COMMENT '评论次数',

 `ds_cnt` bigint COMMENT '打赏次数',

 `sc_add` bigint COMMENT '添加收藏',

 `sc_cancel` bigint COMMENT '取消收藏',

 `gzg_add` bigint COMMENT '关注商品',

 `gzg_cancel` bigint COMMENT '取消关注商品',

 `gzp_add` bigint COMMENT '关注人',

 `gzp_cancel` bigint COMMENT '取消关注人',

 `buzhi_cnt` bigint COMMENT '点不值次数',

 `zhi_cnt` bigint COMMENT '点值次数',

 `zan_cnt` bigint COMMENT '点赞次数',

 `share_cnts` bigint COMMENT '分享次数',

 `bl_cnt` bigint COMMENT '爆料数',

 `fb_cnt` bigint COMMENT '好价发布数',

 `online_cnt` bigint COMMENT '活跃次数',

 `checkin_cnt` bigint COMMENT '签到次数',

 `fix_checkin` bigint COMMENT '补签次数',

 `house_point` bigint COMMENT '幸运屋金币抽奖次数',

 `house_gold` bigint COMMENT '幸运屋积分抽奖次数',

 `pack_cnt` bigint COMMENT '礼品兑换次数',

 `gold_add` bigint COMMENT '获取金币',

 `gold_cancel` bigint COMMENT '支出金币',

 `surplus_gold` bigint COMMENT '剩余金币',

 `event` bigint COMMENT '电商点击次数',

 `gmv_amount` bigint COMMENT 'gmv',

 `gmv_sales` bigint COMMENT '订单数')

PARTITIONED BY (  `dt` string)

  1. 商品详情  -----  购物车  ----- 订单  ------ 付款的转换比率

      5%          30%        70%

  1. 每天的GMV是多少,哪个商品卖的最好?每天下单量多少?
  1. 100万的日活每天大概有10万人购买,平均每人消费100元,一天的GMV在1000万
  2. 面膜,每天销售5000个
  3. 每天下单量在10万左右


  1. 分析过哪些指标(一分钟至少说出30个指标)


  1. 离线指标

网站流量指标  独立访问数UV  页面访客数PV

流量质量指标类  跳出率  平均页面访问时长 人均页面访问数

  1. 购物车类指标

加入购物车次数  加入购物车买家次数  加入购物车商品数  购物车支付转化率

  1. 下单类指标

下单笔数  下单金额  下单买家数  浏览下单转化率

  1. 支付类指标

支付金额  支付买家数 支付商品数  浏览-支付买家转化率

下单-支付金额转化率  下单-支付买家数转换率

  1. 交易类指标

交易成功订单数  交易成功金额  交易成功买家数  交易成功商品数

交易失败订单数  交易失败订单金额  交易失败买家数

交易失败商品数  退款总订单量  退款金额  退款率

  1. 市场营销活动指标  

新增访问人数   新增注册人数  广告投资回报率  UV订单转化率

  1. 风控类指标

买家评价数  买家上传图片数  买家评价率  买家好评率  买家差评率

物流平均配送时间

  1. 投诉类指标

发起投诉数  投诉率 撤销投诉(申诉数)

  1. 商品类指标

产品总数  SKU数  SPU数

上架商品SKU数  上架商品SPU数  上架商品数

 

日活跃用户,

月活跃用户,

各区域Top10商品统计,

季度商品品类点击率top10,

用户留存,

月APP的用户增长人数,

广告区域点击数top3,

活跃用户每天在线时长,

投诉人数占比,

沉默用户占比,

用户的新鲜度,

商品上架的sku数,

同种品类的交易额排名,

统计买家的评价率,

用户浏览时长,

统计下单的数量,

统计支付的数量,

统计退货的数量,

用户的(日活、月活、周活),

统计流失人数

 

日活,周活,月活,沉默用户占比,增长人数,活跃用户占比,在线时长统计,歌曲访问数,歌曲访问时长,各地区Top10歌曲统计 ,投诉人数占比,投诉回应时长,留存率,月留存率,转化率,GMV,复购vip率,vip人数,歌榜,挽回率,粉丝榜,打赏次数,打赏金额,发布歌曲榜单,歌曲热度榜单,歌手榜单,用户年龄组,vip年龄组占比,收藏数榜单,评论数


  1. 用户活跃数统计(日活,月活,周活)
  2. 某段时间的新增用户/活跃用户数
  3. 页面单跳转化率统计
  4. 活跃人数占比(占总用户比例)
  5. 在线时长统计(活跃用户每天在线时长)
  6. 统计本月的人均在线时长
  7. 订单产生效率(下单的次数与访问次数比)
  8. 页面访问时长(单个页面访问时长)  
  9. 统计本季度付款订单
  10. 统计某广告的区城点击数top3
  11. 统计本月用户的流失人数
  12. 统计本月流失人数占用户人数的比例
  13. 统计本月APP的用户增长人数
  14. 统计本月的沉默用户
  15. 统计某时段的登录人数
  16. 统计本日用户登录的次数平均值
  17. 统计用户在某类型商品中的浏览深度(页面转跳率)
  18. 统计用户从下单开始到交易成功的平均时长
  19. Top10热门商品的统计
  20. 统计下单的数量
  21. 统计支付的数量
  22. 统计退货的数量
  23. 统计动销率(有销量的商品/在线销售的宝贝)
  24. 统计支付转化率
  25. 统计用户的消费频率
  26. 统计商品上架的SKU数
  27. 统计同种品类的交易额排名
  28. 统计按下单退款排序的top10的商品
  29. 统计本APP的投诉人数占用户人数的比例
  30. 用户收藏商品


  1. 分析过最难的两个指标,现场手写


最近连续3周活跃用户数:

 

最近7天连续3天活跃用户数:

 

  1. 数据仓库每天跑多少张表,大概什么时候运行,运行多久?

基本一个项目建一个库,表格个数为初始的原始数据表格加上统计结果表格的总数。(一般70-100张表格)

每天0:30开始运行。

所有离线数据报表控制在8小时之内

大数据实时处理部分控制在5分钟之内。


  1. 数仓中使用的哪种文件存储格式

常用的包括:textFile,rcFile,ORC,Parquet,一般企业里使用ORC或者Parquet,因为是列式存储,且压缩比非常高,所以相比于textFile,查询速度快,占用硬盘空间少


  1. 数仓中用到过哪些Shell脚本及具体功能
  1. 集群启动停止脚本(Hadoop、Flume、Kafka、Zookeeper)
  2. Sqoop和数仓之间的导入导出脚本
  3. 数仓层级之间的数据导入脚本。


  1. 项目中用过的报表工具

Echarts、kibana、supesrset


  1. 测试相关
  1. 公司有多少台测试服务器?

测试服务器一般三台

  1. 测试数据哪来的?

一部分自己写Java程序自己造,一部分从生产环境上取一部分。

  1. 如何保证写的sql正确性

需要造一些特定的测试数据,测试。

离线数据和实时数据分析的结果比较。

  1. 测试环境什么样?

测试环境的配置是生产的一半

  1. 测试之后如何上线?

上线的时候,将脚本打包,提交git。先发邮件抄送经理和总监,运维。通过之后跟运维一起上线。


  1. 项目实际工作流程
  1. 先与产品讨论,看报表的各个数据从哪些埋点中取
  2. 将业务逻辑过程设计好,与产品确定后开始开发
  3. 开发出报表SQL脚本,并且跑几天的历史数据,观察结果
  4. 将报表放入调度任务中,第二天给产品看结果。
  5. 周期性将表结果导出或是导入后台数据库,生成可视化报表


  1. 项目中实现一个需求大概多长时间

刚入职第一个需求大概需要7天左右。

对业务熟悉后,平均一天一个需求。

影响时间的因素:开会讨论需求、表的权限申请、测试等


  1. 项目在3年内迭代次数,每一个项目具体是如何迭代的。

差不多一个月会迭代一次。就产品或我们提出优化需求,然后评估时间。每周我们都会开会做下周计划和本周总结。

有时候也会去预研一些新技术。


  1. 项目开发中每天做什么事

新需求比如埋点或是报表来了之后,需要设计做的方案,设计完成之后跟产品讨论,再开发。


数仓的任何步骤出现问题,需要查看问题,比如日活,月活下降等。

  1. JavaSE(答案精简)
  2. hashMap底层源码,数据结构

hashMap的底层结构在jdk1.7中由数组+链表实现,在jdk1.8中由数组+链表+红黑树实现,以数组+链表的结构为例。

 

JDK1.8之前Put方法:

 

JDK1.8之后Put方法:

 

  1. Java自带有哪几种线程池?


  1. newCachedThreadPool


创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。这种类型的线程池特点是:


工作线程的创建数量几乎没有限制(其实也有限制的,数目为Interger. MAX_VALUE), 这样可灵活的往线程池中添加线程。


如果长时间没有往线程池中提交任务,即如果工作线程空闲了指定的时间(默认为1分钟),则该工作线程将自动终止。终止后,如果你又提交了新的任务,则线程池重新创建一个工作线程。


在使用CachedThreadPool时,一定要注意控制任务的数量,否则,由于大量线程同时运行,很有会造成系统瘫痪。


  1. newFixedThreadPool

创建一个指定工作线程数量的线程池。每当提交一个任务就创建一个工作线程,如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中。FixedThreadPool是一个典型且优秀的线程池,它具有线程池提高程序效率和节省创建线程时所耗的开销的优点。但是,在线程池空闲时,即线程池中没有可运行任务时,它不会释放工作线程,还会占用一定的系统资源。


  1. newSingleThreadExecutor

创建一个单线程化的Executor,即只创建唯一的工作者线程来执行任务,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。如果这个线程异常结束,会有另一个取代它,保证顺序执行。单工作线程最大的特点是可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的。


  1. newScheduleThreadPool

创建一个定长的线程池,而且支持定时的以及周期性的任务执行,支持定时及周期性任务执行。延迟3秒执行。


  1. HashMap和HashTable区别


  1. 线程安全性不同

HashMap是线程不安全的,HashTable是线程安全的,其中的方法是Synchronize的,在多线程并发的情况下,可以直接使用HashTabl,但是使用HashMap时必须自己增加同步处理。


  1. 是否提供contains方法

HashMap只有containsValue和containsKey方法;HashTable有contains、containsKey和containsValue三个方法,其中contains和containsValue方法功能相同。


  1. key和value是否允许null值

Hashtable中,key和value都不允许出现null值。HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。


  1. 数组初始化和扩容机制

HashTable在不指定容量的情况下的默认容量为11,而HashMap为16,Hashtable不要求底层数组的容量一定要为2的整数次幂,而HashMap则要求一定为2的整数次幂。


Hashtable扩容时,将容量变为原来的2倍加1,而HashMap扩容时,将容量变为原来的2倍。


  1. TreeSet和HashSet区别


HashSet是采用hash表来实现的。其中的元素没有按顺序排列,add()、remove()以及contains()等方法都是复杂度为O(1)的方法。


TreeSet是采用树结构实现(红黑树算法)。元素是按顺序进行排列,但是add()、remove()以及contains()等方法都是复杂度为O(log (n))的方法。它还提供了一些方法来处理排序的set,如first(), last(), headSet(), tailSet()等等。


  1. String buffer和String build区别
  2. StringBuffer 与 StringBuilder 中的方法和功能完全是等价的,
  3. 只是StringBuffer 中的方法大都采用了 synchronized 关键字进行修饰,因此是线程安全的,而 StringBuilder 没有这个修饰,可以被认为是线程不安全的。
  4. 在单线程程序下,StringBuilder效率更快,因为它不需要加锁,不具备多线程安全而StringBuffer则每次都需要判断锁,效率相对更低
  5. Final、Finally、Finalize


final:修饰符(关键字)有三种用法:修饰类、变量和方法。修饰类时,意味着它不能再派生出新的子类,即不能被继承,因此它和abstract是反义词。修饰变量时,该变量使用中不被改变,必须在声明时给定初值,在引用中只能读取不可修改,即为常量。修饰方法时,也同样只能使用,不能在子类中被重写。


finally:通常放在try…catch的后面构造最终执行代码块,这就意味着程序无论正常执行还是发生异常,这里的代码只要JVM不关闭都能执行,可以将释放外部资源的代码写在finally块中。


finalize:Object类中定义的方法,Java中允许使用finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在销毁对象时调用的,通过重写finalize() 方法可以整理系统资源或者执行其他清理工作。


  1. ==和Equals区别


== : 如果比较的是基本数据类型,那么比较的是变量的值

如果比较的是引用数据类型,那么比较的是地址值(两个对象是否指向同一块内存)

equals:如果没重写equals方法比较的是两个对象的地址值。

如果重写了equals方法后我们往往比较的是对象中的属性的内容

 

equals方法是从Object类中继承的,默认的实现就是使用==

 

  1. Redis(答案精简)
  2. 缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级


缓存雪崩


缓存雪崩我们可以简单的理解为:由于原有缓存失效,新缓存未到期间(例如:我们设置缓存时采用了相同的过期时间,在同一时刻出现大面积的缓存过期),所有原本应该访问缓存的请求都去查询数据库了,而对数据库CPU和内存造成巨大压力,严重的会造成数据库宕机。从而形成一系列连锁反应,造成整个系统崩溃。


缓存正常从Redis中获取,示意图如下:

 

缓存失效瞬间示意图如下:

 

缓存失效时的雪崩效应对底层系统的冲击非常可怕!大多数系统设计者考虑用加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。还有一个简单方案就时讲缓存失效时间分散开,比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。


以下简单介绍两种实现方式的伪代码:


(1)碰到这种情况,一般并发量不是特别多的时候,使用最多的解决方案是加锁排队,伪代码如下:

 

加锁排队只是为了减轻数据库的压力,并没有提高系统吞吐量。假设在高并发下,缓存重建期间key是锁着的,这是过来1000个请求999个都在阻塞的。同样会导致用户等待超时,这是个治标不治本的方法!


注意:加锁排队的解决方式分布式环境的并发问题,有可能还要解决分布式锁的问题;线程还会被阻塞,用户体验很差!因此,在真正的高并发场景下很少使用!


(2)还有一个解决办法解决方案是:给每一个缓存数据增加相应的缓存标记,记录缓存的是否失效,如果缓存标记失效,则更新数据缓存,实例伪代码如下:

 

解释说明:


1、缓存标记:记录缓存数据是否过期,如果过期会触发通知另外的线程在后台去更新实际key的缓存;


2、缓存数据:它的过期时间比缓存标记的时间延长1倍,例:标记缓存时间30分钟,数据缓存设置为60分钟。 这样,当缓存标记key过期后,实际缓存还能把旧数据返回给调用端,直到另外的线程在后台更新完成后,才会返回新缓存。


关于缓存崩溃的解决方法,这里提出了三种方案:使用锁或队列、设置过期标志更新缓存、为key设置不同的缓存失效时间,还有一各被称为“二级缓存”的解决方法,有兴趣的读者可以自行研究。

 

缓存穿透


缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询的时候,在缓存中找不到,每次都要去数据库再查询一遍,然后返回空(相当于进行了两次无用的查询)。这样请求就绕过缓存直接查数据库,这也是经常提的缓存命中率问题。


有很多种方法可以有效地解决缓存穿透问题,最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。


另外也有一个更为简单粗暴的方法,如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。通过这个直接设置的默认值存放到缓存,这样第二次到缓冲中获取就有值了,而不会继续访问数据库,这种办法最简单粗暴!

 

把空结果,也给缓存起来,这样下次同样的请求就可以直接返回空了,即可以避免当查询的值为空时引起的缓存穿透。同时也可以单独设置个缓存区域存储空值,对要查询的key进行预先校验,然后再放行给后面的正常缓存处理逻辑。

 

缓存预热


缓存预热这个应该是一个比较常见的概念,相信很多小伙伴都应该可以很容易的理解,缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!


解决思路:

  1. 直接写个缓存刷新页面,上线时手工操作下;
  2. 数据量不大,可以在项目启动的时候自动进行加载;
  3. 定时刷新缓存;

 

缓存更新


除了缓存服务器自带的缓存失效策略之外(Redis默认的有6种策略可供选择),我们还可以根据具体的业务需求进行自定义的缓存淘汰,常见的策略有两种:


  1. 定时去清理过期的缓存;
  2. 当有用户请求过来时,再判断这个请求所用到的缓存是否过期,过期的话就去底层系统得到新数据并更新缓存。


两者各有优劣,第一种的缺点是维护大量缓存的key是比较麻烦的,第二种的缺点就是每次用户请求过来都要判断缓存失效,逻辑相对比较复杂!具体用哪种方案,大家可以根据自己的应用场景来权衡。

 

缓存降级


当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时,仍然需要保证服务还是可用的,即使是有损服务。系统可以根据一些关键数据进行自动降级,也可以配置开关实现人工降级。


降级的最终目的是保证核心服务可用,即使是有损的。而且有些服务是无法降级的(如加入购物车、结算)。


在进行降级之前要对系统进行梳理,看看系统是不是可以丢卒保帅;从而梳理出哪些必须誓死保护,哪些可降级;比如可以参考日志级别设置预案:


  1. 一般:比如有些服务偶尔因为网络抖动或者服务正在上线而超时,可以自动降级;
  2. 警告:有些服务在一段时间内成功率有波动(如在95~100%之间),可以自动降级或人工降级,并发送告警;
  3. 错误:比如可用率低于90%,或者数据库连接池被打爆了,或者访问量突然猛增到系统能承受的最大阀值,此时可以根据情况自动降级或者人工降级;
  4. 严重错误:比如因为特殊原因数据错误了,此时需要紧急人工降级。

 

  1. 哨兵模式


主从切换技术的方法是:当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费事费力,还会造成一段时间内服务不可用。这不是一种推荐的方式,更多时候,我们优先考虑哨兵模式。


哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。

 

这里的哨兵有两个作用


  1. 通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器。


  1. 当哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机。


然而一个哨兵进程对Redis服务器进行监控,可能会出现问题,为此,我们可以使用多个哨兵进行监控。各个哨兵之间还会进行监控,这样就形成了多哨兵模式。


用文字描述一下故障切换(failover)的过程。假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行failover过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象成为主观下线。当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover操作。

切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线。这样对于客户端而言,一切都是透明的。


  1. 数据类型

string

字符串

list

可以重复的集合

set

不可以重复的集合

hash

类似于Map<String,String>

zset(sorted set)

带分数的set


  1. 持久化
  2. RDB持久化:
  1. 在指定的时间间隔内持久化
  2. 服务shutdown会自动持久化
  3. 输入bgsave也会持久化
  1. AOF :  以日志形式记录每个更新操作


Redis重新启动时读取这个文件,重新执行新建、修改数据的命令恢复数据。


保存策略:


推荐(并且也是默认)的措施为每秒持久化一次,这种策略可以兼顾速度和安全性。


缺点:

  1. 比起RDB占用更多的磁盘空间
  2. 恢复备份速度要慢
  3. 每次读写都同步的话,有一定的性能压力
  4. 存在个别Bug,造成恢复不能


选择策略:


官方推荐:


如果对数据不敏感,可以选单独用RDB;不建议单独用AOF,因为可能出现Bug;如果只是做纯内存缓存,可以都不用


  1. 悲观锁


所谓悲观锁:具有强烈的独占和排他特性。它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。


简单来说:执行操作前假设当前的操作肯定(或有很大几率)会被打断(悲观)。基于这个假设,我们在做操作前就会把相关资源锁定,不允许自己执行期间有其他操作干扰。


悲观锁的并发性能差,但是能保证不会发生脏数据的可能性小一点。


  1. 乐观锁


执行操作前假设当前操作不会被打断(乐观)。基于这个假设,我们在做操作前不会锁定资源,万一发生了其他操作的干扰,那么本次操作将被放弃。Redis使用的就是乐观锁。


  1. redis是单线程的,为什么那么快
  2. 完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。
  3. 数据结构简单,对数据操作也简单,Redis中的数据结构是专门进行设计的
  4. 采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗
  5. 使用多路I/O复用模型,非阻塞IO
  6. 使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求
  7. MySql
  8. MyISAM与InnoDB的区别


对比项

MyISAM

InnoDB

外键

不支持

支持

事务

不支持

支持

行表锁

表锁,即使操作一条记录也会锁住整个表,不适合高并发的操作

行锁,操作时只锁某一行,不对其它行有影响,

适合高并发的操作

缓存

只缓存索引,不缓存真实数据

不仅缓存索引还要缓存真实数据,对内存要求较高,而且内存大小对性能有决定性的影响

 

  1. 索引


数据结构:B+Tree


一般来说能够达到range就可以算是优化了


口诀(两个法则加6种索引失效的情况)


全值匹配我最爱,最左前缀要遵守;

带头大哥不能死,中间兄弟不能断;

索引列上少计算,范围之后全失效;

LIKE百分写最右,覆盖索引不写*;

不等空值还有OR,索引影响要注意;

VAR引号不可丢,SQL优化有诀窍。


  1. b-tree和b+tree的区别
  2. B-树的关键字和记录是放在一起的,叶子节点可以看作外部节点,不包含任何信息;B+树的非叶子节点中只有关键字和指向下一个节点的索引,记录只放在叶子节点中。
  3. 在B-树中,越靠近根节点的记录查找时间越快,只要找到关键字即可确定记录的存在;而B+树中每个记录的查找时间基本是一样的,都需要从根节点走到叶子节点,而且在叶子节点中还要再比较关键字。
  4. MySQL的事务


一、事务的基本要素(ACID)


  1. 原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位
  2. 一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏 。比如A向B转账,不可能A扣了钱,B却没收到。
  3. 隔离性(Isolation):同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
  4. 持久性(Durability):事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。

 

二、事务的并发问题


  1. 脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
  2. 不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致
  3. 幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表

 

三、MySQL事务隔离级别


事务隔离级别                       脏读        不可重复读      幻读

读未提交(read-uncommitted)       是          是              是

不可重复读(read-committed)       否          是              是

可重复读(repeatable-read)        否          否              是

串行化(serializable)             否          否              否


  1. 常见面试sql
  2. 用一条SQL语句查询出每门课都大于80分的学生姓名

name   kecheng   fenshu

   张三    语文    81

   张三    数学    75

   李四    语文    76

   李四    数学     90

   王五    语文    81

   王五    数学    100

   王五    英语    90

   A: select distinct name from table where name not in (select distinct name from table where fenshu<=80)

   B:select name from table group by name having min(fenshu)>80

 

  1. 学生表

自动编号   学号  姓名 课程编号 课程名称 分数

   1     2005001 张三   0001   数学   69

   2     2005002 李四   0001   数学   89

   3     2005001 张三   0001   数学   69

   删除除了自动编号不同, 其他都相同的学生冗余信息


   A: delete tablename where 自动编号 not in(select min(自动编号) from tablename group by学号, 姓名, 课程编号, 课程名称, 分数)

 

  1. 一个叫team的表,里面只有一个字段name,一共有4条纪录,分别是a,b,c,d,对应四个球队,现在四个球队进行比赛,用一条sql语句显示所有可能的比赛组合

select a.name, b.name

   from team a, team b

   where a.name < b.name

  1. 面试题:怎么把这样一个

year   month amount

   1991   1     1.1

   1991   2     1.2

   1991   3     1.3

   1991   4     1.4

   1992   1     2.1

   1992   2     2.2

   1992   3     2.3

   1992   4     2.4

   查成这样一个结果

   year m1  m2  m3   m4

   1991 1.1 1.2 1.3 1.4

   1992 2.1 2.2 2.3 2.4


   答案

   select year,

   (select amount from aaa m where month=1 and m.year=aaa.year) as m1,

   (select amount from aaa m where month=2 and m.year=aaa.year) as m2,

   (select amount from aaa m where month=3 and m.year=aaa.year) as m3,

   (select amount from  aaa m where month=4 and m.year=aaa.year) as m4

   from aaa group by year

  1. 说明:复制表(只复制结构,源表名:a新表名:b)

SQL: select * into b from a where 1<>1 (where1=1,拷贝表结构和数据内容)

   ORACLE:create table b

As

Select * from a where 1=2

 

[<>(不等于)(SQL Server Compact)

比较两个表达式。 当使用此运算符比较非空表达式时,如果左操作数不等于右操作数,则结果为 TRUE。 否则,结果为 FALSE。]

  1. 原表:
    courseid coursename score
    -------------------------------------
    1 java 70
    2 oracle 90
    3 xml 40
    4 jsp 30
    5 servlet 80
    -------------------------------------
    为了便于阅读,查询此表后的结果显式如下(及格分数为60):
    courseid coursename score mark
    ---------------------------------------------------
    1 java 70 pass
    2 oracle 90 pass
    3 xml 40 fail
    4 jsp 30 fail
    5 servlet 80 pass
    ---------------------------------------------------
    写出此查询语句
    select courseid, coursename ,score ,if(score>=60, "pass","fail")  as mark from course
  2. 表名:购物信息

购物人      商品名称     数量

A            甲          2

B            乙          4

C            丙          1

A            丁          2

B            丙          5

……

 

给出所有购入商品为两种或两种以上的购物人记录

 

答:select * from 购物信息 where 购物人 in (select 购物人 from 购物信息 group by 购物人 having count(*) >= 2);

  1. info 表

date          result

2005-05-09    win

2005-05-09    lose

2005-05-09    lose

2005-05-09    lose

2005-05-10    win

2005-05-10    lose

2005-05-10    lose

如果要生成下列结果, 该如何写sql语句?

win           lose

2005-05-09  2   2

2005-05-10  1   2

答案:

(1) select date, sum(case when result = "win" then 1 else 0 end) as "win", sum(case when result = "lose" then 1 else 0 end) as "lose" from info group by date;

(2) select a.date, a.result as win, b.result as lose

  from

  (select date, count(result) as result from info where result = "win" group by date) as a

  join

  (select date, count(result) as result from info where result = "lose" group by date) as b

  on a.date = b.date;

 

  1. JVM
  2. JVM内存分哪几个区,每个区的作用是什么?

 

java虚拟机主要分为以下几个区:


  1. 方法区:
  1. 有时候也成为永久代,在该区内很少发生垃圾回收,但是并不代表不发生GC,在这里进行的GC主要是对方法区里的常量池和对类型的卸载
  2. 方法区主要用来存储已被虚拟机加载的类的信息、常量、静态变量和即时编译器编译后的代码等数据。
  3. 该区域是被线程共享的。
  4. 方法区里有一个运行时常量池,用于存放静态编译产生的字面量和符号引用。该常量池具有动态性,也就是说常量并不一定是编译时确定,运行时生成的常量也会存在这个常量池中。


  1. 虚拟机栈:
  1. 虚拟机栈也就是我们平常所称的栈内存,它为java方法服务,每个方法在执行的时候都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接和方法出口等信息。
  2. 虚拟机栈是线程私有的,它的生命周期与线程相同。
  3. 局部变量表里存储的是基本数据类型、returnAddress类型(指向一条字节码指令的地址)和对象引用,这个对象引用有可能是指向对象起始地址的一个指针,也有可能是代表对象的句柄或者与对象相关联的位置。局部变量所需的内存空间在编译器间确定
  4. 操作数栈的作用主要用来存储运算结果以及运算的操作数,它不同于局部变量表通过索引来访问,而是压栈和出栈的方式
  5. 每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接.动态链接就是将常量池中的符号引用在运行期转化为直接引用。


  1. 本地方法栈:

本地方法栈和虚拟机栈类似,只不过本地方法栈为Native方法服务。

  1. 堆:

java堆是所有线程所共享的一块内存,在虚拟机启动时创建,几乎所有的对象实例都在这里创建,因此该区域经常发生垃圾回收操作。

  1. 程序计数器:

内存空间小,字节码解释器工作时通过改变这个计数值可以选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理和线程恢复等功能都需要依赖这个计数器完成。该内存区域是唯一一个java虚拟机规范没有规定任何OOM情况的区域。

 

  1. Java类加载过程?


Java类加载需要经历一下几个过程:


  1. 加载

加载时类加载的第一个过程,在这个阶段,将完成一下三件事情:

  1. 通过一个类的全限定名获取该类的二进制流。
  2. 将该二进制流中的静态存储结构转化为方法去运行时数据结构。
  3. 在内存中生成该类的Class对象,作为该类的数据访问入口。


  1. 验证

验证的目的是为了确保Class文件的字节流中的信息不回危害到虚拟机.在该阶段主要完成以下四钟验证:

  1. 文件格式验证:验证字节流是否符合Class文件的规范,如主次版本号是否在当前虚拟机范围内,常量池中的常量是否有不被支持的类型.
  2. 元数据验证:对字节码描述的信息进行语义分析,如这个类是否有父类,是否集成了不被继承的类等。
  3. 字节码验证:是整个验证过程中最复杂的一个阶段,通过验证数据流和控制流的分析,确定程序语义是否正确,主要针对方法体的验证。如:方法中的类型转换是否正确,跳转指令是否正确等。
  4. 符号引用验证:这个动作在后面的解析过程中发生,主要是为了确保解析动作能正确执行。
  5. 准备


准备阶段是为类的静态变量分配内存并将其初始化为默认值,这些内存都将在方法区中进行分配。准备阶段不分配类中的实例变量的内存,实例变量将会在对象实例化时随着对象一起分配在Java堆中。


  1. 解析

该阶段主要完成符号引用到直接引用的转换动作。解析动作并不一定在初始化动作完成之前,也有可能在初始化之后。


  1. 初始化

初始化时类加载的最后一步,前面的类加载过程,除了在加载阶段用户应用程序可以通过自定义类加载器参与之外,其余动作完全由虚拟机主导和控制。到了初始化阶段,才真正开始执行类中定义的Java程序代码。

 

  1. java中垃圾收集的方法有哪些?


  1. 引用计数法  应用于:微软的COM/ActionScrip3/Python等
  1. 如果对象没有被引用,就会被回收,缺点:需要维护一个引用计算器
  1. 复制算法  年轻代中使用的是Minor GC,这种GC算法采用的是复制算法(Copying)
  1. 效率高,缺点:需要内存容量大,比较耗内存
  2. 使用在占空间比较小、刷新次数多的新生区
  1. 标记清除  老年代一般是由标记清除或者是标记清除与标记整理的混合实现
  1. 效率比较低,会差生碎片。
  1. 标记压缩  老年代一般是由标记清除或者是标记清除与标记整理的混合实现
  1. 效率低速度慢,需要移动对象,但不会产生碎片。
  1. 标记清除压缩 标记清除-标记压缩的集合,多次GC后才Compact
  1. 使用于占空间大刷新次数少的养老区,是3 4的集合体

 

  1. 如何判断一个对象是否存活?(或者GC对象的判定方法)

判断一个对象是否存活有两种方法:

  1. 引用计数法
  2. 可达性算法(引用链法)
  3. 什么是类加载器,类加载器有哪些?


实现通过类的权限定名获取该类的二进制字节流的代码块叫做类加载器。


主要有一下四种类加载器:

  1. 启动类加载器(Bootstrap ClassLoader)用来加载java核心类库,无法被java程序直接引用。
  2. 扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
  3. 系统类加载器(system class loader)也叫应用类加载器:它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader()来获取它。
  4. 用户自定义类加载器,通过继承 java.lang.ClassLoader类的方式实现。


  1. 简述Java内存分配与回收策略以及Minor GC和Major GC(full GC)

内存分配:

  1. 栈区:栈分为java虚拟机栈和本地方法栈
  2. 堆区:堆被所有线程共享区域,在虚拟机启动时创建,唯一目的存放对象实例。堆区是gc的主要区域,通常情况下分为两个区块年轻代和年老代。更细一点年轻代又分为Eden区,主要放新创建对象,From survivor 和 To survivor 保存gc后幸存下的对象,默认情况下各自占比 8:1:1。
  3. 方法区:被所有线程共享区域,用于存放已被虚拟机加载的类信息,常量,静态变量等数据。被Java虚拟机描述为堆的一个逻辑部分。习惯是也叫它永久代(permanment generation)
  4. 程序计数器:当前线程所执行的行号指示器。通过改变计数器的值来确定下一条指令,比如循环,分支,跳转,异常处理,线程恢复等都是依赖计数器来完成。线程私有的。

 

回收策略以及Minor GC和Major GC:


  1. 对象优先在堆的Eden区分配。
  2. 大对象直接进入老年代。
  3. 长期存活的对象将直接进入老年代。


当Eden区没有足够的空间进行分配时,虚拟机会执行一次Minor GC.Minor GC通常发生在新生代的Eden区,在这个区的对象生存期短,往往发生GC的频率较高,回收速度比较快;Full Gc/Major GC 发生在老年代,一般情况下,触发老年代GC的时候不会触发Minor GC,但是通过配置,可以在Full GC之前进行一次Minor GC这样可以加快老年代的回收速度。


  1. JUC
  2. Synchronized与Lock的区别
  3. Synchronized能实现的功能Lock都可以实现,而且Lock比Synchronized更好用,更灵活。
  4. Synchronized可以自动上锁和解锁;Lock需要手动上锁和解锁
  5. Runnable和Callable的区别
  6. Runnable接口中的方法没有返回值;Callable接口中的方法有返回值
  7. Runnable接口中的方法没有抛出异常;Callable接口中的方法抛出了异常
  8. Runnable接口中的落地方法是call方法;Callable接口中的落地方法是run方法
  9. 什么是分布式锁

当在分布式模型下,数据只有一份(或有限制),此时需要利用锁的技术控制某一时刻修改数据的进程数。分布式锁可以将标记存在内存,只是该内存不是某个进程分配的内存而是公共内存,如 Redis,通过set (key,value,nx,px,timeout)方法添加分布式锁。

  1. 什么是分布式事务

分布式事务指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。简单的说,就是一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务器上,且属于不同的应用,分布式事务需要保证这些小操作要么全部成功,要么全部失败。

相关实践学习
基于MaxCompute的热门话题分析
本实验围绕社交用户发布的文章做了详尽的分析,通过分析能得到用户群体年龄分布,性别分布,地理位置分布,以及热门话题的热度。
SaaS 模式云数据仓库必修课
本课程由阿里云开发者社区和阿里云大数据团队共同出品,是SaaS模式云原生数据仓库领导者MaxCompute核心课程。本课程由阿里云资深产品和技术专家们从概念到方法,从场景到实践,体系化的将阿里巴巴飞天大数据平台10多年的经过验证的方法与实践深入浅出的讲给开发者们。帮助大数据开发者快速了解并掌握SaaS模式的云原生的数据仓库,助力开发者学习了解先进的技术栈,并能在实际业务中敏捷的进行大数据分析,赋能企业业务。 通过本课程可以了解SaaS模式云原生数据仓库领导者MaxCompute核心功能及典型适用场景,可应用MaxCompute实现数仓搭建,快速进行大数据分析。适合大数据工程师、大数据分析师 大量数据需要处理、存储和管理,需要搭建数据仓库?学它! 没有足够人员和经验来运维大数据平台,不想自建IDC买机器,需要免运维的大数据平台?会SQL就等于会大数据?学它! 想知道大数据用得对不对,想用更少的钱得到持续演进的数仓能力?获得极致弹性的计算资源和更好的性能,以及持续保护数据安全的生产环境?学它! 想要获得灵活的分析能力,快速洞察数据规律特征?想要兼得数据湖的灵活性与数据仓库的成长性?学它! 出品人:阿里云大数据产品及研发团队专家 产品 MaxCompute 官网 https://www.aliyun.com/product/odps&nbsp;
相关文章
|
5月前
|
SQL 大数据
常见大数据面试SQL-每年总成绩都有所提升的学生
一张学生成绩表(student_scores),有year-学年,subject-课程,student-学生,score-分数这四个字段,请完成如下问题: 问题1:每年每门学科排名第一的学生 问题2:每年总成绩都有所提升的学生
|
6月前
|
分布式计算 监控 大数据
《吊打面试官》- 大数据工程师50道中大厂面试真题保姆级详解
《吊打面试官》- 大数据工程师50道中大厂面试真题保姆级详解
111 1
《吊打面试官》- 大数据工程师50道中大厂面试真题保姆级详解
|
6月前
|
SQL 分布式计算 算法
程序员必备的面试技巧——大数据工程师面试必备技能
程序员必备的面试技巧——大数据工程师面试必备技能
116 0
|
6月前
|
缓存 运维 NoSQL
面试分享:Redis在大数据环境下的缓存策略与实践
【4月更文挑战第10天】探索Redis在大数据缓存的关键作用,本文分享面试经验及必备知识点。聚焦Redis数据结构(String、List、Set、Hash、Sorted Set)及其适用场景,缓存策略(LRU、LFU、TTL)与过期机制,集群和数据分片,以及性能优化和运维技巧。通过代码示例深入理解,助你面试成功,构建高效缓存服务。
175 4
|
6月前
|
移动开发 前端开发 JavaScript
【前端面试】前端面试题300道~~熬夜吐血整理,2024年最新大厂面试经验分享稿
【前端面试】前端面试题300道~~熬夜吐血整理,2024年最新大厂面试经验分享稿
|
3月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
12天前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
14天前
|
存储 缓存 Java
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
39 4
|
1月前
|
算法 Java 数据中心
探讨面试常见问题雪花算法、时钟回拨问题,java中优雅的实现方式
【10月更文挑战第2天】在大数据量系统中,分布式ID生成是一个关键问题。为了保证在分布式环境下生成的ID唯一、有序且高效,业界提出了多种解决方案,其中雪花算法(Snowflake Algorithm)是一种广泛应用的分布式ID生成算法。本文将详细介绍雪花算法的原理、实现及其处理时钟回拨问题的方法,并提供Java代码示例。
72 2
|
1月前
|
JSON 安全 前端开发
第二次面试总结 - 宏汉科技 - Java后端开发
本文是作者对宏汉科技Java后端开发岗位的第二次面试总结,面试结果不理想,主要原因是Java基础知识掌握不牢固,文章详细列出了面试中被问到的技术问题及答案,包括字符串相关函数、抽象类与接口的区别、Java创建线程池的方式、回调函数、函数式接口、反射以及Java中的集合等。
29 0

热门文章

最新文章

下一篇
无影云桌面