2020最新面试

1、sql 优化

(1)在表中创建索引,优先考虑where、group by使用到的关键字

(2)尽量不要使用*查询,返回无用的字段

(3)尽量不用使用in 或者not in,这样会导致索引失效

(4)尽量不用使用or,这样会导致数据库引擎放弃索引进行全表扫描

(5)利用左、右连接代替子查询

(6)sql中的where条件尽量进行null判断

(7)尽量不用使用 where 1=1

(8)表中的索引最后不要超过6个
2、线程的状态
    线程从创建、运行到结束总是处于下面五个状态之一:新建状态、就绪状态、运行状态、阻塞状态及死亡状态。
    1.新建状态:通过new的方式创建一个线程
    2.就绪状态:每个线程创建成功之后不会立刻运行,需要通过start方法启动线程,还需要同其他线程竞争CPU的时间,获取到cpu之后就会进入线程运行状态,
        但是不会直接运行
    3.运行状态(running):当线程获得CPU时间后,它才进入运行状态,真正开始执行run()方法。
    4.阻塞状态(blocked)
    5.死亡
3、Linux 查看cpu
    top -bn 1 -i -c
    sar -u 1 5  #每秒采集一次CPU情况,共采集五次
4、如何让线程安装特定的顺序输出
    方法1:使用join方法,让主线程放弃CPU的执行权,让给子线程
        join方法的原理就是调用相应线程的wait方法进行等待操作的,例如A线程中调用了B线程的join方法,
        则相当于在A线程中调用了B线程的wait方法,当B线程执行完(或者到达等待时间),
        B线程会自动调用自身的notifyAll( 调用了JVM底层lock.notify_all(thread)方法来唤醒 )方法唤醒A线程,从而达到同步的目的
    方法2:利用单线程化线程池(newSingleThreadExecutor)串行执行所有任务
        利用并发包里的Excutors的newSingleThreadExecuto产生一个单线程的线程池,而这个线程池的底层原理就是一个先进先出(FIFO)的队列。
        代码中executor.submit依次添加了123线程,按照FIFO的特性,执行顺序也就是123的执行结果,从而保证了执行顺序
        
        static ExecutorService executorService = Executors.newSingleThreadExecutor();
        public static void main(String[] args) throws Exception {
            executorService.submit(thread1);
            executorService.submit(thread2);
            executorService.submit(thread3);
            executorService.shutdown();
        }

5、高并发的处理情况
    流量优化:防盗链处理
  前端优化:减少HTTP请求,合并css或js,添加异步请求,启用浏览器缓存和文件压缩,CDN加速,建立独立图片服务器,
  服务端优化:页面静态化,并发处理,队列处理
  数据库优化:数据库缓存,分库分表,分区操作,读写分离,负载均衡
  web服务器优化:负载均衡,nginx反向代理,7,4层LVS软件
6、java中的那些锁:悲观锁、乐观锁
7、spring aop应用的场景
    Authentication 权限
    Caching 缓存
    Context passing 内容传递
    Error handling 错误处理
    Lazy loading 懒加载
    Debugging 调试
    logging, tracing, profiling and monitoring 记录跟踪 优化 校准
    Performance optimization 性能优化
    Persistence 持久化
    Resource pooling 资源池
    Synchronization 同步
    Transactions 事务
8、spring aop 应用方式
    1.经典的基于代理的AOP
    2.@AspectJ注解驱动的切面
    3.纯POJO切面
    4.注入式AspectJ切面
9、bean的生命周期

  • 实例化bean对象(通过构造方法或者工厂方法)
  • 设置对象属性(setter等)(依赖注入)
  • 如果Bean实现了BeanNameAware接口,工厂调用Bean的setBeanName()方法传递Bean的ID。(和下面的一条均属于检查Aware接口)
  • 如果Bean实现了BeanFactoryAware接口,工厂调用setBeanFactory()方法传入工厂自身
  • 将Bean实例传递给Bean的前置处理器的postProcessBeforeInitialization(Object bean, String beanname)方法
  • 调用Bean的初始化方法
  • 将Bean实例传递给Bean的后置处理器的postProcessAfterInitialization(Object bean, String beanname)方法
  • 使用Bean
  • 容器关闭之前,调用Bean的销毁方法

10、redis 

    10.1、redis的数据类型:string hash  list set zset

               String字符串:格式: set key value

                  string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。

                  string类型是Redis最基本的数据类型,一个键最大能存储512MB。

       Hash(哈希):格式: hmset name  key1 value1 key2 value2

                        Redis hash 是一个键值(key=>value)对集合。

                        Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。

              List(列表)

                       Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)

                       格式: lpush  name  value

                         在 key 对应 list 的头部添加字符串元素

                      格式: rpush  name  value

                        在 key 对应 list 的尾部添加字符串元素

                     格式: lrem name  index

                         key 对应 list 中删除 count 个和 value 相同的元素

                   格式: llen name  

                          返回 key 对应 list 的长度

 Set(集合):格式: sadd  name  value

                   Redis的Set是string类型的无序集合。

                   集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。

zset(sorted set:有序集合):格式: zadd  name score value

                   Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。

                   不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。

                    zset的成员是唯一的,但分数(score)却可以重复。

    10.2、redis持久化原理:持久化就是把内存的数据写到磁盘中去,防止服务宕机了内存数据丢失。

   10.3、redis持久化方式:Redis 提供了两种持久化方式:RDB(默认) 和AOF 

            rdb是Redis DataBase缩写

                     功能核心函数rdbSave(生成RDB文件)和rdbLoad(从文件加载内存)两个函数

             AOF:Aof是Append-only file缩写

                     每当执行服务器(定时)任务或者函数时flushAppendOnlyFile 函数都会被调用, 这个函数执行以下两个工作

                    aof写入保存:

                         WRITE:根据条件,将 aof_buf 中的缓存写入到 AOF 文件

                         SAVE:根据条件,调用 fsync 或 fdatasync 函数,将 AOF 文件保存到磁盘中。

         存储结构:

                     内容是redis通讯协议(RESP )格式的命令文本存储。

         比较

               1、aof文件比rdb更新频率高,优先使用aof还原数据。

               2、aof比rdb更安全也更大

               3、rdb性能比aof好

               4、如果两个都配了优先加载AOF

         RESP 是redis客户端和服务端之前使用的一种通讯协议;

         RESP 的特点:实现简单、快速解析、可读性好

            For Simple Strings the first byte of the reply is "+" 回复

            For Errors the first byte of the reply is "-" 错误

            For Integers the first byte of the reply is ":" 整数

            For Bulk Strings the first byte of the reply is "$" 字符串

            For Arrays the first byte of the reply is "*" 数组

   10.4、redis的架构模式:单机模式、主从模式、哨兵模式、集群(proxy 型)、集群(直连型)

   10.5、redis分布式锁:

先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放。

如果在setnx之后执行expire之前进程意外crash或者要重启维护了,那会怎么样?

set指令有非常复杂的参数,这个应该是可以同时把setnx和expire合成一条指令来用的!

   10.6、redis异步队列
   10.7、缓存雪崩:由于原有缓存失效,新缓存未到期间
        (例如:我们设置缓存时采用了相同的过期时间,在同一时刻出现大面积的缓存过期),所有原本应该访问缓存的请求都去查询数据库了,
        而对数据库CPU和内存造成巨大压力,严重的会造成数据库宕机。从而形成一系列连锁反应,造成整个系统崩溃。
    解决方法:
        大多数系统设计者考虑用加锁( 最多的解决方案)或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,
        从而避免失效时大量的并发请求落到底层存储系统上。还有一个简单方案就时讲缓存失效时间分散开。
    缓存穿透:用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询的时候,在缓存中找不到,每次都要去数据库再查询一遍,
        然后返回空(相当于进行了两次无用的查询)。这样请求就绕过缓存直接查数据库,这也是经常提的缓存命中率问题。
    解决方法:    
        最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。
        另外也有一个更为简单粗暴的方法,如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们仍然把这个空结果进行缓存,
        但它的过期时间会很短,最长不超过五分钟。通过这个直接设置的默认值存放到缓存,这样第二次到缓冲中获取就有值了,而不会继续访问数据库,
        这种办法最简单粗暴。

11、springboot的注解:SpringBootapplication(springbootConfiguration、EnableAutoConfiguration、ComponentScan)

12、SpringBoot原理:

       注解 @EnableAutoConfiguration, @Configuration, @ConditionalOnClass 就是自动配置的核心,

@EnableAutoConfiguration 给容器导入META-INF/spring.factories 里定义的自动配置类。

筛选有效的自动配置类。

每一个自动配置类结合对应的 xxxProperties.java 读取配置文件进行自动配置功能

13、jdk8的新特性

(1)接口的默认的方法:允许给接口添加非抽象的方法,用default修饰

(2)lambda表达式

(3)函数式接口

(4)新的日期API

(5)引入Optional

(6)使用Base64

(7)新增方法引用格式

(8)新增Stream类

(9)注解相关的改变

(10)支持并行(parallel)数组

(11)对并发类(Concurrency)的扩展。

14、如何实现hashmap的线程安全

(1)HashTable

           Map<String, String> hashtable = new Hashtable<>();

          HashTable使用synchronized来保证线程安全的,所有线程竞争同一把锁,效率低

(2)ConcurrentHashMap 

         Map<String, String> concurrentHashMap = new ConcurrentHashMap<>();

         使用锁分段技术:它包含一个segment数组,将数据分段存储,给每一段数据配一把锁,效率高

         Java8中使用CAS算法

(3)Synchronized Map

               Map<String, String> synchronizedHashMap = Collections.synchronizedMap(new HashMap<String, String>());

               调用synchronizedMap()方法后会返回一个SynchronizedMap类的对象,而在SynchronizedMap类中使用了synchronized                 同步关键字来保证对Map的操作是安全的。

15、如何判断sql中的索引是否起作用

       使用explain进行检测

没使用索引:

使用组件:

      注意:type字段就可以表示索引是否已经使用

16、springSecurity和shiro优缺点

17、springcloud的核心组件:zureka、Feign、Ribbon、Hystrin、zurl

18、微服务springcloud和dubbo的区别

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值